Byte-buddy: generate classes with cyclic types

倖福魔咒の 提交于 2019-12-01 15:54:10

This is a bug in Byte Buddy; the resolver for type annotations needs to know the depth of any type description and therefore resolves the type path of any type description. For latent types, this depth is always 0 but the default implementation applies a more complex solution.

This will be fixed in the next release. In the meantime, subclass the latent type description and override the method to return 0.

I decided not to change the TypeDescription.Latent type but rather make the InstrumentedType.Default implementation more accessible. Use the latter type which allows you to define features of the cyclic type which will be visible to any user. This way, you can for example specify existing fields and methods if you want to define Implementations that validate against this feature.

This is a working solution, following the accepted answer:

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();
        }
    }
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!