【问题标题】:REST with Spring and Jackson full data bindingREST 与 Spring 和 Jackson 完整数据绑定
【发布时间】:2011-05-25 09:39:09
【问题描述】:

我正在使用 Spring MVC 来处理 JSON POST 请求。在幕后,我使用的是基于 Jackson JSON 处理器构建的 MappingJacksonHttpMessageConverter,并在您使用 mvc:annotation-driven 时启用。

我的一个服务收到一个操作列表:

@RequestMapping(value="/executeActions", method=RequestMethod.POST)
    public @ResponseBody String executeActions(@RequestBody List<ActionImpl> actions) {
        logger.info("executeActions");
        return "ACK";
    }

我发现 Jackson 将 requestBody 映射到 java.util.LinkedHashMap 项目列表(简单数据绑定)。相反,我希望将请求绑定到类型化对象的列表(在本例中为“ActionImpl”)。

我知道如果您直接使用 Jackson 的 ObjectMapper,这很容易做到:

List<ActionImpl> result = mapper.readValue(src, new TypeReference<List<ActionImpl>>() { }); 

但我想知道在使用 Spring MVC 和 MappingJacksonHttpMessageConverter 时实现这一目标的最佳方法是什么。有什么提示吗?

谢谢

【问题讨论】:

    标签: json spring rest spring-mvc jackson


    【解决方案1】:

    供您参考,该功能将在 Spring 3.2 中提供(请参阅https://jira.springsource.org/browse/SPR-9570

    我刚刚在当前的 M2 上对其进行了测试,它就像一个开箱即用的魅力(无需提供额外的注释来提供参数化类型,它将由新的 MessageConverter 自动解析)

    【讨论】:

      【解决方案2】:

      我发现您还可以通过使用数组作为@RequestBody 而不是集合来解决类型擦除问题。例如,以下将起作用:

      public @ResponseBody String executeActions(@RequestBody ActionImpl[] actions) { //... }
      

      【讨论】:

      • 我遇到了类似的问题,试过了,它可以工作。然而,通过更新到 3.1.1.Release,即使 List 也可以工作......
      • 行为是任意的..仍然很困惑
      【解决方案3】:

      这个问题已经很老了,但我想我还是可以贡献一点。

      就像 StaxMan 指出的那样,这是由于类型擦除造成的。这绝对应该是可能的,因为您可以通过方法定义中的反射获得通用参数。但是,问题在于HttpMessageConverter的API:

      T read(Class<? extends T> clazz, HttpInputMessage inputMessage);
      

      这里,只有 List.class 会被传递给方法。所以,如你所见,不可能实现一个通过查看方法参数类型来计算真实类型的 HttpMessageConverter,因为那是不可用的。

      尽管如此,您可以编写自己的解决方法 - 您只是不会使用 HttpMessageConverter。 Spring MVC 允许您编写自己的WebArgumentResolver,在标准解析方法之前启动。例如,您可以使用自己的自定义注释 (@JsonRequestBody?),它直接使用 ObjectMapper 来解析您的值。您将能够从方法中提供参数类型:

      final Type parameterType= method.getParameterTypes()[index];
      List<ActionImpl> result = mapper.readValue(src, new TypeReference<Object>>() {
          @Override
          public Type getType() {
              return parameterType;
          }
      });
      

      我认为 TypeReference 的使用方式并非如此,但 ObjectMapper 没有提供更合适的方法。

      【讨论】:

        【解决方案4】:

        我怀疑问题是由于类型擦除造成的,即没有传递泛型参数类型,可能只传递了 actions.getClass();这将给出相当于 List.

        的类型

        如果这是真的,一种可能性是使用中间子类,例如:

        public class ActionImplList extends ArrayList<ActionImpl> { }
        

        因为即使只传递了类,这也会保留类型信息。 那么:

        public @ResponseBody String executeActions(@RequestBody ActionImplList actions)
        

        会成功的。不是最佳的,但应该可以工作。

        我希望有更多 Spring MVC 知识的人可以阐明为什么没有传递参数类型(也许这是一个错误?),但至少有一个解决方法。

        【讨论】:

        【解决方案5】:

        您是否尝试过将方法声明为:

        executeActions(@RequestBody TypeReference<List<ActionImpl>> actions)
        

        我没有尝试过,但根据你的问题,这是我尝试的第一件事。

        【讨论】:

        • 很好,但它不起作用。 Jackson 尝试将接收到的 List 反序列化为 TypeReference 的实例,这会产生 JsonMappingException。
        猜你喜欢
        • 1970-01-01
        • 2011-08-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-27
        • 2018-06-04
        • 2019-06-16
        • 1970-01-01
        相关资源
        最近更新 更多