0

I'm trying to find methods in a Spring RestController that are annotated with a given annotation. In order to see what annotations exist on methods for that RestController, I've done the following:

Map<String, Object> beans = appContext.getBeansWithAnnotation(RestController.class);
for (Map.Entry<String, Object> entry : beans.entrySet()) {
    Method[] allMethods = entry.getValue().getClass().getDeclaredMethods();
    for(Method method : allMethods) {
        LOG.debug("Method: " + method.getName());
        Annotation[] annotations = method.getDeclaredAnnotations();
        for(Annotation annotation : annotations) {
            LOG.debug("Annotation: " + annotation);
        }
    }
}

The problem is that I'm not seeing any annotations at all, despite the fact that I know I have at least one that is annotated with @Retention(RetentionPolicy.RUNTIME). Any ideas? Is CGLIB a factor here? (Being a Controller, the methods in question are bieing proxied using CGBLIB).

GordyB
  • 179
  • 4
  • 14
  • please add annotation interface code aswell – Sagar Kharab Jun 05 '18 at 08:09
  • The annotation in question is the Spring @PreAuthorize annotation. – GordyB Jun 05 '18 at 08:12
  • 1
    Use the Spring `AnnotationUtils` or at least the `AopUtils` to get the actual class. You get a proxy, and as annotations aren't inherted you won't see them. Also why do you need this? – M. Deinum Jun 05 '18 at 08:30
  • Thank you @M.Deinum, that's great. The requirement relates to documenting the authorisations. If you submit an answer I'll mark it as correct. – GordyB Jun 05 '18 at 08:41

1 Answers1

2

Due to the @PreAuthorize annotation you don't get the actual class but a proxied instance of that class. As annotations aren't inherited (by design in the language) you won't see them.

I suggest to do 2 things, first use the AopProxyUtils.ultimateTargetClass to get the actual class of the bean and second use the AnnotationUtils to get the annotation from the class.

Map<String, Object> beans = appContext.getBeansWithAnnotation(RestController.class);
for (Map.Entry<String, Object> entry : beans.entrySet()) {
    Class clazz = AopProxyUtils. AopProxyUtils.ultimateTargetClass(entry.getValue());
    ReflectionUtils.doWithMethods(clazz, new MethodCallback() {
        public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
            Annotation[] annotations = AnnotationUtils.getAnnotations(method);
            for(Annotation annotation : annotations) {
                LOG.debug("Annotation: " + annotation);
            }
        }
    });
}

Something like that should do the trick, also some cleanup using the Spring provided utility classes.

M. Deinum
  • 115,695
  • 22
  • 220
  • 224