转载自:http://www.oschina.net/bbs/thread/9893
简介: Eclipse 为程序员提供了强大的搜索功能,文件搜索 (File Search) 用来搜索工作空间下的所有文本文件,JAVA 搜索 (Java Search) 能够搜索工作空间下的所有 Java 文件。如果被搜索的内容包含于项目依赖的 Jar 文件中,如界面上的字符串,Eclipse 现有的搜索功能就无法满足需求。本文介绍了 Eclipse 提供的 API 以及 JDT 中 Jar 文件相关的 UML 结构图,讲述如何定位 Jar 文件中包含关键字的源代码和文本文件。
Eclipse 为程序员提供了强大的文本搜索功能,程序员可以方便的在工作空间中搜索到需要的 JAVA 代码或者文本。但是有时候,程序员希望在 .class 文件源码或者普通文本文件中搜索某个字符串,而这些文件包含于 Jar 文件中,此时 Eclipse 就无法满足要求。比如,用户试图寻找 UI 上显示的某字符串的定义位置,这就需要在 Jar 文件内的普通文本文件 , 以及 .class 文件源码中搜索。这些 Jar 文件包含于项目类路径中,这个功能在 RCP 开发中是经常需要的,而 Eclipse 目前还未提供这个特性。本文通过使用 JDT(Java Development Toolkit)中与 Jar 相关的接口,解决了这个问题,并给出示例及程序。
Eclipse 提供了文件搜索(File Search)的功能,用来搜索指定范围 ( 项目、工作空间等 ) 内的文本文件。这个功能并没有根据某些特殊关键字进行索引。因为对于任意字符串的搜索,是无法找到特定关键字进行索引的。因此为了提高搜索效 率,Eclipse 对于任意字符串的搜索范围仅限于用户编写的文本文件,而没有对项目所依赖的 Jar 文件中的类的源代码进行搜索。因为 Jar 源代码的数量往往数量庞大,搜索它们将是一个相当费时的操作。但是在很多情况下,程序员有必要进行类源代码的搜索,通过查看需要的源代码解决一些问 题,Eclipse 目前提供的搜索功能就无法满足这样的需求。
下面两图展示了 JDT 中与 Jar 文件处理相关的类,从图中,可以清晰的了解它们的层次、包含和对应关系。
图 1. JDT 中与 Jar 文件相关的 UML 类结构图
图 2. JDT 中与 Jar 文件相关的类结构对应图
上图描述了各个节点之间的层次、包含和对应 关系,了解这些信息,对文章下一部分的阅读是必要的。Java 项目,Jar 文件,Jar 文件中的包,Jar 文件中的普通文件夹,class 文件和非 class 文件分别对应于 IJavaProject,JarPackageFragmentRoot,JarPackageFragment,JarEntryDirectory,IClassFile 以及 JarEntryFile。IJavaProject 包含了多个 JarPackageFragmentRoot。而每个 JarPackageFragmentRoot 包含多个的 JarPackageFragment、JarEntryDirectory 和 JarEntryFile。类似的,JarPackageFragment 包含多个的 IClassFile 和 JarEntryFile;每个 JarEntryDirectory 包含多个的 JarEntryFile 和 JarEntryDirectory。
本文将用一个例子程序,逐步介绍如何实现 Jar 源代码的搜索,进一步了解 JDT 提供的 API。解决方案的主要逻辑为:遍历工作空间下的所有 JAVA 项目,并且逐一获得项目所依赖的 Jar 文件列表。然后遍历该列表获得每个 Jar 文件中的 class 文件源码和非 class 文件的文本内容,使用正则表达式进行匹配查找。最后输出结果的类名、文件路径、匹配的起始位置和匹配的字符串长度等信息。
结合这个逻辑以及 JDT 中 Jar 文件相关的类结构,上述解决方案中的主要技术问题包括:
下面将对各个步骤逐一地进行分析,并且一一解决上面提到的问题。
步骤 1. 转换 IProject 为 IJavaProject
Eclipse 工作空间下,可能存在许多类型的项目,有 JAVA 项目也有非 JAVA 项目,为了获得项目依赖的 Jar 文件,该项目必须是 Java 类型的项目。以下代码通过调用 JDT 提供的接口,获得 JAVA 项目列表。
|
步骤 2. 获得依赖的 JarPackageFragmentRoot 列表
获得 IJavaProject 对象后,需要得到它所依赖的 Jar 文件列表。在 JDT 中,Jar 文件对应的类为 JarPackageFragmentRoot,下面一段程序用于获得 Jar 文件列表。
清单 2. 获得 JAVA 项目依赖的 Jar 文件列表的代码
|
大多数时候程序员想要搜索的范围并不包含 JRE 库的源代码,因此为了提高搜索效率,需要屏蔽 JRE 库源代码的搜索,下面一段程序展示如何实现这个需求。
|
步骤 3. 获得 JarPackageFragmentRoot 中的 IClassFile 列表
如果想获得 .class 文件的源码,就需要获得 .class 文件对应的 IClassFile 对象,下面的程序展示了如何从 JarPackageFragmentRoot 对象开始遍历,获得其包含的 PackageFragment 对象,又从 PackageFragment 对象中获得 IClassFile 对象列表。
|
需要注意的是,JDT 中 Jar 文件中的包(package)对应的类为 JarPackageFragment,但是该类为 default 类型,无法引用,可以先将它转换为它的父类 PackageFragment,然后进行处理。
得到 IClassFile 对象后,需要获得其源码 .IClassFile 提供了非常方便的接口: getSource。应用该方法可以获得源码字符串。如果该方法的输出值为 null,说明这个类还未绑定源代码。这种情况下可以通过双击 .class 文件,点击 Change Attached Source 按钮进行源代码的绑定。下面的程序展示了如何根据用户输入的正则表达式进行比较搜索。
|
步骤 5. 获得 JarPackageFragmentRoot 中的非 JAVA 资源
Jar 文件中 JAVA 资源主要是 .java 文件和 .class 文件。Jar 文件中非 JAVA 的资源,对应的类为 IJarEntryResource,比如 Jar 中的 .properties 文件、META-INF 文件夹、META-INF 文件夹下的 MANIFEST.MF 等,都属于非 JAVA 资源,这些非 JAVA 资源可以存放于 JarPackageFragmentRoot 下,也可以存放于 JarPackageFragment 下。下面的程序展示如何遍历获得 JarPackageFragmentRoot 下的所有非 JAVA 资源。
|
在本文的代码示例中只展示从 JarEntryFile 获得源代码的方法,如果需要使用其他类型的非 JAVA 资源的获取方法,请查看附件中的源码。
|
为了简单,程序会将结果打印到控制台上,包括结果中的偏移量、长度、以及查找到源代码路径。
在 RCP 二次开发中,有时候非常需要查看已有 UI 的源码,供程序员参考使用。下面将使用前面开发的例子搜索包含 UI 上某字符串的源文件或源代码。一般来说,界面上的字符串都被存放于 .properties 文件,方便修改和多语言处理。由于 .properties 中可能出现占位符,界面显示的是处理占位符后的结果,所以需要选取合适的字符串进行搜索。搜索到 .properties 文件后,就根据该 .properties 文件所在的包名,和自身的文件名,搜索引用该 properties 文件的类。如对于 com.ibm.wise.A_zh_CN.propertis 文件,搜索 com.ibm.wise.A 即可,具体原因可以搜索 ResourceBundle 的相关资料进行查阅。下面展示这一搜索过程。
步骤 1. 根据 UI 上的字符串获得其 properties 文件所在
图 3. 要搜索的 UI 字符串
例子将试图搜索包含“This section provides general information about” 字符串的 properties 文件,如果未搜索到,可以适当缩短字符串长度。
图 4. 输入 UI 字符串的程序界面
点击 OK 就可以进行搜索。
图 5. 属性文件搜索结果(用时 3.23 秒)
结果显示了包含该字符串的 properties 文件路径,以及字符串在该文件中出现的起始位置和长度信息。该文件包含于 Jar 文件中。根据搜索到的路径,打开文件查看源码。
图 6. 属性文件源代码
图中灰色背景部分就是需要查找的字符串。
步骤 2. 根据 properties 文件名获得引用该 properties 文件的类
在获得 properties 文件名之后,根据搜索到的 properties 文件名(在本文的例子中是 gui.properties),搜索引用该属性文件的 java 类 , 输入查询的字符串为:com.ibm.btools.blm.ui.attributesview.resource.gui。
图 7. 输入使用属性文件的字符串程序界面
图 8. 类搜索结果(用时 2.43 秒)
通过 Open Type 功能,输入 BLMAttributesviewMessageKeys,就可以找到此 .class 文件,打开 .class 文件就可以查看它的源代码。
这里简单的介绍了 JDT 中与 Jar 相关的类的其他有用接口,如表 1 所示。
类 接口IClassFile | isClass():boolean 判断是否是 class 类型 isInterface():boolean 判断是否是 interface 类型 |
PackageFragment | createCompilationUnit():ICompilationUnit 新建 JAVA 文件 delete():void 删除此包 getClassFile():IClassFile 得到包下某个 class 文件 getClassFiles():IClassFile[] 得到包下所有 class 文件 getCompilationUnit():ICompilationUnit 得到包下某个 java 文件 getCompilationUnits():ICompilationUnit[] 得到包下所有 java 文件 rename():void 重命名 |
JarPackageFragmentRoot | getJar():ZipFile 得到 jar 文件对应的 ZipFile getKind():int 可以是 IPackageFragmentRoot.K_SOURCE 或者 IPackageFragmentRoot.K_BINARY,表示是源代码类型还是二进制类型 isArchive():boolean 判断是否是压缩文件 isReadOnly():boolean 判断是否只读 |