基于JDT的JAR源代码搜索
当前位置:以往代写 > JAVA 教程 >基于JDT的JAR源代码搜索
2019-06-14

基于JDT的JAR源代码搜索

基于JDT的JAR源代码搜索

副标题#e#

引言

Eclipse 为措施员提供了强大的文本搜索成果,措施员可以利便 的在事情空间中搜索到需要的 JAVA 代码可能文本。可是有时候,措施员但愿在 .class 文件源码可能普通文本文件中搜索某个字符串,而这些文件包括于 Jar 文件中,此时 Eclipse 就无法满意要求。好比,用户试图寻找 UI 上显示的某 字符串的界说位置,这就需要在 Jar 文件内的普通文本文件 , 以及 .class 文 件源码中搜索。这些 Jar 文件包括于项目类路径中,这个成果在 RCP 开拓中是 常常需要的,而 Eclipse 今朝还未提供这个特性。本文通过利用 JDT(Java Development Toolkit)中与 Jar 相关的接口,办理了这个问题,并给出示例及 措施。

Eclipse 中搜索的道理

Eclipse 回收 Lucene 技能开拓其搜索内核, 该内核通过对要害字举办索引,快速定位方针文件。譬喻,Eclipse 会对 JAVA 源文件中的类名、字段名、要领名等举办索引,当措施员利用 Open Type 成果 (快捷键:CTRL+SHIFT+T)举办类搜索时,便可以通过类名这个索引字段举办快 速搜索 ; 在利用 JAVA 搜索(Java Search)成果时,Eclipse 也会让用户指定 详细的索引字段(Search For),如可以选择要领名、类名、字段名、包名、构 造器名等,Eclipse 会按照选择的索引字段与用户的输入,快速搜索到源代码。

Eclipse 在提供 Jar 源代码搜索方面的限制

Eclipse 提供了文 件搜索(File Search)的成果,用来搜索指定范畴 ( 项目、事情空间等 ) 内 的文本文件。这个成果并没有按照某些非凡要害字举办索引。因为对付任意字符 串的搜索,是无法找到特定要害字举办索引的。因此为了提高搜索效率, Eclipse 对付任意字符串的搜索范畴仅限于用户编写的文本文件,而没有对项目 所依赖的 Jar 文件中的类的源代码举办搜索。因为 Jar 源代码的数量往往数量 复杂,搜索它们将是一个相当费时的操纵。可是在许多环境下,措施员有须要进 行类源代码的搜索,通过查察需要的源代码办理一些问题,Eclipse 今朝提供的 搜索成果就无法满意这样的需求。

JDT 中 Jar 文件相关的类布局图阐明

下面两图展示了 JDT 中与 Jar 文件处理惩罚相关的类,从图中,可以清晰 的相识它们的条理、包括和对应干系。

图 1. JDT 中与 Jar 文件相关的 UML 类布局图

基于JDT的JAR源代码搜索

图 2. JDT 中与 Jar 文件相关的类布局对应图


#p#副标题#e#

基于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 源代码搜索办理方案

本文将用一个例子措施,慢慢先容如何 实现 Jar 源代码的搜索,进一步相识 JDT 提供的 API。办理方案的主要逻辑为 :遍历事情空间下的所有 JAVA 项目,而且逐一得到项目所依赖的 Jar 文件列 表。然后遍历该列表得到每个 Jar 文件中的 class 文件源码和非 class 文件 的文本内容,利用正则表达式举办匹配查找。最后输出功效的类名、文件路径、 匹配的起始位置和匹配的字符串长度等信息。

团结这个逻辑以及 JDT 中 Jar 文件相关的类布局,上述办理方案中的主要技能问题包罗:

ResourcesPlugin.getWorkspace().getRoot().getProjects() 可以得到 事情空间下的所有项目,范例为 IProject。那么如何将 IProject 工具转换为 JAVA 项目对应的 IJavaProject 工具?(文中步调 1 办理该问题)

获 得 IJavaProject 工具后,如何得到它所依赖的 Jar 文件列表,也就是 JarPackageFragmentRoot 工具列表?(文中步调 2 办理该问题)

得到 JarPackageFragmentRoot 工具后,如何得到它下面的包(JarPackageFragment ),又如何得到包下的 class 文件(IClassFile)和非 class 文本文件 (JarFileEntry)?(文中步调 3、5 办理该问题)

如何得到 IClassFile 的源代码,又如何得到 JarFileEntry 的文本内容?(文中步调 4 、6 办理该问题)

下面将对各个步调逐一地举办阐明,而且一一办理上 面提到的问题。

#p#副标题#e#

步调 1. 转换 IProject 为 IJavaProject

#p#分页标题#e#

Eclipse 事情空间下,大概存在很多范例的项目,有 JAVA 项目也有非 JAVA 项目,为了得到项目依赖的 Jar 文件,该项目必需是 Java 范例的项目。以下代码通过挪用 JDT 提供的接口,得到 JAVA 项目列表。

