簡體   English   中英

我們如何在編譯時訪問ByteBuddy生成的方法?

[英]How can we access methods generated by ByteBuddy in compilation time?

我寫了這個例子:

E someCreateMethod(Class<E> clazz) {
    Class<? extends E> dynamicType = new ByteBuddy()
            .subclass(clazz)
            .name("NewEntity")
            .method(named("getNumber"))
            .intercept(FixedValue.value(100))
            .defineField("stringVal", String.class, Visibility.PRIVATE)
            .defineMethod("getStringVal", String.class, Visibility.PUBLIC)
            .intercept(FieldAccessor.ofBeanProperty())
            .make()
            .load(clazz.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
            .getLoaded();

    return dynamicType.newInstance();
}

我想用它來獲取重新定義的number屬性:

Integer num = someCreateMethod(EntityExample.class).getNumber();  //(1)

或獲取新定義的stringVal屬性:

String sVal = someCreateMethod(EntityExample.class).getStringVal(); //(2)  

我的問題是(1)效果很好,而(2)效果不好。 我收到以下錯誤:

Error:(40, 67) java: cannot find symbol

symbol:   method getStringVal()

另外,是否可以對動態生成的類執行以下操作:

NewEntity newEntity = someCreateMethod(EntityExample.class);
Integer num = newEntity.getNumber();
String sVal = newEntity.getStringVal();

編輯:感謝您的幫助,此示例是我第一次嘗試使用ByteBuddy庫。 我發現defineMethod實際上定義了接口方法的實現,而不僅僅是在類中添加隨機方法。 所以我決定在這里解釋我到底要完成什么。

對於E類中的每個Date屬性,我想再添加兩個字段(以及它們各自的getter和setters),比如說(atribute name)InitialDate(atribute name)FinalDate ,以便我可以對中的每個日期使用間隔函數E

我想知道是否可以使用代碼生成來添加這些方法,而不必為每個E創建子類。

PS: E不能更改,它屬於舊模塊。

PS2:我不知道每個實體E中將有多少個日期屬性,但是將使用約定(例如__FisrtDay__LastDay )來創建新的服裝和方法,如下所示:

NewA a = eb.create(A.class);
a.getDeadLine(); //inherited
a.getDeadLineFirstDay(); //added 
a.getDeadLineLastDay(); //added

NewA b = eb.create(B.class);
b.getBirthday(); //inherited
b.getBirthdayFirstDay(); //added
b.getBirthdayLastDay(); //added

b.getAnniversary(); //inherited
b.getAnniversaryFirstDay(); //added
b.getAnniversaryLastDay(); //added

PS3:我嘗試使用ByteBuddy甚至完成什么? 還有另一種方法嗎?

PS4:我的編輯應該是一個新問題嗎?

您需要E成為包含要嘗試調用的方法的超類/或接口-您將無法解析E上不存在的子類型方法。

這不是ByteBuddy的問題,這不是類設計的問題-您應該將要生成的功能設計和分組為可抽象的部分,以便可以通過在編譯時有意義的類型來公開它。

例如,我們可以使用超類型'ValueProvider',然后使用ByteBuddy定義IntConstantProvider。

public interface ValueProvider<T> {
    public T getValue();
}

Class<? extends ValueProvider<Integer>> dynamicType = new ByteBuddy()
    .subclass(clazz)
    .name("ConstantIntProvider")
    .method(named("getValue"))
    .intercept(FixedValue.value(100))
    // etc.

您的原型具有3個單獨的功能(如果我們將非引用私有字段視為某些預期行為的殘根),則沒有明顯的抽象來包含它們。 最好將其設計為3個簡單的原子行為,對於這些行為,抽象是顯而易見的。

您可以使用反射在任意動態定義的類上查找任意方法,但這對於編碼或設計POV而言並沒有真正的意義(您的代碼如何知道要調用的方法?如果知道,為什么不使用類型來表達出來嗎?)也不是很出色。

按照問題進行編輯 -Java Bean屬性是通過反射起作用的,因此從已知屬性中查找“相關屬性”(例如“第一/最后日期”)的例子並非不合理。

但是,可以考慮使用DateInterval(FirstDate,LastDate)類,以便每個基本屬性僅需要一個補充屬性。

正如Thomas所指出的,Byte Buddy在運行時生成類,以使您的編譯器無法在編譯期間驗證它們的存在。

您可以做的是在構建時應用代碼生成。 如果您的EntityExample.class存在於特定模塊中,則可以使用Byte Buddy Maven或Gradle插件來增強此模塊,然后在增強后允許編譯器驗證其存在。

您還可以做的是定義接口,例如

interface StringVal {
  String getStringVal();
}

您可以要求Byte Buddy在您的子類中實現,如果您將子類表示為此接口,則允許編譯器驗證方法的存在。

除此之外,您的編譯器完全按照預期的方式運行:告訴您正在調用的方法(當時不存在)。

暫無
暫無

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

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