【问题标题】:Custom made Java Annotation hidden by SpringSpring隐藏的定制Java注释
【发布时间】:2015-12-02 17:40:02
【问题描述】:

在使用 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 用代理包装了方法,这就是为什么我没有得到方法的注释,而是代理中的注释。我还没有找到任何解决这种情况的方法。

【问题讨论】:

  • Class 会返回什么 getClass?你列出了getDeclaredMethods返回的所有方法吗?
  • 我猜你说的是expert.getClass(),它会返回一个@Component,它应该继承自GenericExpert抽象类。我没有列出所有的方法,我只选择了我要找的一种。
  • 是的。打印出该类的完全限定名。不要猜测。这些都是你应该开始的调试步骤。
  • 类名:com.rcs.template.experts.SampleExpert$$EnhancerBySpringCGLIB$$d5843bae

标签: java spring reflection annotations


【解决方案1】:

我终于得到了我的问题的答案。我需要使用org.springframework.core.annotation.AnnotationUtils 实用程序类来检查注释是否存在,如下所示:

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

Spring 的AnnotationUtils.findAnnotation() 方法正确地克服了CGLIB 引入的问题。

【讨论】:

    【解决方案2】:

    问题在于 Spring 会为您的对象创建代理,所以当您这样做时

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

    您实际上得到的是代理对象,而不是您所期望的 SampleExpert。

    将@Inherited 注释添加到您的RestMethod 注释中。默认情况下,即使是常规子类也不会继承注解,更不用说代理了。

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

    如果这不起作用,请确保使用 CGLIB 代理(它们可能是因为您将它与非接口类一起使用)。

    【讨论】:

    • 是的,CGLIB 是导致问题的原因......但我不知道如何将这些方法级别的注释继承到代理,正如 Sotirios 所说,@Inherited 仅适用于类。
    猜你喜欢
    • 2019-02-22
    • 2012-11-06
    • 1970-01-01
    • 2019-12-29
    • 2012-03-04
    • 2018-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多