jeudi 7 novembre 2019

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

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

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

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)?





Aucun commentaire:

Enregistrer un commentaire