清单 1. 得到事情空间下的所有 JAVA 项目

/* 得到事情 空间下的所有项目 */
 IProject[] projects =  ResourcesPlugin.getWorkspace().getRoot()
             .getProjects();
 if (projects != null)
 {
     for (IProject p : projects)
    {
       /*  实验转换普通项目为 JAVA 项目 */
       IJavaProject  create = JavaCore.create(p);
       /* 判定项目是否是  JAVA 项目 */
       if (create != null &&  create.exists())
       {
          /* 操 作 JAVA 项目 */
          …
        }
    }
 }

步调 2. 得到依赖的 JarPackageFragmentRoot 列表

得到 IJavaProject 工具后,需要获得它 所依赖的 Jar 文件列表。在 JDT 中,Jar 文件对应的类为 JarPackageFragmentRoot,下面一段措施用于得到 Jar 文件列表。

清单 2. 得到 JAVA 项目依赖的 Jar 文件列表的代码

IJavaProject  project= …
 IJavaElement[] children =  project.getChildren();
 if (children != null)
 {
  /* 遍历 project 下的 Java 元素 */
  for  (IJavaElement ele : children)
  {
    /* 判定是否 是 JarPackageFragmentRoot 工具 */
    if (ele instanceof  JarPackageFragmentRoot)
    {
       /* 操纵此  jar 文件 */
          …
    }
 }
 }

大大都时候措施员想要搜索的范畴并不包括 JRE 库的源代码,因此为了提高搜索效率,需要屏蔽 JRE 库源代码的搜索,下面一 段措施展示如何实现这个需求。

清单 3. 屏蔽 JRE 库的源码搜索

JarPackageFragmentRoot jarFile = … ;
  IJavaProject project = … ;
 /**
 * 判定此 Jar  是否在 JRE 库中。假如是,将其屏蔽 , 以提高效率
 */
  IClasspathEntry rawClasspathEntry = jarFile.getRawClasspathEntry ();
 IClasspathContainer classpathContainer =  JavaCore.getClasspathContainer(
          rawClasspathEntry.getPath(), project);
 /* 判定此 jar 是否属 于项目默认的 JRE 库。假如是,不查抄该 jar*/
 if  (classpathContainer.getKind() ==  IClasspathContainer.K_DEFAULT_SYSTEM)
 {
   /* 跳过此  jar 的搜索 */
 }

#p#副标题#e#

步调 3. 得到 JarPackageFragmentRoot 中的 IClassFile 列表

假如想得到 .class 文 件的源码,就需要得到 .class 文件对应的 IClassFile 工具,下面的措施展示 了如何从 JarPackageFragmentRoot 工具开始遍历,得到其包括的 PackageFragment 工具,又从 PackageFragment 工具中得到 IClassFile 工具 列表。

清单 4. 获取所有类文件的代码

JarPackageFragmentRoot root = …
  IJavaElement[] children = root.getChildren();
 if (children  != null)
 {
   /* 遍历 JarPackageFragmentRoot 下的 所有包元素 */
   for (IJavaElement ele : children)
   {
      if (ele instanceof PackageFragment)
      {
        IJavaElement[] classes =  ((PackageFragment) ele).getChildren();
        /* 遍历  PackageFragment 下的所有类元素 */
        for  (IJavaElement cls : children)
        {
           if (ele instanceof IClassFile)
           {
            /* 得到 IClassFile 工具举办操纵  */
          }
        }
       }
   }
 }

需要留意的是,JDT 中 Jar 文件 中的包(package)对应的类为 JarPackageFragment,可是该类为 default 类 型,无法引用,可以先将它转换为它的父类 PackageFragment,然后举办处理惩罚。

步调 4. 得到 IClassFile 源代码并较量

#p#分页标题#e#

获得 IClassFile 工具 后,需要得到其源码 .IClassFile 提供了很是利便的接口: getSource。应用 该要领可以得到源码字符串。假如该要领的输出值为 null,说明这个类还未绑 定源代码。这种环境下可以通过双击 .class 文件,点击 Change Attached Source 按钮举办源代码的绑定。下面的措施展示了如何按照用户输入的正则表 达式举办较量搜索。

清单 5. 获取类文件源码并较量

IClassFile cf = … ;
 Pattern  searchPattern = Pattern.compile("用户输入的正则表达式");
 /*  得到 IClassFile 源码 */
 String source = cf.getSource ();
 if (source != null)
 {
  Matcher matcher  = searchPattern.matcher(source);
  while (matcher.find())
  {
    /* 得到偏移量 */
    int offset =  matcher.start();
    String group = matcher.group();
    /* 得到长度 */
    int length = group.length ();
  }
 }

#p#副标题#e#

步调 5. 得到 JarPackageFragmentRoot 中的非 JAVA 资源

