如何在代理类上获取方法注释? [英] How to get method annotations on a proxied class?

查看:51
本文介绍了如何在代理类上获取方法注释?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在读取代理类的方法的注释时遇到问题.

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)));
    }
}

问题来了:局部变量testTest类的一个实例,而局部变量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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