我创建了一个类的CGLib动态代理,但是当我尝试访问原始类中声明的任何字段时,我获得了java.lang.NoSuchFieldException。我需要获取该字段才能更改其值。
顺便说一句,这是代理所基于的类:
public class Person {
private String name;
....
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
...
}
这是提升上述异常(更具体地说是第一行)的代码片段(在“MethodInterceptor”的“拦截”方法内):
public Object intercept(Object instance, Method jdkMethod, Object[] args, MethodProxy method) throws Throwable {
...
Field field = instance.getClass().getField("name");
field.setAccessible(true);
field.set(instance, "foo");
....
您是否知道以其他方式访问所需字段或更改其值?
感谢。
答案 0 :(得分:2)
显然,CGLib代理是原始类的子类。因此,以下代码运作良好:
Field field = instance.getClass().getSuperclass().getDeclaredField("name");
答案 1 :(得分:1)
尝试:
Field field = instance.getClass().getDeclaredField("name");
如this SO answer中所述,getField仅适用于公共字段,但适用于整个类层次结构。您可以将其视为检查类的公共接口。 getDeclaredField适用于私有字段,不会检查类层次结构;你可以把它想象成解决类的实现。
答案 2 :(得分:1)
即使您已经找到了解决问题的方法,但这里有一个关于cglib如何工作以及导致问题的原因的简短说明。考虑到您的Person
类,cglib在运行时创建另一个代表您的代理的类。这个类在Java源代码中大致类似于以下内容,但是,使用的许多实例都是缓存的,这就是cglib添加其他几个字段的原因。此外,MethodInterceptor
通过使用不同的静态字段注入:
public class Person$EnhancedByCglib extends Person {
private static class GetNameMethodProxy extends MethodProxy {
@Override
public Object invokeSuper(Object instance,
Object[] arguments) {
return ((Person$EnhancedByCglib) instance).getNameSuper();
}
// ...
}
// ...
private static MethodInterceptor methodInterceptor;
@Override
public String getName() {
return (String) methodInterceptor.intercept(this,
getClass().getDeclaredMethod("getName"),
new Object[0],
new GetNameMethodProxy());
}
private String getNameSuper() {
return super.getName();
}
@Override
public void setName(String name) {
methodInterceptor.intercept(this,
getClass().getDeclaredMethod("setName", String.class),
new Object[] {name},
new SetNameMethodProxy());
}
private void setNameSuper(String name) {
super.setName(name);
}
// ...
}
如您所见,通过覆盖任何方法来实现拦截。这样,您的MethodInterceptor
将被调用,而不是使用MethodProxy
仍然可以调用的原始方法。由于拦截,使用cglib时调用getMethod
或getDeclaredMethod
按预期工作。但是,字段不会被继承,这就是您需要在一个类中浏览类层次结构的原因。这就是原因:
instance.getClass().getSuperclass().getDeclaredField("name");
的工作原理。请注意,不再维护cglib。如果您正在寻找替代方案,请查看我的图书馆Byte Buddy。但请注意,我将在下周某个时候发布一个完全稳定的版本。当前的v0.1版本包含一些过早的功能。