在使用Spring和Jersey的REST服务的上下文中,我创建了一个自定义注释,以便在运行时在方法级别上使用。然后我用它注释了一个方法,并通过反射,试图获得该方法的所有注释,但我总是得到零个注释。
自定义注释如下:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RestMethod {
}
然后,方法注释:
@Service
public class SampleExpert extends GenericExpert {
...
@RestMethod
public PaginationDTO<SampleDTO> list(SamplePaginationFiltersDTO filters) {
...
}
}
最重要的部分是,试图获得方法list()的所有注释的代码部分,该方法得到一个零元素数组:
@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;
}
}
...
}
在这里,logger.info("注释数:"+…)总是打印:
18:31:31,837 INFO [http-apr-8080-exec-7][RestResponder:60] Number of annotations: 0
但是,如果我执行以下操作:
Method m = SampleExpert.class.getMethod("list", SamplePaginationFiltersDTO.class);
logger.info("Number of annotations: " + m.getAnnotations().length);
我得到了适当数量的注释(在本例中为1)。
我猜Spring正在用代理封装方法,这就是为什么我没有得到方法的注释,而是得到代理中的注释。我一直没能找到解决这种情况的办法。
我终于找到了问题的答案。我需要使用org.springframework.core.annotation.AnnotationUtils
实用程序类来检查注释是否存在,如下所示:
AnnotationUtils.findAnnotation(m, RestMethod.class) != null
Spring的AnnotationUtils.findAnnotation()
方法正确地克服了CGLIB引入的问题。
问题是Spring为您的对象创建代理,所以当您执行时
(GenericExpert) ctx.getBean(expertName + "Expert");
实际上,您得到的是代理对象,而不是预期的SampleExpert
。
将@Inherited
注释添加到RestMethod
注释中。默认情况下,注释甚至不会被常规子类继承,更不用说代理了。
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface RestMethod {
}
如果这不起作用,请确保使用CGLIB
代理(它们可能是因为您将其与非接口类一起使用)。