我正在使用反射代理来执行对公共API的额外检查。基本上我想要包装从它返回的每个对象,以便调用者获取的任何对象都是真实对象的代理。
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);
}
}
我查看了Type / ParametrizedType API,似乎找不到获取resultType
的方法,即使delegateType
和returnType
应该有足够的信息来计算它。
这样做的“正确”方法是什么?
答案 0 :(得分: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);
}
现在,当您拥有delegateType
声明的方法,即List
时,您可以获得已解决的返回类型:
Method method = List.class.getMethod("get", int.class);
ResolvedType resultType = resolved.get(method).getReturnType();
System.out.println("resultType = " + resultType); // prints resultType = Cat
答案 1 :(得分:1)
对于将来过来的人来说,这是番石榴的方式:
...
Type returnType = method.getGenericReturnType();
TypeToken<?> resultType = TypeToken.of(delegateType).resolveType(returnType);
我将delegateType的类型更改为TypeToken<?>
以使事情变得更容易一些。当然,我添加了相当多的缓存(使用LoadingCache
)以将性能降低到合理的速度。他们的解析代码比我最初的hacking-up代码慢,它执行相同的操作。不同的是,我现在有信心正确地完成它。