2014-06-13 2 views
2

클래스의 CGLib 동적 프록시를 만들었지 만 원래 클래스에서 선언 된 필드에 액세스하려고하면 java.lang.NoSuchFieldException을 얻습니다. 나는 그 가치를 바꾸기 위해서 현장을 얻을 필요가있다. 그런데 CGLib 프록시 필드 값을 변경하려고 시도하는 예외

, 이것은 프록시에 기초 클래스이다

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"); 
.... 

필요한 필드에 액세스하거나 값을 변경하는 다른 방법을 알고 있습니까?

감사합니다.

답변

2

분명히 CGLib 프록시는 원래 클래스의 서브 클래스입니다. 그래서, 다음의 코드가 잘 작동 : 이미 문제를 해결하는 방법을 알아 냈 비록

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

시도 :

this SO answer에서 언급 한 바와 같이
Field field = instance.getClass().getDeclaredField("name"); 

, getField는 공공 분야에 대한 작동하지만, 전체 클래스 계층 구조에 적용됩니다. 당신은 클래스의 공용 인터페이스를 검사하는 것으로 생각할 수 있습니다. getDeclaredField은 개인 필드에 대해 작동하며 클래스 계층을 검사하지 않습니다. 당신은 그것을 클래스의 구현을 해결하는 것으로 생각할 수 있습니다.

+0

힌트 감사합니다. 내가 제안한대로 "getDeclaredField"를 변경했으며 CGLib와 관련된 다양한 필드를 얻었습니다. 그러나 반환 된 필드 중 "name"필드가 없으므로 문제가 여전히 지속됩니다. –

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을 사용하여 호출 할 수 있습니다. 차단으로 인해 getMethod 또는 getDeclaredMethod을 호출하면 cglib를 사용할 때 예상대로 작동합니다. 그러나 필드는 상속되지 않으므로 클래스 계층 구조를 한 클래스 위로 찾아야합니다. 그 이유는 다음과 같습니다.

instance.getClass().getSuperclass().getDeclaredField("name"); 

작품입니다. cglib는 더 이상 유지되지 않습니다. 다른 도서관을 찾고있는 경우 내 도서관 Byte Buddy을보십시오. 그러나 다음 주 언젠가 완전히 안정적인 버전을 발표 할 예정입니다. 현재 v0.1 릴리스에는 일부 조기 기능이 포함되어 있습니다.

관련 문제