Question

Est-il possible d'extraire un nom de classe à partir d'un bytecode formé à partir du code source de la classe?

La situation est la suivante: je reçois un code de classes à distance de quelque part, peu importe d'où il provient. Pour charger efficacement cette classe avec un chargeur de classe, il me faudrait aussi le nom de la classe ... non?

Était-ce utile?

La solution

Si vous avez juste besoin du nom de la classe, il est probablement plus facile d'analyser vous-même le début du fichier de classe au lieu d'ajouter une bibliothèque tierce pour la manipulation du code de classe, uniquement dans ce but. Vous avez juste besoin des classes et des chaînes du pool constant, ignorez les indicateurs d'accès, puis remplacez / par. dans le nom de la classe. Si vous avez un tableau d'octets, vous pouvez appeler cette méthode avec new ByteArrayInputStream (byteArray) :

public static String getClassName(InputStream is) throws Exception {
    DataInputStream dis = new DataInputStream(is);
    dis.readLong(); // skip header and class version
    int cpcnt = (dis.readShort()&0xffff)-1;
    int[] classes = new int[cpcnt];
    String[] strings = new String[cpcnt];
    for(int i=0; i<cpcnt; i++) {
        int t = dis.read();
        if(t==7) classes[i] = dis.readShort()&0xffff;
        else if(t==1) strings[i] = dis.readUTF();
        else if(t==5 || t==6) { dis.readLong(); i++; }
        else if(t==8) dis.readShort();
        else dis.readInt();
    }
    dis.readShort(); // skip access flags
    return strings[classes[(dis.readShort()&0xffff)-1]-1].replace('/', '.');
}

Autres conseils

Le moyen le plus simple consiste probablement à utiliser quelque chose comme ASM :

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.commons.EmptyVisitor;

public class PrintClassName {
  public static void main(String[] args) throws IOException {
    class ClassNamePrinter extends EmptyVisitor {
      @Override
      public void visit(int version, int access, String name, String signature,
          String superName, String[] interfaces) {
        System.out.println("Class name: " + name);
      }
    }

    InputStream binary = new FileInputStream(args[0]);
    try {
      ClassReader reader = new ClassReader(binary);
      reader.accept(new ClassNamePrinter(), 0);
    } finally {
      binary.close();
    }
  }
}

Si vous ne pouvez pas utiliser de bibliothèque tierce, vous pouvez lisez le format du fichier de classe vous-même .

Vous devriez pouvoir utiliser javap pour désassembler le code octet, si cela se produit de temps en temps.

Pour le faire à l'exécution: utilisez une bibliothèque de manipulation de code octet comme BCEL d'Apache ( http: // jakarta. apache.org/bcel ) pour analyser le code octet.

Je pense que vous pouvez utiliser la méthode ClassLoader.defineClass, dans une sous-classe de ClassLoader, pour obtenir l'objet Class pour un bytecode donné. (non testé)

Juste pour compléter, dans les cas où l'utilisation de la bibliothèque ASM5 est acceptable, l'appel suivant peut être utilisé pour obtenir le nom de la classe à partir de sa représentation en octets.

public String readClassName(final byte[] typeAsByte) {
    return new ClassReader(typeAsByte).getClassName().replace("/", ".");
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top