Java 我们如何在编译时访问ByteBuddy生成的方法?

Java 我们如何在编译时访问ByteBuddy生成的方法?,java,code-generation,byte-buddy,Java,Code Generation,Byte Buddy,我写了这个例子: E someCreateMethod(Class<E> clazz) { Class<? extends E> dynamicType = new ByteBuddy() .subclass(clazz) .name("NewEntity") .method(named("getNumber")) .intercept(FixedValue.value

我写了这个例子:

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();
}
或获取新定义的
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和setter),比如
(atribute name)InitialDate
(atribute name)FinalDate
,这样我就可以对
E
中的每个日期使用interval函数

我想知道是否可以使用代码生成来添加这些方法,而不必为每个
E
创建子类

PS:
E
无法更改,它属于旧模块

PS2:我不知道每个实体
E
中会有多少个日期属性,但新的属性和方法将使用约定(例如
\uuuu FisrtDay
\uu 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实现的目标是可能的还是根本不可能的?还有别的办法吗


我的编辑应该是一个新问题吗

您需要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.
公共接口值提供程序{
公共T getValue();
}

类正如Thomas指出的,Byte Buddy在运行时生成类,这样编译器就无法在编译时验证它们的存在性

您可以做的是在构建时应用代码生成。如果特定模块中存在
EntityExample.class
,则可以使用Byte Buddy Maven或Gradle插件增强此模块,然后在增强后,允许编译器验证其存在性

您还可以定义接口,如

interface StringVal {
  String getStringVal();
}
您可以要求Byte Buddy在您的子类中实现它,如果您将子类表示为此接口,则允许编译器验证方法的存在性


除此之外,您的编译器正在做它应该做的事情:告诉您您正在调用一个(当时)不存在的方法。

我猜
getNumber
是在
EntityExample
接口中定义的,而
getStringVal
不是。另外,请原谅我这一愚蠢的问题。。。但是你认为你为什么要这么做?@Joe C哦,ByteBuddy让我们定义新的方法,对吗?(因为“.defineMethod”部分)所以我认为它应该给我们一些方法来访问我们正在创建的方法。。。我只是不知道怎么做。至于你的第二条评论,我需要动态地创建我作为参数传递给方法“someCreateMethod”的任何类的子类,这些子类应该实现两个新方法。这就是我想要这个的原因。谢谢你,托马斯!你能看一下我对这个问题的修改吗?我试图更好地解释我要做的事情。欢迎提出任何想法/建议/更正。感谢您澄清您的目的@ReyaGistrout,请编辑我的答案。
interface StringVal {
  String getStringVal();
}