我写了这个例子:
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
atributte:
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和setter),让我们说(atribute name)InitialDate
和(atribute name)FinalDate
,这样我就可以对E
中的每个日期使用间隔功能。
我想知道是否可以使用代码生成来添加这些方法,而无需为每个E
创建子类。
PS:E
无法更改,它属于传统模块。
PS2:我不知道每个实体E
中会有多少个日期属性,但新的属性和方法将使用约定创建(例如__FisrtDay
,{{1} }),如下所示:
__LastDay
PS3:我正在尝试用ByteBuddy或者根本不可能实现的目标吗?还有另外一种方法吗?
PS4:我的编辑应该是一个新问题吗?
答案 0 :(得分:4)
您需要E成为超类/或接口,其中包含您尝试调用的方法 - 您将无法解析E上不存在的子类型方法。
这不是ByteBuddy的问题,这是你的课程设计的一个问题 - 你应该设计&amp;将您想要生成的功能分组为可抽象的部分,因此可以通过在编译时有意义的类型进行公开。
例如,我们可以使用超类型'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)类,以便每个基本属性只需要一个补充属性。
答案 1 :(得分:0)
正如Thomas指出的那样,Byte Buddy在运行时生成类,这样编译器就无法在编译期间验证它们的存在。
您可以做的是在构建时应用代码生成。如果您的EntityExample.class
存在于特定模块中,则可以使用Byte Buddy Maven或Gradle插件增强此模块,然后在增强后,允许编译器验证它们的存在。
您还可以做的是定义
等接口interface StringVal {
String getStringVal();
}
您可以要求Byte Buddy在您的子类中实现,如果您将子类表示为此接口,则允许编译器验证方法的存在。
除此之外,您的编译器正在完成它应该做的事情:告诉您正在调用一个不存在的方法(当时)。