[英]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.