是否有可能从类源代码中形成的字节码中挖掘出类名?
情况是这样的:我从某个地方远程获取一个类字节码,它来自哪里无关紧要。要使用类加载器有效地加载该类,我还需要拥有类名...对吗?
答案 0 :(得分:9)
如果您只需要类名,则可能更容易自行解析类文件的开头,而不是为此目的添加第三方库以进行类代码操作。您只需要来自常量池的类和字符串,跳过访问标志然后替换/。在班级名称中。如果您有一个字节数组,则可以使用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('/', '.');
}
答案 1 :(得分:2)
最简单的方法可能是使用类似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();
}
}
}
如果您无法使用第三方库,则可以read the class file format yourself。
答案 2 :(得分:1)
如果只是偶尔发生一次,你应该可以使用javap
来反汇编字节码。
在运行时这样做:使用像Apache的BCEL(http://jakarta.apache.org/bcel)这样的字节码操作库来分析字节码。
答案 3 :(得分:0)
我认为您可以在ClassLoader的子类中使用ClassLoader.defineClass方法来获取给定字节码的Class对象。 (未经测试)
答案 4 :(得分:0)
为了完整起见,在可以使用ASM5库的情况下,可以使用以下调用从其字节表示中获取类名。
def myVar = build.getEnvironment(listener).get('JOB_NAME')
println "JOB_NAME = " + myVar