2010-04-22 4 views
5

Je cherche un moyen d'obtenir une liste de stubs de toutes les classes dans un fichier jar. Je ne sais pas par où commencer ... Puis-je utiliser Reflection ou Javassist ou d'autres outils dont je n'ai pas encore entendu parler? Au moins, il peut être possible de décompresser le fichier jar, de décompiler les fichiers de classe et de scanner avec un analyseur de ligne pour les méthodes, mais je pense que c'est le plus sale ;-)Java: Un moyen facile d'extraire la méthode de fichiers de classe dans un fichier JAR? Réflexion?

Des idées?

Cordialement

Répondre

11

Se appuyant sur aioobe's answer, vous pouvez également utiliser l'API de l'arbre de l'ASM (par opposition à son API visiteur) pour analyser le contenu des fichiers de classe contenus dans votre fichier JAR. Vous pouvez également lire les fichiers contenus dans le fichier JAR à l'aide de la classe JarFile. Voici un exemple de la façon dont cela pourrait être fait:

La méthode printMethodStubs accepte un JarFile et continue à imprimer des descriptions de toutes les méthodes contenues dans tous les fichiers de 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)); 
     } 
    } 
} 

La méthode describeClass accepte un objet ClassNode et procède à décrire et ses méthodes associées:

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

La méthode describeMethod accepte un MethodNode et retourne une chaîne qui décrit la signature de la méthode:

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

C'est génial et fait exactement ce que j'ai cherché. Merci les gars! – djatomic

+0

Voici toutes les importations, pour utiliser ce code: '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; importer xbn.lang.SimpleXbnObject; ' – aliteralmind

+0

Je n'ai pas trouvé le bon pot à importer sur le site web. Pouvez-vous aider s'il vous plaît ? Je vous remercie. Oui, je connais le vieux post mais la question est très intéressante. – MychaL

1

La meilleure façon que je peux penser est d'utiliser le cadre ASM-bytecode. Au moins, vous n'auriez pas à passer par une décompilation-sortie avec un analyseur de ligne. En fait, obtenir les stubs de méthode devrait être comme une implémentation en 20 lignes d'une de leurs interfaces visiteurs.

Je l'ai utilisé moi-même pour la réécriture de bytecode et c'est assez simple et direct (surtout si vous êtes juste lecture les fichiers de classe).

http://asm.ow2.org/

Questions connexes