Domanda

È possibile scavare un nome di classe dal bytecode che è formato dal codice sorgente della classe?

La situazione è questa: ricevo un bytecode di classi da remoto da qualche parte, non importa da dove viene. Per caricare efficacemente quella classe con un classloader avrei bisogno di avere anche il nome della classe ... giusto?

È stato utile?

Soluzione

Se hai solo bisogno del nome della classe, probabilmente è più facile analizzare tu stesso l'inizio del file di classe invece di aggiungere una libreria di terze parti per la manipolazione del codice di classe solo per questo scopo. Hai solo bisogno delle classi e delle stringhe dal pool costante, salta i flag di accesso e quindi sostituisci / con. nel nome della classe. Se si dispone di un array di byte, è possibile chiamare questo metodo con 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('/', '.');
}

Altri suggerimenti

Il modo più semplice è probabilmente usare qualcosa come 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();
    }
  }
}

Se non puoi utilizzare una libreria di terze parti, puoi leggi tu stesso il formato del file di classe .

Dovresti essere in grado di usare javap per disassemblare il codice byte, se ciò accade di tanto in tanto.

Per farlo in fase di esecuzione: utilizzare una libreria di manipolazione del codice byte come BCEL di Apache ( http: // jakarta. apache.org/bcel ) per analizzare il codice byte.

Penso che tu possa usare il metodo ClassLoader.defineClass, in una sottoclasse di ClassLoader, per ottenere l'oggetto Class per un dato bytecode. (non testato)

Solo per completezza, nei casi in cui l'uso della libreria ASM5 è accettabile, è possibile utilizzare la seguente chiamata per ottenere il nome della classe dalla sua rappresentazione in byte.

public String readClassName(final byte[] typeAsByte) {
    return new ClassReader(typeAsByte).getClassName().replace("/", ".");
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top