【发布时间】:2019-05-02 21:33:45
【问题描述】:
如何在构造函数拦截器中启动对象字段?
我使用 Byte Buddy 创建了一个构造函数,如下面的代码所示。
Class<?> klass = new ByteBuddy()
.subclass(Object.class, ConstructorStrategy.Default.NO_CONSTRUCTORS)
.defineProperty("origin", CoreObject.class, true)
.defineProperty("variableNamedField", Map.class, true)
.defineConstructor(Visibility.PUBLIC)
.withParameters(CoreObject.class)
.intercept(
// Invoke Objects default constructor explicitly
MethodCall.invoke(Object.class.getConstructor())
.andThen(FieldAccessor.ofField("origin").setsArgumentAt(0))
.andThen(FieldAccessor.ofField("variableNamedField").setsValue(new HashMap<>()))
.andThen(MethodDelegation.to(new FillMapInterceptor("variableNamedField")))
//
// I have to fill the map.
// Something like this:
//
// variableNamedField.put("first", new FirstHandler(origin));
// variableNamedField.put("second", new SecondHandler(origin));
//
)
.make()
.load(CoreObject.class.getClassLoader())
.getLoaded();
首先构造函数将参数保存到私有字段。然后它创建集合。然后它调用以下拦截器来填充该集合。
class FillMapInterceptor {
private final String mapField;
public FillMapInterceptor(String mapField) {
this.mapField = mapField;
}
public void construct(@FieldValue("variableNamedField") Map<String, Handler> map, @FieldValue("origin") CoreObject coreObject){
map.put("first", new FirstHandler(coreObject));
map.put("second", new SecondHandler(coreObject));
}
}
最好在拦截器中实例化 variableNamedField 字段,因为事实证明,每次创建新的类实例时,variableNamedField 字段都会用相同的 HashMap 对象实例化。但是,我只能通过 @FieldValue 注释将现有字段传递给拦截器。但似乎我无法在拦截器中分配带有新变量的字段。
- 如何在构造函数拦截器中启动类字段?我只能在拦截器中使用@FieldValue 来处理现有字段值。
- 如何使字段名称任意? @FieldValue 之类的注解需要常量参数(例如字段名称)。也许,我可以以某种方式从 defineProperty 方法结果中获取字段并将其传递给拦截器或用作拦截器的字段?
- 如何将构造函数参数直接传递给拦截器?我不喜欢先初始化字段,然后通过@FieldValue注解将字段传递给拦截器的方式。
【问题讨论】:
标签: java byte-buddy