我已成功使用ASM将动态生成的字节码转储到文件中,但无法加载它。错误消息是:
java.lang.ClassFormatError: JVMCFRE102 field signature invalid; class=TGWD, offset=0
at java.lang.ClassLoader.defineClass(ClassLoader.java:364)
at java.lang.ClassLoader.defineClass(ClassLoader.java:284)
at java.lang.invoke.ByteCodeClassLoader.run(ByteCodeClassLoader.java:20)
BytecodeClassLoader
是我在这里写的课程。 javap -v结果也显示如下。
Classfile /C:/temp/TGWD.class
Last modified Mar 10, 2015; size 750 bytes
MD5 checksum 462ec39a439ab0d30c676eb92a93fd5a
public class TGWD extends java.lang.invoke.BaseTemplate
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Utf8 TGWD
#2 = Class #1 // TGWD
#3 = Utf8 java/lang/invoke/BaseTemplate
#4 = Class #3 // java/lang/invoke/BaseTemplate
#5 = Utf8 guard
#6 = Utf8 Ljava/lang/invoke/MethodHandle;
#7 = Utf8 trueTarget
#8 = Utf8 falseTarget
#9 = Utf8 <init>
#10 = Utf8 (Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V
#11 = Utf8 java.lang.invoke.MethodHandle
#12 = NameAndType #5:#11 // guard:java.lang.invoke.MethodHandle
#13 = Fieldref #2.#12 // TGWD.guard:java.lang.invoke.MethodHandle
#14 = NameAndType #7:#11 // trueTarget:java.lang.invoke.MethodHandle
#15 = Fieldref #2.#14 // TGWD.trueTarget:java.lang.invoke.MethodHandle
#16 = NameAndType #8:#11 // falseTarget:java.lang.invoke.MethodHandle
#17 = Fieldref #2.#16 // TGWD.falseTarget:java.lang.invoke.MethodHandle
#18 = Utf8 eval
#19 = Utf8 ()V
#20 = Utf8 Hello
#21 = Utf8 (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
#22 = Utf8 java/lang/Throwable
#23 = Class #22 // java/lang/Throwable
#24 = NameAndType #5:#6 // guard:Ljava/lang/invoke/MethodHandle;
#25 = Fieldref #2.#24 // TGWD.guard:Ljava/lang/invoke/MethodHandle;
#26 = Utf8 java/lang/invoke/MethodHandle
#27 = Class #26 // java/lang/invoke/MethodHandle
#28 = Utf8 invokeExact
#29 = Utf8 (Ljava/lang/String;)Z
#30 = NameAndType #28:#29 // invokeExact:(Ljava/lang/String;)Z
#31 = Methodref #27.#30 // java/lang/invoke/MethodHandle.invokeExact:(Ljava/lang/String;)Z
#32 = NameAndType #7:#6 // trueTarget:Ljava/lang/invoke/MethodHandle;
#33 = Fieldref #2.#32 // TGWD.trueTarget:Ljava/lang/invoke/MethodHandle;
#34 = NameAndType #28:#21 // invokeExact:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
#35 = Methodref #27.#34 // java/lang/invoke/MethodHandle.invokeExact:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
#36 = NameAndType #8:#6 // falseTarget:Ljava/lang/invoke/MethodHandle;
#37 = Fieldref #2.#36 // TGWD.falseTarget:Ljava/lang/invoke/MethodHandle;
#38 = Utf8 Code
#39 = Utf8 StackMapTable
#40 = Utf8 Exceptions
{
final java.lang.invoke.MethodHandle guard;
flags: ACC_FINAL
final java.lang.invoke.MethodHandle trueTarget;
flags: ACC_FINAL
final java.lang.invoke.MethodHandle falseTarget;
flags: ACC_FINAL
public TGWD(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
flags: ACC_PUBLIC, ACC_VARARGS
Code:
stack=0, locals=4, args_size=4
0: aload_0
1: aload_1
2: bipush 0
4: aaload
5: putfield #13 // Field guard:java.lang.invoke.MethodHandle
8: aload_0
9: aload_1
10: bipush 1
12: aaload
13: putfield #15 // Field trueTarget:java.lang.invoke.MethodHandle
16: aload_0
17: aload_1
18: bipush 2
20: aaload
21: putfield #17 // Field falseTarget:java.lang.invoke.MethodHandle
24: return
public void eval();
flags: ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
public java.lang.String Hello(java.lang.String, java.lang.String) throws java.lang.Throwable;
flags: ACC_PUBLIC
Code:
stack=0, locals=3, args_size=3
0: aload_0
1: getfield #25 // Field guard:Ljava/lang/invoke/MethodHandle;
4: aload_1
5: invokevirtual #31 // Method java/lang/invoke/MethodHandle.invokeExact:(Ljava/lang/String;)Z
8: ifeq 21
11: aload_0
12: getfield #33 // Field trueTarget:Ljava/lang/invoke/MethodHandle;
15: aload_1
16: aload_2
17: invokevirtual #35 // Method java/lang/invoke/MethodHandle.invokeExact:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
20: areturn
21: aload_0
22: getfield #37 // Field falseTarget:Ljava/lang/invoke/MethodHandle;
25: aload_1
26: aload_2
27: invokevirtual #35 // Method java/lang/invoke/MethodHandle.invokeExact:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
30: areturn
StackMapTable: number_of_entries = 1
frame_type = 21 /* same */
Exceptions:
throws java.lang.Throwable
}
我可以知道生成的字节码在哪里出错吗?谢谢。 我还在这里附加了类文件Class File ..
以下信息可能有用: 1, 根据堆栈,我猜问题是三个现场成员。我使用下面的代码生成这些字段:
FieldVisitor fv;
fv = cw.visitField(ACC_FINAL, 'guard', "Ljava/lang/..", null, null);
fv.visitEnd();
我将ACC_FINAL
更改为ACC_PRIVATE
。结果是相同的,除了javap -v
结果中没有显示三个字段成员。
2,Base类BaseTemplate
是一个空的抽象类,定义为:
public abstract class BaseTemplate { }
============================== 更新:
从
中更改原始代码中的putfield指令后 mv.visitFieldInsn(PUTFIELD, className, list.get(i).name(), list.get(i).type());
到
mv.visitFieldInsn(PUTFIELD, className, list.get(i).name(),Utils.getFieldDesc(list.get(i).type()));
,类加载现在成功。原因是wronlg字段签名集(如@Holger中的答案)。
答案 0 :(得分:1)
您使用"java.lang.invoke.MethodHandle"
作为字段签名而不是正确的"Ljava/lang/invoke/MethodHandle;"
来生成构造函数。这可以在行的javap
输出中看到:
5: putfield #13 // Field guard:java.lang.invoke.MethodHandle
…
13: putfield #15 // Field trueTarget:java.lang.invoke.MethodHandle
…
21: putfield #17 // Field falseTarget:java.lang.invoke.MethodHandle
而Hello
方法正确使用:
1: getfield #25 // Field guard:Ljava/lang/invoke/MethodHandle;
…
12: getfield #33 // Field trueTarget:Ljava/lang/invoke/MethodHandle;
…
22: getfield #37 // Field falseTarget:Ljava/lang/invoke/MethodHandle;
这也解释了相当大的常数池。项目#11包含错误的java.lang.invoke.MethodHandle
签名,然后由构造函数使用的后续项目#12 - #17使用。这些与Hello
方法中使用的项目#25,#33和#37不同。在正确生成的类中,这些指令共享常量池中的相同项(它们都间接引用存储在此类文件中的项#6中的正确签名Ljava/lang/invoke/MethodHandle;
。