2010-04-22 38 views

回答

11

大廈在aioobe's answer,您還可以使用ASM的樹API(而不是其訪問者API)來解析包含您的JAR文件中的類文件的內容。同樣,您可以使用JarFile類讀取JAR文件中包含的文件。下面是一個如何實現的例子:

printMethodStubs方法接受JarFile並繼續打印出所有類文件中包含的所有方法的描述。

public void printMethodStubs(JarFile jarFile) throws Exception { 
    Enumeration<JarEntry> entries = jarFile.entries(); 
    while (entries.hasMoreElements()) { 
     JarEntry entry = entries.nextElement(); 

     String entryName = entry.getName(); 
     if (entryName.endsWith(".class")) { 
      ClassNode classNode = new ClassNode(); 

      InputStream classFileInputStream = jarFile.getInputStream(entry); 
      try { 
       ClassReader classReader = new ClassReader(classFileInputStream); 
       classReader.accept(classNode, 0); 
      } finally { 
       classFileInputStream.close(); 
      } 

      System.out.println(describeClass(classNode)); 
     } 
    } 
} 

的​​方法接受ClassNode對象,並進行到描述它和它的相關聯的方法:

public String describeClass(ClassNode classNode) { 
    StringBuilder classDescription = new StringBuilder(); 

    Type classType = Type.getObjectType(classNode.name); 



    // The class signature (e.g. - "public class Foo") 
    if ((classNode.access & Opcodes.ACC_PUBLIC) != 0) { 
     classDescription.append("public "); 
    } 

    if ((classNode.access & Opcodes.ACC_PRIVATE) != 0) { 
     classDescription.append("private "); 
    } 

    if ((classNode.access & Opcodes.ACC_PROTECTED) != 0) { 
     classDescription.append("protected "); 
    } 

    if ((classNode.access & Opcodes.ACC_ABSTRACT) != 0) { 
     classDescription.append("abstract "); 
    } 

    if ((classNode.access & Opcodes.ACC_INTERFACE) != 0) { 
     classDescription.append("interface "); 
    } else { 
     classDescription.append("class "); 
    } 

    classDescription.append(classType.getClassName()).append("\n"); 
    classDescription.append("{\n"); 



    // The method signatures (e.g. - "public static void main(String[]) throws Exception") 
    @SuppressWarnings("unchecked") 
    List<MethodNode> methodNodes = classNode.methods; 

    for (MethodNode methodNode : methodNodes) { 
     String methodDescription = describeMethod(methodNode); 
     classDescription.append("\t").append(methodDescription).append("\n"); 
    } 



    classDescription.append("}\n"); 

    return classDescription.toString(); 
} 

describeMethod方法接受MethodNode和返回描述方法的簽名的String:

public String describeMethod(MethodNode methodNode) { 
    StringBuilder methodDescription = new StringBuilder(); 

    Type returnType = Type.getReturnType(methodNode.desc); 
    Type[] argumentTypes = Type.getArgumentTypes(methodNode.desc); 

    @SuppressWarnings("unchecked") 
    List<String> thrownInternalClassNames = methodNode.exceptions; 

    if ((methodNode.access & Opcodes.ACC_PUBLIC) != 0) { 
     methodDescription.append("public "); 
    } 

    if ((methodNode.access & Opcodes.ACC_PRIVATE) != 0) { 
     methodDescription.append("private "); 
    } 

    if ((methodNode.access & Opcodes.ACC_PROTECTED) != 0) { 
     methodDescription.append("protected "); 
    } 

    if ((methodNode.access & Opcodes.ACC_STATIC) != 0) { 
     methodDescription.append("static "); 
    } 

    if ((methodNode.access & Opcodes.ACC_ABSTRACT) != 0) { 
     methodDescription.append("abstract "); 
    } 

    if ((methodNode.access & Opcodes.ACC_SYNCHRONIZED) != 0) { 
     methodDescription.append("synchronized "); 
    } 

    methodDescription.append(returnType.getClassName()); 
    methodDescription.append(" "); 
    methodDescription.append(methodNode.name); 

    methodDescription.append("("); 
    for (int i = 0; i < argumentTypes.length; i++) { 
     Type argumentType = argumentTypes[i]; 
     if (i > 0) { 
      methodDescription.append(", "); 
     } 
     methodDescription.append(argumentType.getClassName()); 
    } 
    methodDescription.append(")"); 

    if (!thrownInternalClassNames.isEmpty()) { 
     methodDescription.append(" throws "); 
     int i = 0; 
     for (String thrownInternalClassName : thrownInternalClassNames) { 
      if (i > 0) { 
       methodDescription.append(", "); 
      } 
      methodDescription.append(Type.getObjectType(thrownInternalClassName).getClassName()); 
      i++; 
     } 
    } 

    return methodDescription.toString(); 
} 
+0

這是偉大的,而且確實是我搜索的。 謝謝你們! – djatomic 2010-04-22 13:40:46

+0

這裏是所有導入,使用此代碼:'import java.io.InputStream; import java.util.Enumeration; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.objectweb.asm.ClassReader; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; import xbn.lang.SimpleXbnObject; ' – aliteralmind 2014-01-01 22:14:53

+0

我沒有找到在網站上導入的好罐子。你能幫忙嗎?謝謝。是的,我知道舊帖子,但問題很有趣。 – MychaL 2014-04-14 18:38:37

1

我能想到的是使用ASM字節碼框架的最好方法。那麼至少你不必通過一個行解析器來進行反編譯輸出。事實上,獲取方法存根應該像是他們的一個Visitor接口的20行實現。

我已經使用它自己進行字節碼重寫,它非常簡單和直接(特別是如果你只是閱讀類文件)。

http://asm.ow2.org/

相關問題