2012-09-25 2 views
1

저는 리플렉션 프록시를 사용하여 공용 API에 대한 추가 검사를 수행하고 있습니다. 본질적으로 나는 호출자가 자신의 손을 잡는 모든 객체가 실제 객체의 프록시가되도록 모든 객체를 다시 감싸고 싶습니다.ParametrizedType/TypeVariable을 클래스의 ParametrizedType을 알고있을 때 어떻게 해결할 수 있습니까?

자바는 여전히 전체 지우기 문제가 있으므로 래핑 된 객체의 유형을 전달합니다. API에 대한 입력이 하나의 비 제네릭 인터페이스이기 때문에 모든 유형이 무엇인지 알아야합니다.

public class ProxyInvocationHandler implements InvocationHandler { 
    private final Object delegate; 
    private final Type delegateType; 

    public ProxyInvocationHandler(Object delegate, Type delegateType) { 
     this.delegate = delegate; 
     this.delegateType = delegateType; 
    } 

    @Override 
    public Object invoke(Object proxy, Method method, Object[] args) { 
     // Omitted: additional checks performed here. 

     Object result = method.invoke(delegate, args); 

     Type returnType = method.getGenericReturnType(); 

     // e.g. if delegateType is List<Cat> and the method is the get method, 
     // returnType would be E but resultType should be Cat. 
     Type resultType = ??? 

     // Utility method I will omit, it just creates another proxy instance 
     // using its own invocation handler. 
     return ProxyUtils.wrap(result, resultType); 
    } 
} 

나는 유형/ParametrizedType API를 둘러 보았다하고 delegateTypereturnType이를 계산하기에 충분한 정보이어야한다하더라도, resultType을 얻을 수있는 방법을 찾을 수 없습니다.

이렇게하는 "적절한"방법은 무엇입니까?

+0

"resultType"과 "returnType"의 차이점은 무엇입니까? – jtahlborn

+0

resultType은 결과의 실제 유형입니다. returnType은 메소드 서명에 의해 선언 된 리턴 유형입니다. 예 : delegateType가 List 이고 메서드가 get 메서드 인 경우 returnType은 E이지만 resultType은 Cat이됩니다. – Trejkaz

답변

1

Java ClassMate을 사용할 수 있습니다. 당신은 타입 토큰 com.fasterxml.classmate.GenericType를 사용해야합니다 :

GenericType<?> delegateType = new GenericType<List<Cat>>() {}; 

참고 "Super-type Token" pattern라고 빈 {}합니다.

TypeResolver typeResolver = new TypeResolver(); 
MemberResolver memberResolver = new MemberResolver(

ResolvedType type = typeResolver.resolve(delegateType); 
ResolvedTypeWithMembers members = memberResolver.resolve(type, null, null); 
ResolvedMethod[] methods = members.getMemberMethods(); 

캐시 Map의 결과 :

Method method = List.class.getMethod("get", int.class); 
ResolvedType resultType = resolved.get(method).getReturnType(); 
System.out.println("resultType = " + resultType);    // prints resultType = Cat 
: 당신이 즉 List delegateType 선언하는 방법을 때 이제

Map<Method, ResolvedMethod> resolved = new HashMap<>(); 
for (ResolvedMethod method: methods) { 
    resolved.put(method.getRawMember(), method); 
} 

, 당신은 해결 반환 유형을 얻을 수 있습니다

+1

도서관이 개입 될 우려가 있습니다. 구아바도이 줄을 따라 뭔가를 가지고 있다고 생각합니다. 그렇지 않다면 FasterXML을 사용합니다. 좋은 물건을 만드는 경향이 있습니다. :) – Trejkaz

+0

@Trejkaz 당신이 여기에서 무엇이든 찾으세요? 좀 더 우아한 라이브러리에 동일한 기능이 있는지 알고 싶습니다. – Saintali

+0

완료. 대체 답변으로 게시 됨 정말 간단하지만 GenericType 대신 TypeToken입니다. Guava가 TypeToken 자체에 직접 넣는 대신 ClassMate가 별도의 유틸리티로 분리기를 구분하기 때문에 코드 몇 줄을 피할 수 있습니다. – Trejkaz

1

앞으로 올 사람들을위한 구아바 방식입니다.

... 
Type returnType = method.getGenericReturnType(); 
TypeToken<?> resultType = TypeToken.of(delegateType).resolveType(returnType); 

좀 더 쉽게하기 위해 delegateType 유형을 TypeToken<?>으로 변경했습니다. 물론 성능을 현저한 속도로 낮추기 위해 캐싱 (LoadingCache 사용)을 추가했습니다. 그들의 해법 코드는 같은 일을 한 초기 해킹 - 업 코드보다 느렸다. 차이점은 이제 내가 올바르게 수행되고 있다는 확신을 갖게된다는 것입니다.

+0

아주 좋네요. 구아바로 전환해야 할 수도 있습니다 :) – Saintali

관련 문제