2012-09-25 22 views
1

我正在使用反射代理在公共API上執行其他檢查。基本上我想包裝從它回來的每個對象,以便調用者獲得它們的任何對象都是真實對象的代理。當我知道它所在的類的ParametrizedType時,如何解析ParametrizedType/TypeVariable?

Java仍然有整個擦除問題,所以我傳遞包裝對象的類型。我應該知道一切是什麼類型,因爲進入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似乎並不能找到一個辦法讓resultType,即使delegateTypereturnType應該是足夠的信息來計算此。

什麼是「正確」的方式來做到這一點?

+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

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

現在,當你有即ListdelegateType聲明的方法,你可以得到它的解決返回類型:

Method method = List.class.getMethod("get", int.class); 
ResolvedType resultType = resolved.get(method).getReturnType(); 
System.out.println("resultType = " + resultType);    // prints resultType = Cat 
+1

我擔心圖書館可能會涉及。我認爲Guava也有這方面的一些東西。如果沒有,我會使用FasterXML的 - 他們傾向於做出好東西。 :) – Trejkaz

+0

@Trejkaz你可以請發佈任何你在這裏找到?我想知道更優雅的庫是否具有相同的功能。 – Saintali

+0

完成。作爲替代答案發布。它非常簡單,但不是GenericType而是TypeToken,我可能會避免使用幾行代碼,因爲ClassMate會將解析器分離爲單獨的實用程序,而Guava將它直接放到TypeToken本身上。 – Trejkaz

1

以下是番石榴的方式,適合未來的人:

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

我將delegateType的類型更改爲TypeToken<?>以使事情變得更容易一些。當然,我添加了相當多的緩存(使用LoadingCache)以使性能降至明智的速度。他們的解析代碼比我最初做的同樣的代碼慢。不同的是,我現在有信心它正在正確地完成。

+0

非常好。我可能需要自己切換到番石榴:) – Saintali

相關問題