如何在代理类上获取方法注释? [英] How to get method annotations on a proxied class?
问题描述
我在读取代理类的方法的注释时遇到问题.
I have a problem while reading annotations off methods of a proxied class.
有一个接口、一个对象和一个方法的注解,这部分很简单:
There is an interface, an object and an annotation on a method, this part is really simple:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface A {
}
interface I {
void method();
}
class Test implements I {
@A
public void method() { }
}
接下来,有一个 InvocationHandler
什么都不做,只是简单地调用传递参数的方法:
Next, there is an InvocationHandler
that does nothing, just simply calls the method with the arguments passed:
class DefaultInvocationHandler implements InvocationHandler {
@Override
public Object invoke(final Object o, final Method method, final Object[] args) throws Throwable {
return method.invoke(o, args);
}
}
还有一个 main
方法,用于打印 Test
实例及其代理副本的声明方法:
And there is a main
method that prints declared methods of a Test
instance and its proxied counterpart:
class Main {
public static void main(String[] args) {
Object test = new Test();
printMethods(test); // Outputs that `I#method` has `A` annotation
System.out.println();
Object proxied = Proxy.newProxyInstance(test.getClass().getClassLoader(), test.getClass().getInterfaces(), new DefaultInvocationHandler());
printMethods(proxied); // Outputs that `I#method` does not have `A` annotation
}
static void printMethods(Object obj) {
Arrays.stream(obj.getClass().getDeclaredMethods())
.forEach(method -> System.out.println(method.toString() + " has A annotation: " + method.isAnnotationPresent(A.class)));
}
}
问题来了:局部变量test
是Test
类的一个实例,而局部变量proxied
实际上是一个>Proxy
,所以它的方法没有任何注释.这是程序的输出:
And here comes the problem: local variable test
has is an instance of Test
class, and local variable proxied
is actually a Proxy
, so it does not have any annotations on its methods. Here's the output of the program:
public void Test.method() has A annotation: true // <- good thing
public final boolean $Proxy2.equals(java.lang.Object) has A annotation: false
public final java.lang.String $Proxy2.toString() has A annotation: false
public final void $Proxy2.method() has A annotation: false // <- bad thing
public final int $Proxy2.hashCode() has A annotation: false
我已经尝试寻找解决方案,但是这个问题 是关于从注释中提取注释(我认为),这个 太关于注解类了.其中一些是关于其他代理实现的.
I've tried searching for the solution, but this question is about extracting annotations off an annotation (I presume), this one is too about annotation class. Some of them are about other proxy implementations.
➥ 那么,有没有办法从代理对象中获取实际注释,或者公开隐藏在代理下的类(不过我想要前者)?
➥ So, is there any way to get actual annotations off a proxied object, or to expose the class that is hidden under the proxy (I want the former one, though)?
推荐答案
那么,有没有办法从代理对象中获取实际注释,或者公开隐藏在代理下的类(我想要不过是前一个)?
So, is there any way to get actual annotations off a proxied object, or to expose the class that is hidden under the proxy (I want the former one, though)?
不是直接的,不是.
Proxy
设计背后的想法是实际包装的实例(如果有的话)将隐藏在调用处理程序后面.您可以从 newProxyInstance
方法中看到这一点:没有对任何地方传递的 test
实例的引用.Proxy
实例不知道您的 Test
实例.
The idea behind Proxy
's design is that the actual wrapped instance (if there even is one) would be hidden behind the invocation handler. You can see this from the newProxyInstance
method: there's no reference to the test
instance passed anywhere. The Proxy
instance has no knowledge of your Test
instance.
一个常见的模式是使用一个公共的 InvocationHandler
子类,该子类保留对包装实例的引用并可以将其返回给您,您可以使用它来执行检查.例如,
A common pattern is to use a common InvocationHandler
subclass that keeps a reference to a wrapped instance and can return it to you and you can use that to perform your checks. For example,
abstract class InvocationHandlerWithTarget implements InvocationHandler {
protected final Object target;
public InvocationHandlerWithTarget(Object target) {
this.target = target;
}
public Object getTarget() {
return target;
}
}
class DefaultInvocationHandler extends InvocationHandlerWithTarget {
public DefaultInvocationHandler(Object target) {
super(target);
}
@Override
public Object invoke(final Object o, final Method method, final Object[] args) throws Throwable {
return method.invoke(target, args);
}
}
然后检查您是否正在使用 Proxy
以及它的 InvocationHandler
是否符合您的预期
and then check if you're working with a Proxy
and whether its InvocationHandler
is what you expect
Object proxied = Proxy.newProxyInstance(test.getClass().getClassLoader(), test.getClass().getInterfaces(),
new DefaultInvocationHandler(test));
[...]
if (Proxy.isProxyClass(proxied.getClass())) {
var handler = Proxy.getInvocationHandler(proxied);
if (handler instanceof InvocationHandlerWithTarget) {
var handlerWithTarget = (InvocationHandlerWithTarget) handler;
// now process the target
handlerWithTarget.getTarget();
}
}
然后你就有了一个具体的实例来反思(或者你需要做的任何其他处理).
You then have a concrete instance with which to reflect on (or whatever other processing you need to do).
这篇关于如何在代理类上获取方法注释?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!