【问题标题】:RequestMapping annotation leads to empty RequestMethod array when looking up annotation for the controller method查找控制器方法的注释时,RequestMapping 注释导致空的 RequestMethod 数组
【发布时间】:2012-04-24 14:31:26
【问题描述】:

我们正在构建某种自动自我描述 REST 服务(实时文档生成)。为此,我们有一个控制器方法,它查找所有控制器 bean 并获取请求映射信息以将它们显示在一个友好的 html 页面中。

为此,我们使用 MetadataReader(通过 CachingMetadataReaderFactory 创建)来获取类的元数据。 当我们获取公共方法的 MethodMetaData 时,我们发现 RequestMapping 注释以及生产和值参数,但方法字段始终是一个空数组,尽管我们在源代码中配置了它并且映射工作。所以信息应该在某个地方。这相当令人费解! :-)

编辑:方法字段为空=> RequestMapping 注释有一个方法字段,它是一个 RequestMethod 对象的数组。如果您尝试从 MethodMetaData 实例中读取它,则它是一个空数组。示例:metadata.getAnnotationAttributes(RequestMapping.class.getName()).get("method")

我尝试在spring框架源码中查找原因,但目前还没有找到原因……

有什么想法吗?

仅供参考:我们使用的是 Spring 3.1

【问题讨论】:

  • 但是方法字段总是空的??描述
  • 请看编辑部分
  • 我不知道您的 MetadataReader 的工作(编码),检查是否有任何其他方式来检索对象信息,因为 @RequestMapping 注释中的方法属性类型是 RequestMethod 数组。即 RequestMethod[]
  • 我已经澄清了。当然它是一个空数组而不是一个空变量。我的错。 MetadataReader 是一个弹簧类。

标签: java spring reflection spring-mvc annotations


【解决方案1】:

出于自己的好奇心,我创建了一个小示例项目,并对 Spring 提供的 MetadataReader 进行了一些操作。对于演示,我创建了一个非常简单的控制器,如下所示:

@Controller
public class SomeAnnotatedController {

   @RequestMapping(method = {RequestMethod.GET}, value = "/someUrl")
   public void someMethod() {
       // do something later
   }

}

我无法使用 Spring MetadataReader 从注释中提取正确的信息。

@Test
public void shouldReturnMethodArrayWithSpringMetadataReader() throws Exception {
    MetadataReader metadataReader = new CachingMetadataReaderFactory().getMetadataReader(SomeAnnotatedController.class.getName());
    Set<MethodMetadata> annotatedMethods = metadataReader.getAnnotationMetadata().getAnnotatedMethods(RequestMapping.class.getName());
    assertEquals(1, annotatedMethods.size());
    MethodMetadata methodMetadata = annotatedMethods.iterator().next();
    assertEquals("someMethod", methodMetadata.getMethodName());
    Map<String, Object> annotationAttributes = methodMetadata.getAnnotationAttributes(RequestMapping.class.getName());
    assertTrue(annotationAttributes.containsKey("method"));
    RequestMethod[] methodAttribute = (RequestMethod[]) annotationAttributes.get("method");
    assertEquals(1, methodAttribute.length);
}

在最后一行运行此测试失败,并告诉您这是一个空数组...

java.lang.AssertionError: 
Expected :1
Actual   :0

用原生 Java 做同样的事情感觉更容易一些,并返回正确的信息。

@Test
public void shouldReturnMethodArrayWithPlainJava() throws Exception {
    Method method = SomeAnnotatedController.class.getDeclaredMethod("someMethod");
    RequestMapping annotation = method.getAnnotation(RequestMapping.class);
    assertEquals(1, annotation.method().length);
    assertEquals(RequestMethod.GET, annotation.method()[0]);
}

很遗憾地告诉您,我没有找到问题的解决方案,但示例项目或基于纯 java 的文档替代方案可能会有所帮助。

【讨论】:

    【解决方案2】:

    这不是您所要求的直接答案,但它是一种非常好的方法来对 REST API 进行自我记录。使用 Rossen Stoyanchev 在他的 github 位置描述的端点文档控制器:https://github.com/rstoyanchev/spring-mvc-31-demo.git

    总而言之,您的控制器看起来像这样:

    @Controller
    public class EndpointDocController {
    
        private final RequestMappingHandlerMapping handlerMapping;
    
        @Autowired
        public EndpointDocController(RequestMappingHandlerMapping handlerMapping) {
            this.handlerMapping = handlerMapping;
        }
    
        @RequestMapping(value="/endpointdoc", method=RequestMethod.GET)
        public void show(Model model) {
            model.addAttribute("handlerMethods", this.handlerMapping.getHandlerMethods());
        }
    
    }
    

    你的jsp会以这种方式引用方法、生产、消费、方法签名的属性,假设hm是一个处理方法:

    Patterns:${hm.key.patternsCondition.patterns}
    Method: ${hm.key.methodsCondition.methods}
    Method signature: ${hm.value}
    Consumes: ${hm.key.consumesCondition.expressions}
    Produces: ${hm.key.producesCondition.expressions}
    

    【讨论】:

    • 看起来几乎像我需要的一样 - 如果我问你在哪里实例化 RequestMappingHandlerMapping,你介意吗?我看到的所有示例都只是使用默认构造函数实例化它,但它随后返回并清空处理程序方法的映射:(
    猜你喜欢
    • 2013-03-30
    • 1970-01-01
    • 2012-02-27
    • 1970-01-01
    • 1970-01-01
    • 2014-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多