java - ByteBuddy 拦截 setter 并使用参数调用方法,具体取决于调用 setter 方法的对象
问题描述
我想拦截在一个类的所有实例上调用的每个 setter 方法,然后在另一个类对象上调用一个方法,其参数对应于第一个类的每个实例的某些字段值。为此,我想使用 ByteBuddy API,但我也想为指定类的所有实例只创建一个子类
例如,我编写了以下代码:
public final class AttributesIntercepted<T> {
private static EnumMap<ResourceType, Class> attributesClasses = new EnumMap<>(ResourceType.class);
private Target target;
private T attributes;
private Resource resource;
private AttributesIntercepted(T attributes, Target target, Resource resource) {
this.attributes = attributes;
this.target = target;
this.resource = resource;
}
private T makeInstance() {
T instance = null;
try {
Class subClass;
if (!attributesClasses.containsKey(resource.getType())) {
subClass = new ByteBuddy()
.subclass(attributes.getClass())
.method(ElementMatchers.isSetter())
.intercept(SuperMethodCall.INSTANCE.andThen(
MethodCall.invoke(target.getClass().getMethod("updateResource", Resource.class))
.on(target)
.with(resource)
)).make()
.load(attributes.getClass().getClassLoader())
.getLoaded();
attributesClasses.put(resource.getType(), subClass);
} else {
subClass = attributesClasses.get(resource.getType());
}
// create the new instance of this subclass
instance = (T) (subClass.getDeclaredConstructor(attributes.getClass()).newInstance(attributes));
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
System.out.println(e.toString());
}
return instance;
}
public static<T> T create(T attributes, Target target, Resource resource) {
return (T) (new AttributesIntercepted(attributes, target, resource).makeInstance());
}
}
我将每个资源类型创建的每个子类保存在一个地图中,以便为每个资源类型只创建一个子类。这里的问题是,对于创建的子类的所有实例,传递给目标对象上调用的方法“updateResource”的参数“resource”的值将始终相同。似乎传递给目标对象的参数是在创建子类时评估的,而不是在调用 setter 时
如果我只是在注释中将保存子类的代码放在地图中,它可以工作,但是,正如我所说,我只想为每种资源类型创建一个子类......
谢谢你的帮助
解决方案
您应该使用 Byte BuddyTypeCache
并避免使用自己的解决方案,它会帮助您避免一些常见问题。
至于您的拦截:defineField
在您的 DSL 中使用这些值定义字段。然后代替on(target)
,你做onField(...)
和withField(...)
。创建类后,您现在需要为您创建的任何特定实例设置这些字段,这样您就可以在所有场合重用该类。
推荐阅读
- javascript - 隐藏/显示基于 javascript 按钮单击的视频元素
- css - 如何创建 CSS 代码以覆盖自定义 CC 中的现有主题断点?
- javascript - 打开多个选项卡,将方法附加到它们并让它们在各自的选项卡上运行
- reactjs - 用于家族树 Neo4J 和 React Tree Graph 的 JSON
- reactjs - 我不断收到此错误。类型错误:addItems 不是函数。(在 'addItems(text)' 中,'addItems' 是 Object 的一个实例)
- python - datetime.datetime.strptime("%d/%m/%Y %H:%M:%S").timetuple().tm_hour
- sql-server - SSIS 变量表达式 - 转换为字符串
- python - SQLAlchemy:从连接中获取数据库名称
- php - 无需提交即可获取表单的输入值并将其放在php中的变量中
- android - 我们可以检测到主页启动器更改事件吗