Java – byte Buddy: generate a class of loop type
I am trying to generate classes with cyclic class dependencies, similar to this problem: byte buddy – handling cyclic references in generated classes
As a minimum example, the class I want to generate has such dependencies:
//class A depends on class B,and vice-versa final class A { B theB; } final class B { A theA; }
The answers accepted in the above link do not provide me with enough information to achieve this This is what I tried:
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",null,null); final TypeDescription.Latent typeDescrB = new TypeDescription.Latent("B",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(); } } }
When I run it, I get exception Java in the thread "main" Lang.illegalstateexception: cannot resolve declaration type of potential Type Description: Class B in tag line
The answer to the question mentioned above is "make sure that types are not loaded before potential types are correctly defined". I guess this may be my problem I don't know how to define potential types, although:-(
Edit: put classes a and B last (because this will be the ideal solution)
Editing: adding stack traces
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)
Solution
This is an error in byte buddy; The parser of type annotation needs to know the depth of any type description, so it parses the type path of any type description For potential types, this depth is always 0, but the default implementation applies a more complex solution
This will be fixed in the next release During this time, the subclass latent type describes and overrides the method and returns 0
I decided not to change typedescription Late type, but instrumentedtype The default implementation is easier to access Using the latter type, it allows you to define the function of loop types that can be seen by any user In this way, if you want to define an implementation that validates this function, you can specify existing fields and methods