40

我正在使用 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";
    }

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

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

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

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

谢谢

4

5 回答 5

43

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

public @ResponseBody String executeActions(@RequestBody ActionImpl[] actions) { //... }
于 2012-05-10T00:37:56.170 回答
28

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

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

public class ActionImplList extends ArrayList<ActionImpl> { }

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

public @ResponseBody String executeActions(@RequestBody ActionImplList actions)

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

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

于 2010-12-19T18:59:54.017 回答
9

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

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

于 2012-09-26T09:12:10.393 回答
2

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

就像 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 没有提供更合适的方法。

于 2011-12-17T10:29:48.933 回答
0

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

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

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

于 2010-12-15T19:43:00.473 回答