Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

method annotations null when proxying via CGLIB

I'm experiencing a strange behaviour when looking via reflection for annotations on a method belonging to a class proxied via CGLIB. We use CGLIB in Spring, and if I annotate a method only with an annotation it works well (I'm able to retrieve the annotations via the getAnnotations() method on the correspondent Method object). If I annotate the method with 2 annotations instead (no matter the order of annotation), getAnnotations() just return null. Both annotation have RetentionPolicy.RUNTIME.

I read there are some issues with CGLIB, but it's strange that it simply works for one annotation and it returns null when I put 2 annotations.

Any suggestions?

(Using Spring 3.0.5 and CGLIB 2.2.2)

Adding code:

1st annotation is:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Produces {
    ResultType[] value();
}

2nd annotation is

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface JamonMonitored {
    String type() default "";
    String tag() default "";
}

And the block of code is for checking annotations is

Collection<Method> candidates = Collections2.filter(Arrays.asList(executorInstance.getClass().getMethods()), new Predicate<Method>() {
    @Override
    public boolean apply(Method input) {
        return input.getAnnotation(Produces.class) != null;
    }
});

if (candidates.isEmpty()) {
    // throws exception
}

If I annotate a method with both @Produces and @JamonMonitored, getAnnotation(Produces.class) is always null.

like image 659
manub Avatar asked Jan 23 '12 15:01

manub


2 Answers

Another option would be to specify @Inherited within the annotations definition. This would make the annotation appear even in the sub class generated by cglib. Of course in some scenarios you would not want your annotation to appear in "real" subclasses so this might not be an option for every scenario and the way to go is to use the Spring helpers as shown by skaffman

like image 97
bennidi Avatar answered Nov 15 '22 17:11

bennidi


CGLIB works by generating a subclass of the target object's class, and that subclass has generated methods that delegate to the target object. When you use reflection to query the proxy object's annotations, you're asking for annotations on the proxy class, not the target object's class.

Spring has to do a lot of annotation processing itself in order to navigate its way around proxies, superclasses, interfaces and so. The logic for doing this is encapsulated and exposed in the org.springframework.core.annotation.AnnotationUtils class. In your case, it sounds like you want the findAnnotation utility method, i.e.

@Override
public boolean apply(Method input) {
    return AnnotationUtils.findAnnotation(input, Produces.class) != null;
}
like image 43
skaffman Avatar answered Nov 15 '22 17:11

skaffman