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();
}