Jar 文件中 JAVA 资源主要 是 .java 文件和 .class 文件。Jar 文件中非 JAVA 的资源,对应的类为 IJarEntryResource,好比 Jar 中的 .properties 文件、META-INF 文件夹、 META-INF 文件夹下的 MANIFEST.MF 等,都属于非 JAVA 资源,这些非 JAVA 资 源可以存放于 JarPackageFragmentRoot 下,也可以存放于 JarPackageFragment 下。下面的措施展示如何遍历得到 JarPackageFragmentRoot 下的所有非 JAVA 资源。

清单 6. 得到非类文 件的资源

/* 注:ele 也可以是 PackageFragment, 它们都拥 有 getNonJavaResources 要领 */
 JarPackageFragmentRoot ele  = … ;
 Object[] nonjavares =  ele.getNonJavaResources();
 if (nonjavares != null)
  {
   for (Object o : nonjavares)
   {
        /* JarEntryDirectory 相当于 META-INF 文件夹 */
        if (o instanceof JarEntryDirectory)
        {
         JarEntryDirectory ff =  (JarEntryDirectory)o;
         IJarEntryResource[]  children = ff.getChildren();
         for  (IJarEntryResource e : children)
         {
            if (e instanceof JarEntryDirectory)
            {
               /* 这里需要递归处 理 */
            }
             else if (e instanceof JarEntryFile)
             {
                /* 处理惩罚该文本文件 */
             }
          }
 }
 /*  JarEntryFile 相当于 META-INF 文件夹下的 MANIFEST.MF 可能  .properties 文件等 */
       else if (o instanceof  JarEntryFile)
       {
          JarEntryFile ff = (JarEntryFile) o;
 /* 处理惩罚该文本文件  */
       }
    }
 }

步调 6. 得到非 JAVA 资源的源代码并较量

在本文的代码示例中只展示从 JarEntryFile 得到源代码的要领,假如需要利用其他范例的非 JAVA 资源的获 取要领,请查察附件中的源码。

清单 7. 得到非类文件的文本内容而且 较量

/**
 * 该要领用于得到 JarEntryFile 源代码并 且较量得到功效 
 */
 private void cooperate (JarEntryFile ff, Pattern searchPattern)
  {
     ByteArrayInputStream contents;
    try 
    {
      contents = (ByteArrayInputStream) ff.getContents ();
      byte[] bs = new byte[contents.available ()];
      contents.read(bs);
      String con  = new String(bs);
      Matcher matcher =  searchPattern.matcher(con);
      while (matcher.find())
      {
 /* 得到功效的偏移和长度 */
         int start = matcher.start();
        int  length = matcher.group().length();
      }
     }
    catch (Exception e)
    {
    }
 }

#p#副标题#e#

步调 7. 输出功效

为了简朴,措施会将功效打 印到节制台上,包罗功效中的偏移量、长度、以及查找到源代码路径。

详细应用情况 —RCP 中查找源码

#p#分页标题#e#

在 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 字符串

基于JDT的JAR源代码搜索

例子将试图搜索包括“This section provides general information about” 字符串的 properties 文件,假如未搜索到,可以 适当缩短字符串长度。

图 4. 输入 UI 字符串的措施界面

基于JDT的JAR源代码搜索

点击 OK 就可以举办搜索。

图 5. 属性文件搜索功效(用时 3.23 秒)

基于JDT的JAR源代码搜索

功效显示了包括该字符串的 properties 文件路径,以及字符串在该文件中 呈现的起始位置和长度信息。该文件包括于 Jar 文件中。按照搜索到的路径, 打开文件查察源码。

图 6. 属性文件源代码

基于JDT的JAR源代码搜索

图中灰色配景部门就是需要查找的字符串。

#p#副标题#e#

步调 2. 按照 properties 文件名得到引用该 properties 文件的类

在得到 properties 文件名之后,按照搜索到的 properties 文件名(在本文的例子中 是 gui.properties),搜索引用该属性文件的 java 类 , 输入查询的字符串为 :com.ibm.btools.blm.ui.attributesview.resource.gui。

图 7. 输入 利用属性文件的字符串措施界面

基于JDT的JAR源代码搜索

图 8. 类搜索功效(用时 2.43 秒)

基于JDT的JAR源代码搜索

通过 Open Type 成果,输入 BLMAttributesviewMessageKeys,就可 以找到此 .class 文件,打开 .class 文件就可以查察它的源代码。

其 他接口简朴先容

这里简朴的先容了 JDT 中与 Jar 相关的类的其他有用 接口,如表 1 所示。

表 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 判 断是否只读

竣事语

在举办二次开拓时,通 过查察源代码可以很好的辅佐措施员相识原有系统,同时对付查找和阐明代码漏 洞也有很大的辅佐。该文章简朴的先容了如何利用 JDT 提供的接口举办源代码 的搜索,文章内容仅供参考,有乐趣的伴侣可以参考该文章的实现,举办进一步 的优化,提高搜索效率,可能做成实用的插件宣布,相信会受到许多 Java 措施 员的喜爱。

原文地点:http://www.ibm.com/developerworks/cn/opensource/os-ecl- jdtsearch/

    关键字:

在线提交作业