如何在代理类上获取方法注释?

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

在方法上有一个接口,一个对象和一个注释,这部分非常简单:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface A {
}

interface I {
    void method();
}

class Test implements I {
    @A
    public void method() { }
}

接下来,有一个invocationHandler什么也不做,只是简单地调用带有传递参数的方法:

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实例及其代理对应对象的声明方法:

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,所以它没有其方法上的任何注释。这是程序的输出:

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

我尝试搜索解决方案,但是this question涉及从注释中提取注释(我想),this one也是关于注释类的。 Some of them与其他代理实现有关。

➥那么,是否有任何方法可以从代理对象中获取实际的注释,或者公开隐藏在代理下的类(不过,我想要前一个)?

gouridetongxingzheng 回答:如何在代理类上获取方法注释?

  

因此,有什么方法可以从代理对象中获得实际的注释,   或公开隐藏在代理下的类(我希望   是前一个)?

不直接,不。

Proxy设计背后的想法是,实际的包装实例(如果有,甚至是一个实例)将被隐藏在调用处理程序的后面。您可以从newProxyInstance方法中看到这一点:没有引用传递到任何地方的test实例。 Proxy实例不了解您的Test实例。

常见的模式是使用公共的InvocationHandler子类,该子类保留对包装实例的引用,并将其返回给您,您可以使用该子类执行检查。例如,

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是否符合您的期望

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

然后您将具有一个具体的实例来进行反思(或您需要执行的其他任何处理)。

本文链接:https://www.f2er.com/3144140.html

大家都在问