簡體   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