REST与Spring和Jackson完全数据绑定

时间:2010-12-14 16:33:41

标签: json spring rest spring-mvc jackson

我正在使用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时实现这一目标的最佳方法是什么。任何提示?

由于

5 个答案:

答案 0 :(得分:42)

我发现你也可以通过使用数组作为@RequestBody而不是集合来解决类型擦除问题。例如,以下内容可行:

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

答案 1 :(得分:27)

我怀疑问题是由于类型擦除,即不是传递泛型参数类型,也许只传递actions.getClass();这将给出类似于List&lt;的类型。 ?&GT;

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

public class ActionImplList extends ArrayList<ActionImpl> { }

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

public @ResponseBody String executeActions(@RequestBody ActionImplList actions)

会做到这一点。不是最佳的,但应该有效。

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

答案 2 :(得分:8)

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

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

答案 3 :(得分:2)

这个问题已经过时了,但我认为无论如何我都可以做出贡献。

像PaxMan指出的那样,这是由于类型擦除。肯定应该是可能的,因为可以通过方法定义中的反射来获取泛型参数。但是,问题是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 :(得分:0)

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

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

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