简体   繁体   中英

Custom made Java Annotation hidden by Spring

In the context of a REST service that is using Spring and Jersey, I have created a custom annotation to use on the method level at run time. Then I have annotated a method with it and through reflection, tried to get all the annotations of that method, but I always get zero annotations.

The custom annotation is this:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RestMethod {
}

Then, the method annotated:

@Service
public class SampleExpert extends GenericExpert {
...

    @RestMethod
    public PaginationDTO<SampleDTO> list(SamplePaginationFiltersDTO filters) {
    ...
    }
}

And the most important part, the portion of code trying to get all the annotations of the method list() which gets an array of zero elements:

@POST
@Path("/{expert}/{method}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response post(@PathParam("expert") String expertName, @PathParam("method") String methodName, @Context HttpServletRequest request, String data) {
    try {
        logger.debug("Invoking {}.{}()", WordUtils.capitalize(expertName) + "Expert", methodName);

        // Get Bean and Method.
        WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
        GenericExpert expert = (GenericExpert) ctx.getBean(expertName + "Expert");
        Method method = null;
        for (Method m : expert.getClass().getDeclaredMethods()) {
            if (m.getName().equals(methodName)) {
                logger.info("Number of annotations: " + m.getAnnotations().length);
                method = m;
                break;
            }
        }
    ...
}

Here, logger.info("Number of annotations: " + ...) always prints:

18:31:31,837 INFO  [http-apr-8080-exec-7][RestResponder:60] Number of annotations: 0

However, if I do the following:

Method m = SampleExpert.class.getMethod("list", SamplePaginationFiltersDTO.class);
logger.info("Number of annotations: " + m.getAnnotations().length);

I get the proper number of annotations (1, in this case).

I guess that Spring is wrapping the method with a proxy and that's why I don't get the annotations of the method but the ones in the proxy. I haven't been able to find any solution to this situation.

I've finally got the answer to my question. I need to use org.springframework.core.annotation.AnnotationUtils utility class to check if the annotation is present, like this:

AnnotationUtils.findAnnotation(m, RestMethod.class) != null

The Spring's AnnotationUtils.findAnnotation() method correctly overcomes the problem introduced by CGLIB.

The problem is that Spring creates proxies for your objects, so when you do

(GenericExpert) ctx.getBean(expertName + "Expert");

You are actually getting proxy object instead of SampleExpert that you're expecting.

Add @Inherited annotation to your RestMethod annotation. Annotations are not inherited by default even by regular subclasses, much less proxies.

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface RestMethod {
}

If that doesn't work make sure CGLIB proxies are used (they probably are since you are using it with non-interface class).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM