簡體   English   中英

字節預算:生成具有循環類型的類

[英]Byte-buddy: generate classes with cyclic types

我正在嘗試生成具有循環類依賴性的類,類似於此問題: 字節伙伴-處理生成類中的循環引用

作為一個最小的示例,我要生成的類的種類具有如下依賴性:

//class A depends on class B, and vice-versa
final class A { B theB; }
final class B { A theA; }

上面鏈接中接受的答案沒有為我提供足夠的信息來使它起作用。 這是我嘗試的:

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得到Exception in thread "main" java.lang.IllegalStateException: Cannot resolve declared type of a latent type description: class B標記行中的Exception in thread "main" java.lang.IllegalStateException: Cannot resolve declared type of a latent type description: class B

上面提到的問題的答案是“確保在正確定義潛在類型之前,不要加載類型”,而且我猜這可能是我的問題。 我不知道如何定義潛在類型:-(

編輯:使AB類比最終版本高(因為這將是理想的解決方案)

編輯:添加堆棧跟蹤

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)

這是Byte Buddy中的錯誤; 類型注釋的解析器需要知道任何類型描述​​的深度,因此可以解析任何類型描述​​的類型路徑。 對於潛在類型,此深度始終為0,但默認實現采用更復雜的解決方案。

此問題將在下一版本中修復。 同時,子類化潛在類型描述並重寫該方法以返回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();
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM