我无法加载使用 ASM 库修改字节码后的类。
这里是恒等更改器(mutator),我希望得到与字节一大小相同的修改后的数组,但它短了两倍! (439 比 278)
String path = SimpleClass.class.getName().replace(".", "/") + ".class";
ClassLoader classLoader = SimpleClass.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream(path);
byte[] bytes = IOUtils.toByteArray(is);
ClassReader reader = new ClassReader(bytes);
ClassWriter writer = new ClassWriter(reader, 0);
byte[] modified = writer.toByteArray();
加载失败没什么奇怪的。 我怀疑 header 被截断,但第一个字节是相同的 两个数组。
-54、-2、-70
static class ByteClassLoader extends ClassLoader {
public Class define(String name, byte[] body) {
return defineClass(name, body, 0, body.length);
}
}
ByteClassLoader myLoader = new ByteClassLoader();
Class myClass = myLoader.define("Ooo", modified);
因错误而失败:
java.lang.UnsupportedClassVersionError: Ooo has been compiled by a more recent version of the Java Runtime (class file version 0.0), this version of the Java Runtime only recognizes class file versions up to 52.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at PrintTest$ByteClassLoader.define(PrintTest.java:24)
at PrintTest.x(PrintTest.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:253)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
最佳答案
这些字节对应于 0xcafeba
,它与 Java 类文件魔数(Magic Number) 0xcafebabe
相匹配。
这里的问题是 new ClassWriter(reader, 0)
并没有做你可能认为它会做的事情;请参阅API documentation :
classReader
- the ClassReader used to read the original class. It will be used to copy the entire constant pool from the original class and also to copy other fragments of original bytecode where applicable.
我们仍然需要让作者通过 ClassReader.accept
访问读者。 ,如下:
reader.accept(writer, 0);
<小时/>
顺便说一句,您不需要 IOUtils.toByteArray
因为 ClassReader
有一个 constructor taking InputStream
.
关于java - 如何使用ASM进行字节码转换后定义类(类文件版本0.0),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38917284/