Разрешить имя класса из байт-кода - PullRequest
1 голос
/ 30 октября 2009

Можно ли выкопать имя класса из байт-кода, который сформирован из исходного кода класса?

Ситуация такова: я получаю байт-код класса откуда-то удаленно, не важно, откуда он. Чтобы эффективно загрузить этот класс загрузчиком классов, мне нужно было бы также иметь имя класса ... верно?

Ответы [ 5 ]

9 голосов
/ 30 октября 2009

Если вам просто нужно имя класса, вероятно, проще разобрать начало файла класса, а не добавлять стороннюю библиотеку для манипулирования кодом класса только для этой цели. Вам просто нужны классы и строки из пула констант, пропустите флаги доступа и затем замените / на. в названии класса. Если у вас есть байтовый массив, вы можете вызвать этот метод с помощью 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('/', '.');
}
2 голосов
/ 30 октября 2009

Самый простой способ, вероятно, использовать что-то вроде 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();
    }
  }
}

Если вы не можете использовать стороннюю библиотеку, вы можете прочитать формат файла класса самостоятельно .

1 голос
/ 30 октября 2009

Вы должны быть в состоянии использовать javap, чтобы разобрать байт-код, если это случается время от времени.

Для того, чтобы сделать это во время выполнения: используйте библиотеку манипулирования байт-кодом, например BCEL Apache (http://jakarta.apache.org/bcel), для анализа байт-кода.

0 голосов
/ 25 декабря 2015

Просто для полноты, в случаях, когда использование библиотеки ASM5 приемлемо, следующий вызов может использоваться для получения имени класса из его байтового представления.

public String readClassName(final byte[] typeAsByte) {
    return new ClassReader(typeAsByte).getClassName().replace("/", ".");
}
0 голосов
/ 30 октября 2009

Я думаю, что вы можете использовать метод ClassLoader.defineClass в подклассе ClassLoader, чтобы получить объект Class для данного байт-кода. (не проверено)

...