Pregunta

¿Es posible desenterrar un nombre de clase a partir del código de bytes que se forma a partir del código fuente de la clase?

La situación es esta: obtengo un bytecode de clases de forma remota desde algún lugar, no importa de dónde venga. Para cargar efectivamente esa clase con un cargador de clases, también necesitaría tener el nombre de la clase ... ¿verdad?

¿Fue útil?

Solución

Si solo necesita el nombre de la clase, probablemente sea más fácil analizar el comienzo del archivo de la clase usted mismo en lugar de agregar una biblioteca de terceros para la manipulación del código de la clase solo para este propósito. Solo necesita las clases y las cadenas del grupo constante, omita los indicadores de acceso y luego reemplace / con. en el nombre de la clase Si tiene una matriz de bytes, puede llamar a este método 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('/', '.');
}

Otros consejos

La forma más fácil es probablemente usar algo como 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 no puede usar una biblioteca de terceros, puede lea el formato del archivo de clase usted mismo .

Debería poder usar javap para desarmar el código de bytes, si eso sucede de vez en cuando.

Para hacerlo en tiempo de ejecución: utilice una biblioteca de manipulación de código de bytes como BCEL de Apache ( http: // jakarta. apache.org/bcel ) para analizar el código de bytes.

Creo que puede usar el método ClassLoader.defineClass, en una subclase de ClassLoader, para obtener el objeto Class para un bytecode dado. (no probado)

Solo para completar, en los casos en que el uso de la biblioteca ASM5 es aceptable, la siguiente llamada podría usarse para obtener el nombre de clase de su representación de bytes.

public String readClassName(final byte[] typeAsByte) {
    return new ClassReader(typeAsByte).getClassName().replace("/", ".");
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top