Byte-buddy:使用循环类型生成 类
Byte-buddy: generate classes with cyclic types
我正在尝试生成具有循环 class 依赖关系的 classes,类似于这个问题:
作为一个最小的例子,我想要生成的那种 classes 具有这样的依赖关系:
//class A depends on class B, and vice-versa
final class A { B theB; }
final class B { A theA; }
上面 link 中接受的答案没有为我提供足够的信息来使它起作用。这是我试过的:
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.jar.asm.Opcodes;
public class ByteBuddyHello {
public static void main(String[] args) {
try {
final ByteBuddy bb = new ByteBuddy();
final TypeDescription.Latent typeDescrA = new TypeDescription.Latent("A", 0, null, null);
final TypeDescription.Latent typeDescrB = new TypeDescription.Latent("B", 0, null, null);
final DynamicType.Unloaded<Object> madeA = bb
.subclass(Object.class)
.name("A")
.defineField("theB", typeDescrB, Opcodes.ACC_PUBLIC)
.make(); // exception thrown here!
final DynamicType.Unloaded<Object> madeB = bb.subclass(Object.class)
.name("B")
.defineField("theA", typeDescrA, Opcodes.ACC_PUBLIC)
.make();
Object a = madeA
.include(madeB)
.load(ByteBuddyHello.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded().newInstance();
System.out.println(a.toString());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
当我运行这个时,我在标记行中得到Exception in thread "main" java.lang.IllegalStateException: Cannot resolve declared type of a latent type description: class B
。
上面提到的问题的答案是 "Make sure that you do not load a type before defining the latent type properly",我猜这可能是我的问题。我不知道如何定义潜在类型:-(
编辑:使 classes A
和 B
高于最终版本(因为这将是理想的解决方案)
编辑:添加堆栈跟踪
Exception in thread "main" java.lang.IllegalStateException: Cannot resolve declared type of a latent type description: class B
at net.bytebuddy.description.type.TypeDescription$Latent.getDeclaringType(TypeDescription.java:7613)
at net.bytebuddy.description.type.TypeDescription$AbstractBase.getSegmentCount(TypeDescription.java:6833)
at net.bytebuddy.implementation.attribute.AnnotationAppender$ForTypeAnnotations.onNonGenericType(AnnotationAppender.java:617)
at net.bytebuddy.implementation.attribute.AnnotationAppender$ForTypeAnnotations.onNonGenericType(AnnotationAppender.java:333)
at net.bytebuddy.description.type.TypeDescription$Generic$OfNonGenericType.accept(TypeDescription.java:3364)
at net.bytebuddy.implementation.attribute.FieldAttributeAppender$ForInstrumentedField.apply(FieldAttributeAppender.java:122)
at net.bytebuddy.dynamic.scaffold.TypeWriter$FieldPool$Record$ForExplicitField.apply(TypeWriter.java:270)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:4156)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1633)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:174)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:155)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:2559)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:2661)
at my.package.playground.ByteBuddyHello.main(ByteBuddyHello.java:20)
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:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
这是字节好友中的一个错误;类型注释的解析器需要知道任何类型描述的深度,因此解析任何类型描述的类型路径。对于潜在类型,此深度始终为 0,但默认实现应用更复杂的解决方案。
这将在下一版本中修复。同时,将潜在类型描述子类化并将方法重写为 return 0.
我决定不更改 TypeDescription.Latent
类型,而是让 InstrumentedType.Default
实现更易于访问。使用后一种类型,它允许您定义对任何用户都可见的循环类型的特征。这样,如果您想要定义针对此功能进行验证的 Implementation
,您可以指定现有的字段和方法。
这是一个有效的解决方案,遵循公认的答案:
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.annotation.AnnotationList;
import net.bytebuddy.description.modifier.ModifierContributor;
import net.bytebuddy.description.modifier.TypeManifestation;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.jar.asm.Opcodes;
import java.io.File;
import java.io.IOException;
import java.util.List;
class TypeDescrFix extends TypeDescription.Latent {
TypeDescrFix(final String name, final int modifiers, final Generic superClass, final List<? extends Generic> interfaces) {
super(name, modifiers, superClass, interfaces);
}
@Override
public int getSegmentCount() {
return 0;
}
@Override
public AnnotationList getDeclaredAnnotations() {
return new AnnotationList.Empty();
}
}
public class ByteBuddyHello {
public static void main(String[] args) {
try {
final ByteBuddy bb = new ByteBuddy();
final TypeDescription.Latent typeDescrA = new TypeDescrFix("A", 0, null, null);
final TypeDescription.Latent typeDescrB = new TypeDescrFix("B", 0, null, null);
final DynamicType.Unloaded<Object> madeA = bb
.subclass(Object.class)
.name("A")
.modifiers(ModifierContributor.Resolver.of(Visibility.PUBLIC, TypeManifestation.FINAL).resolve())
.defineField("theB", typeDescrB, Opcodes.ACC_PUBLIC)
.make();
final DynamicType.Unloaded<Object> madeB = bb.subclass(Object.class)
.name("B")
.modifiers(ModifierContributor.Resolver.of(Visibility.PUBLIC, TypeManifestation.FINAL).resolve())
.defineField("theA", typeDescrA, Opcodes.ACC_PUBLIC)
.make();
Object a = madeA
.include(madeB)
.load(ByteBuddyHello.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded().newInstance();
System.out.println(a.toString());
final File folder = new File("/tmp/ByteBuddyHello");
madeA.saveIn(folder);
madeB.saveIn(folder);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
我正在尝试生成具有循环 class 依赖关系的 classes,类似于这个问题:
作为一个最小的例子,我想要生成的那种 classes 具有这样的依赖关系:
//class A depends on class B, and vice-versa
final class A { B theB; }
final class B { A theA; }
上面 link 中接受的答案没有为我提供足够的信息来使它起作用。这是我试过的:
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.jar.asm.Opcodes;
public class ByteBuddyHello {
public static void main(String[] args) {
try {
final ByteBuddy bb = new ByteBuddy();
final TypeDescription.Latent typeDescrA = new TypeDescription.Latent("A", 0, null, null);
final TypeDescription.Latent typeDescrB = new TypeDescription.Latent("B", 0, null, null);
final DynamicType.Unloaded<Object> madeA = bb
.subclass(Object.class)
.name("A")
.defineField("theB", typeDescrB, Opcodes.ACC_PUBLIC)
.make(); // exception thrown here!
final DynamicType.Unloaded<Object> madeB = bb.subclass(Object.class)
.name("B")
.defineField("theA", typeDescrA, Opcodes.ACC_PUBLIC)
.make();
Object a = madeA
.include(madeB)
.load(ByteBuddyHello.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded().newInstance();
System.out.println(a.toString());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
当我运行这个时,我在标记行中得到Exception in thread "main" java.lang.IllegalStateException: Cannot resolve declared type of a latent type description: class B
。
上面提到的问题的答案是 "Make sure that you do not load a type before defining the latent type properly",我猜这可能是我的问题。我不知道如何定义潜在类型:-(
编辑:使 classes A
和 B
高于最终版本(因为这将是理想的解决方案)
编辑:添加堆栈跟踪
Exception in thread "main" java.lang.IllegalStateException: Cannot resolve declared type of a latent type description: class B
at net.bytebuddy.description.type.TypeDescription$Latent.getDeclaringType(TypeDescription.java:7613)
at net.bytebuddy.description.type.TypeDescription$AbstractBase.getSegmentCount(TypeDescription.java:6833)
at net.bytebuddy.implementation.attribute.AnnotationAppender$ForTypeAnnotations.onNonGenericType(AnnotationAppender.java:617)
at net.bytebuddy.implementation.attribute.AnnotationAppender$ForTypeAnnotations.onNonGenericType(AnnotationAppender.java:333)
at net.bytebuddy.description.type.TypeDescription$Generic$OfNonGenericType.accept(TypeDescription.java:3364)
at net.bytebuddy.implementation.attribute.FieldAttributeAppender$ForInstrumentedField.apply(FieldAttributeAppender.java:122)
at net.bytebuddy.dynamic.scaffold.TypeWriter$FieldPool$Record$ForExplicitField.apply(TypeWriter.java:270)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:4156)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1633)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:174)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:155)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:2559)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:2661)
at my.package.playground.ByteBuddyHello.main(ByteBuddyHello.java:20)
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:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
这是字节好友中的一个错误;类型注释的解析器需要知道任何类型描述的深度,因此解析任何类型描述的类型路径。对于潜在类型,此深度始终为 0,但默认实现应用更复杂的解决方案。
这将在下一版本中修复。同时,将潜在类型描述子类化并将方法重写为 return 0.
我决定不更改 TypeDescription.Latent
类型,而是让 InstrumentedType.Default
实现更易于访问。使用后一种类型,它允许您定义对任何用户都可见的循环类型的特征。这样,如果您想要定义针对此功能进行验证的 Implementation
,您可以指定现有的字段和方法。
这是一个有效的解决方案,遵循公认的答案:
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.annotation.AnnotationList;
import net.bytebuddy.description.modifier.ModifierContributor;
import net.bytebuddy.description.modifier.TypeManifestation;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.jar.asm.Opcodes;
import java.io.File;
import java.io.IOException;
import java.util.List;
class TypeDescrFix extends TypeDescription.Latent {
TypeDescrFix(final String name, final int modifiers, final Generic superClass, final List<? extends Generic> interfaces) {
super(name, modifiers, superClass, interfaces);
}
@Override
public int getSegmentCount() {
return 0;
}
@Override
public AnnotationList getDeclaredAnnotations() {
return new AnnotationList.Empty();
}
}
public class ByteBuddyHello {
public static void main(String[] args) {
try {
final ByteBuddy bb = new ByteBuddy();
final TypeDescription.Latent typeDescrA = new TypeDescrFix("A", 0, null, null);
final TypeDescription.Latent typeDescrB = new TypeDescrFix("B", 0, null, null);
final DynamicType.Unloaded<Object> madeA = bb
.subclass(Object.class)
.name("A")
.modifiers(ModifierContributor.Resolver.of(Visibility.PUBLIC, TypeManifestation.FINAL).resolve())
.defineField("theB", typeDescrB, Opcodes.ACC_PUBLIC)
.make();
final DynamicType.Unloaded<Object> madeB = bb.subclass(Object.class)
.name("B")
.modifiers(ModifierContributor.Resolver.of(Visibility.PUBLIC, TypeManifestation.FINAL).resolve())
.defineField("theA", typeDescrA, Opcodes.ACC_PUBLIC)
.make();
Object a = madeA
.include(madeB)
.load(ByteBuddyHello.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded().newInstance();
System.out.println(a.toString());
final File folder = new File("/tmp/ByteBuddyHello");
madeA.saveIn(folder);
madeB.saveIn(folder);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}