2016-06-25 7 views
0

J'écris un programme qui analyse les fichiers .class. Je veux attacher le nom de paquet et de classe à ma sortie. Mon plan est d'écrire une fonction qui prend le nom du paquet et de la classe en entrée et trouve le fichier correspondant .class (donc l'utilisateur n'a pas à entrer cela aussi, et ne peut pas se tromper), où 'find' doit être lu comme 'donnez-moi des données que je peux utiliser comme arguments pour le constructeur ClassParser de BCEL' (soit un nom de fichier, soit un nom de fichier zip et un nom dans le fichier zip).Traduire le nom du package + class en .class filename

Comment puis-je faire? Est-ce que java vient avec quelque chose qui fait ça? Je comprends la résolution de nom à faire dans le contexte d'un CLASSPATH, donc l'utilisateur devrait probablement fournir l'un de ceux aussi; C'est très bien.

Remarque: les solutions doivent et non exécuter n'importe quel code à partir du fichier .class. Juste les octets, ma'm ;-)

Répondre

1

Eh bien, si vous utilisez BCEL, tout est déjà là, voir ClassPath:

import java.io.IOException; 
import org.apache.bcel.classfile.ClassParser; 
import org.apache.bcel.classfile.JavaClass; 
import org.apache.bcel.util.ClassPath; 

public class BcelTest { 
    public static void main(String[] args) throws IOException { 
     String classPath=System.getProperty("java.class.path"); 
     // demonstrating with our own class path examplary for an arbitrary path String 
     ClassPath cp=new ClassPath(classPath); 
     ClassPath.ClassFile cf=cp.getClassFile(BcelTest.class.getName()); 
     ClassParser p=new ClassParser(cf.getInputStream(), cf.getPath()); 
     JavaClass jc = p.parse(); 
     System.out.println(jc); 

     // or just using our own system path explicitly 
     cf=ClassPath.SYSTEM_CLASS_PATH.getClassFile("java.lang.Object"); 
     p=new ClassParser(cf.getInputStream(), cf.getPath()); 
     jc = p.parse(); 
     System.out.println(jc); 
    } 
} 
+0

Je n'ai pas explicitement déclaré, bien que je voulais dire, que la résolution de classe devrait être faite dans un chemin de classe fourni par l'utilisateur, qui peut être différent de celui avec lequel mon code fonctionne sous/avec. Je pense que tout ce que je dois faire est de donner des arguments différents à 'new ClassPath (...)'. Avec cela en place, cela semble très prometteur! –

+1

J'ai supposé que vous vouliez pouvoir fournir un chemin de classe arbitraire; C'est pourquoi j'ai choisi le constructeur dans l'exemple, sinon le 'ClassPath.SYSTEM_CLASS_PATH' fonctionnerait aussi pour l'exemple. Notez que le 'ClassPath' construit avec le chemin explicite ne trouve pas les classes du système car elles ne sont pas accessibles depuis le chemin de la classe explicite, vous devrez [fournir' SYSTEM_CLASS_PATH' comme parent] (http: //commons.apache. org/proper/commun-bcel/apidocs/org/apache/bcel/util/ClassPath.html # ClassPath-org.apache.bcel.util.ClassPath-java.lang.String-) pour cela. – Holger

0

Si vous avez déjà le classfile, remplacez simplement chaque/dans le nom de classe par le séparateur de répertoire pour votre système et ajoutez .class.

Si vous voulez passer du nom de classe Java au nom de classe bytecode, la plupart des classes sont plutôt simples. Ajouter le paquet + '.' et remplacez '.' avec '/'. Pour les classes internes et imbriquées, je ne suis pas sûr s'il existe un algorithme simple.

+0

Je n'ai pas le fichier de classe. Dis que je cours mon projet sur lui-même. Il réside dans '~/whatever /' avec 'main()' dans 'invalid/jonaskoelker/Main.java' et mon chemin de classe est'.:/Usr/share/java/bcel.jar'. L'algorithme que je veux, lorsqu'il est exécuté sur 'org.apache.bcel.classfile.ClassParser', devrait retourner deux valeurs,'/usr/share/java/bcel.jar' et 'org/apache/bcel/classfile/ClassParser.class' (cependant vous faites deux valeurs en java, par exemple une paire apache-commons). Y a-t-il une chose intégrée qui fait quelque chose dans cette direction? –

+0

@ JonasKölker Et si la même classe apparaît dans plusieurs Jars? – Antimony

+0

Je veux que le java charge, ce que je suppose et semble rappeler est le premier trouvé sur le classpath. –

0

Je veux remercier de me guider les gens bien dans irc://freenode.org/##java vers la recette suivante:

// replace 'Throwable' with something else in production code :-) 
JavaClass recipe() throws Throwable { 
    URLClassLoader loader = new URLClassLoader(new URL[] { 
      new URL("file:///usr/share/java/js.jar"), 
     }); 
    String path = "org/mozilla/classfile/ByteCode.class"; 
    InputStream resource = loader.getResourceAsStream(path); 
    String fake_filename = "<" + path + ">"; 
    ClassParser classparser = new ClassParser(resource, fake_filename); 
    JavaClass java_class = classparser.parse(); 
    // System.out.format("%s\n", jc); 
    return java_class; 
} 

Il est possible de dé-coder en dur le chemin de classe et la valeur path en calculant les chaînes dans le bon format en fonction de l'entrée de l'utilisateur. Je vais utiliser la réponse que j'ai acceptée parce qu'elle prend moins de travail de ma part, mais je veux mentionner cette réponse parce qu'elle est plus généralement applicable (c'est-à-dire avec moins de dépendances).