Java 尝试更改CGLib代理字段值时出现异常

Java 尝试更改CGLib代理字段值时出现异常,java,proxy,cglib,Java,Proxy,Cglib,我创建了一个类的CGLib动态代理,但是当我试图访问原始类中声明的任何字段时,我获得了java.lang.NoSuchFieldException。我需要获取字段以更改其值 顺便说一下,这是代理所基于的类: public class Person { private String name; .... public String getName() { return name; } public void setName(String

我创建了一个类的CGLib动态代理,但是当我试图访问原始类中声明的任何字段时,我获得了java.lang.NoSuchFieldException。我需要获取字段以更改其值

顺便说一下,这是代理所基于的类:

public class Person {

    private String name;
    ....
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    ...
}
这是引发上述异常的代码片段(在“MethodInterceptor”的“intercept”方法中)(更具体地说是第一行):

您知道访问所需字段或更改其值的其他方法吗

谢谢。

试试:

Field field = instance.getClass().getDeclaredField("name");
如中所述,仅适用于公共字段,但适用于整个类层次结构。您可以将其视为检查类的公共接口。适用于私有字段,不会检查类层次结构;您可以将其视为解决类的实现。

尝试:

Field field = instance.getClass().getDeclaredField("name");

如中所述,仅适用于公共字段,但适用于整个类层次结构。您可以将其视为检查类的公共接口。适用于私有字段,不会检查类层次结构;您可以将其视为解决类的实现。

显然,CGLib代理是原始类的子类。因此,以下代码运行良好:

Field field = instance.getClass().getSuperclass().getDeclaredField("name");

显然,CGLib代理是原始类的一个子类。因此,以下代码运行良好:

Field field = instance.getClass().getSuperclass().getDeclaredField("name");

尽管您已经找到了解决问题的方法,但以下是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。看看我的图书馆,以防你正在寻找替代品。但是请注意,我将在下周发布一个完全稳定的版本。当前的v0.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。看看我的图书馆,以防你正在寻找替代品。但是请注意,我将在下周发布一个完全稳定的版本。当前的v0.1版本包含一些不成熟的功能。

感谢您的提示。我按照您的建议更改为“getDeclaredField”,并获得了与CGLib相关的各种字段。但是问题仍然存在,因为返回的字段中没有一个是“name”字段。谢谢您的提示。我按照您的建议更改为“getDeclaredField”,并获得了与CGLib相关的各种字段。但是,问题仍然存在,因为返回的字段中没有一个是“name”字段。