Не удалось загрузить динамически сгенерированные байт-коды
Мне удалось сбросить динамически сгенерированные байт-коды в файл с помощью 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, Базовый класс 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 ответы).
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, которые используются конструктором. Они отличаются от предметов № 25, № 33 и № 37, используемых в Hello
метод. В правильно сгенерированном классе эти инструкции совместно используют одни и те же элементы в пуле констант (которые все косвенно относятся к правильной сигнатуре Ljava/lang/invoke/MethodHandle;
который хранится в пункте № 6 в этом файле класса.