繁体   English   中英

如何使用 Java 列出文件中所有导入类的所有方法?

[英]How can I list all methods of all imported classes in a file using Java?

我的目标是查看外部文件的一些代码行,然后计算调用 class 的函数数。

例如,如果我有以下代码:

import java.io.BufferedReader;
import whatever.MyClass;
import java.util.ArrayList;
...
...
public void example(){
    InputStreamReader isr = new InputStreamReader (whatever);
    MyClass object = new MyClass();
    someArrayList.add(whatever2)
    someArrayList.add(whatever3)
}

本例中BufferedReaderMyClass函数被调用了一次, ArrayList函数被调用了两次。

我的解决方案是获取所用类中所有方法的列表,并尝试与我的代码中的一些字符串匹配。 对于在我的项目中创建的类,我可以执行以下操作:

jar -tf jarPath

这会返回 JAR 中的类列表。并执行以下操作:

javap -cp jarPath className

我可以获得 JAR 内所有方法的列表,并带有特定的 class 名称。 但是,我该怎么做才能获得外部方法名称,例如“外部” class java.util.ArrayListadd(...) 我无法访问 java.util.ArrayList 的.jar文件, java.util.ArrayList吗? 有人有其他建议来达到目标吗?

编译器不会将导入放入 object 文件中。 它把它们扔掉了。 Import 只是编译器的简写。(Imports 是一个编译时特性)。

第一步:

使用 Qdox https://github.com/paul-hammant/qdox获取 class 中的所有导入:

String fileFullPath = "Your\\java\\ file \\full\\path";
JavaDocBuilder builder = new JavaDocBuilder();
builder.addSource(new FileReader( fileFullPath  ));

JavaSource src = builder.getSources()[0];
String[] imports = src.getImports();

for ( String imp : imports )
{
    System.out.println(imp);
}

第二步:从该代码中获得灵感,循环导入(字符串数组)并应用相同的代码,您将获得这些方法。

 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;

  public class Tes {
  public static void main(String[] args) {
    Class c;
    try {
        c = Class.forName("java.util.ArrayList");
        Arrays.stream(getAccessibleMethods(c)).
                              forEach(System.out::println);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

public static Method[] getAccessibleMethods(Class clazz) {
    List<Method> result = new ArrayList<Method>();
    while (clazz != null) {
        for (Method method : clazz.getDeclaredMethods()) {
            result.add(method);
        }
        clazz = clazz.getSuperclass();
    }
    return result.toArray(new Method[result.size()]);
}
}

Output:

  public void java.util.ArrayList.add(int,java.lang.Object)
  public boolean java.util.ArrayList.add(java.lang.Object)
  public boolean java.util.ArrayList.remove(java.lang.Object)
  public java.lang.Object java.util.ArrayList.remove(int)
  public java.lang.Object java.util.ArrayList.get(int)
  public java.lang.Object java.util.ArrayList.clone()
  public int java.util.ArrayList.indexOf(java.lang.Object)
  public void java.util.ArrayList.clear()
  .
  .
  .

所有代码 - 一个 class:

  import java.io.FileNotFoundException;
  import java.io.FileReader;
  import java.lang.reflect.Method;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;

  import com.thoughtworks.qdox.JavaDocBuilder;
  import com.thoughtworks.qdox.model.JavaSource;

  public class Tester {
  public static void main(String[] args) {
  // put your .java file path
  // CyclicB is a class within another project in my pc
    String fileFullPath =
      "C:\\Users\\OUSSEMA\\Desktop\\dev\\OCP_Preparation\\src\\w\\CyclicB.java";
JavaDocBuilder builder = new JavaDocBuilder();
try {
    builder.addSource(new FileReader( fileFullPath  ));
} catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

JavaSource src = builder.getSources()[0];
String[] imports = src.getImports();

for ( String imp : imports )
{
    Class c;
    try {
        c = Class.forName(imp);
        Arrays.stream(getAccessibleMethods(c)).
                              forEach(System.out::println);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
 }
 }
  public static Method[] getAccessibleMethods(Class clazz) {
  List<Method> result = new ArrayList<Method>();
  while (clazz != null) {
    for (Method method : clazz.getDeclaredMethods()) {
        result.add(method);
    }
    clazz = clazz.getSuperclass();
  }
return result.toArray(new Method[result.size()]);
}
}

Output 在文件 CyclicB.java 中导入的类中的所有方法:

  private void java.lang.Throwable.printStackTrace(java.lang.Throwable$PrintStreamOrWriter)
  public void java.lang.Throwable.printStackTrace(java.io.PrintStream)
  public void java.lang.Throwable.printStackTrace()
  public void java.lang.Throwable.printStackTrace(java.io.PrintWriter)
  public synchronized java.lang.Throwable java.lang.Throwable.fillInStackTrace()
  .
  .
  .

您可以查看具有 Java 编译器的OpenJDK项目。 学习构建修改后的版本。 调查此编译器的语法分析层并找到处理方法调用的位置。 将日志记录放入这些位置,现在您只需使用修改后的编译器构建 java 文件即可获取有关调用的信息。

构建很复杂,但您可能只需要仔细编辑几个文件。 这并不是很容易实现的目标,但我认为应该可以发现这些文件并对其进行更改,并且仍然可能是比实现自己的 Java 语法解析器(也可以使用JavaCC )更简单/更干净的方法。

如果您还需要跟踪来自外部库的调用,也可以使用修改后的编译器构建它们,您将获得所需的记录。

GNU Classpath是另一个开源项目,您可以在其中做类似的事情,而且构建起来可能更容易。 但是,与 OpenJDK 不同的是,GNU Classpath java 系统库并不完整。

这种方法可能不会发现一些在反射期间调用的方法。 但是它会发现调用了反射框架方法。 如果是安全相关的项目,最简单的就是同意不允许反射。 在不是框架的普通 Java 应用程序中使用反射是不常见的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM