REST与Spring和Jackson完全数据绑定

我正在使用Spring MVC来处理JSON POST请求。 在封面下面,我使用了构build在Jackson JSON处理器上的MappingJacksonHttpMessageConverter,并在使用mvc:annotation驱动时启用。

我的一项服务收到一个行动清单:

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

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

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

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

但是我想知道当使用Spring MVC和MappingJacksonHttpMessageConverter时,最好的方法是什么。 任何提示?

谢谢

我怀疑问题是由于types擦除,即而不是传递generics参数types,也许只有actions.getClass()传递; 这会给types相当于List <?>。

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

 public class ActionImplList extends ArrayList<ActionImpl> { } 

因为即使只有类被传递,这也将保留types信息。 那么:

 public @ResponseBody String executeActions(@RequestBody ActionImplList actions) 

会做的伎俩。 不是最优的,但应该工作。

我希望有更多的Spring MVC知识的人可以阐明为什么参数types不被传递(也许是一个bug),但至less有一个解决方法。

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

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

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

我只是在当前的M2上进行了testing,它就像一个开箱即用的魅力(不需要提供额外的注释来提供参数化types,它将由新的MessageConverter自动parsing)

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

像StaxMan指出的,这是由于types擦除。 这绝对应该是可能的,因为你可以通过方法定义的reflection获得generics参数。 但是,问题是HttpMessageConverter的API:

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

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

不过,可以编写自己的解决方法 – 你只是不会使用HttpMessageConverter。 Spring MVC允许你编写自己的WebArgumentResolver ,它们在标准parsing方法之前开始。 例如,你可以使用自己的自定义注释(@JsonRequestBody?)直接使用ObjectMapper来parsing你的值。 您将能够从方法提供参数types:

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

TypeReference并不是我想要的,但是ObjectMapper并没有提供更合适的方法。

你有没有试过声明这个方法:

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

我还没有尝试过,但基于你的问题,这是我尝试的第一件事。