2010-04-22 11 views
5

Sto cercando un modo per ottenere un elenco di metodi stub di tutte le classi all'interno di un file jar. Non sono sicuro da dove cominciare ... Posso usare Reflection o Javassist o qualche altro strumento di cui non ho ancora sentito parlare !? Almeno può essere possibile decomprimere il barattolo, decompilare i file di classe ed eseguire la scansione con un parser di linea per i metodi, ma penso che sia il modo più sporco ;-)Java: modo semplice per ottenere lo stub del metodo dai file di classe all'interno di un file JAR? Riflessione?

Qualche idea?

Cordiali saluti

risposta

11

Basandosi sulle aioobe's answer, è anche possibile utilizzare l'albero API di ASM (in contrasto con le sue API visitatore) per analizzare il contenuto dei file di classe contenuti all'interno del file JAR. Inoltre, è possibile leggere i file contenuti nel file JAR utilizzando la classe JarFile. Ecco un esempio di come ciò potrebbe essere fatto:

Il metodo printMethodStubs accetta uno JarFile e procede alla stampa di descrizioni di tutti i metodi contenuti in tutti i file di classe.

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)); 
     } 
    } 
} 

Procedimento describeClass accetta un oggetto ClassNode e procede a descrivere e relativi metodi:

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(); 
} 

Procedimento describeMethod accetta un MethodNode e restituisce una stringa che descrive la firma del metodo:

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

Questo è ottimo e fa esattamente quello che ho cercato. Grazie ragazzi! – djatomic

+0

Ecco tutte le importazioni, per utilizzare questo codice: 'import java.io.InputStream; import java.util.Enumeration; import java.util.List; importare java.util.jar.JarEntry; import java.util.jar.JarFile; import org.objectweb.asm.ClassReader; importare 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

+0

Non ho trovato il buon jar da importare sul sito web. Potete aiutare per favore? grazie. Sì, conosco il vecchio post ma la domanda è molto interessante. – MychaL

1

Il modo migliore che posso pensare è quello di utilizzare il quadro ASM-bytecode. Quindi almeno non dovresti passare attraverso l'output di decompilazione con un parser di riga. In effetti, ottenere gli stub del metodo dovrebbe essere come un'implementazione di 20 linee di una delle loro interfacce Visitor.

L'ho usato io stesso per la riscrittura bytecode ed è abbastanza semplice e diretto (specialmente se si è solo che legge i file di classe).

http://asm.ow2.org/

Problemi correlati