json REST 与 Spring 和 Jackson 完整数据绑定

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4441557/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 17:41:31  来源:igfitidea点击:

REST with Spring and Hymanson full data binding

jsonspringrestspring-mvcHymanson

提问by Javier Ferrero

I'm using Spring MVC to handle JSON POST requests. Underneath the covers I'm using the MappingHymansonHttpMessageConverter built on the Hymanson JSON processor and enabled when you use the mvc:annotation-driven.

我正在使用 Spring MVC 来处理 JSON POST 请求。在幕后,我使用 MappingHymansonHttpMessageConverter 构建在 Hymanson JSON 处理器上,并在您使用 mvc:annotation-driven 时启用。

One of my services receives a list of actions:

我的一项服务收到了一系列操作:

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

I have found that Hymanson maps the requestBody to a List of java.util.LinkedHashMap items (simple data binding). Instead, I would like the request to be bound to a List of typed objects (in this case "ActionImpl").

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

I know this is easy to do if you use Hymanson's ObjectMapper directly:

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

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

but I was wondering what's the best way to achieve this when using Spring MVC and MappingHymansonHttpMessageConverter. Any hints?

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

Thanks

谢谢

采纳答案by StaxMan

I suspect problem is due to type erasure, i.e. instead of passing generic parameter type, maybe only actions.getClass() is passed; and this would give type equivalent of List< ?>.

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

If this is true, one possibility would be to use an intermediate sub-class, like:

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

public class ActionImplList extends ArrayList<ActionImpl> { }

because this will the retain type information even if only class is passed. So then:

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

public @ResponseBody String executeActions(@RequestBody ActionImplList actions)

would do the trick. Not optimal but should work.

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

I hope someone with more Spring MVC knowledge can shed light on why parameter type is not being passed (perhaps it's a bug?), but at least there is a work around.

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

回答by Michiel Verkaik

I have found that you can also work around the type erasure issue by using an array as the @RequestBody instead of a collection. For example, the following would work:

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

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

回答by Frédéric

For your information, the feature will be available in Spring 3.2 (see https://jira.springsource.org/browse/SPR-9570)

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

I just tested it on current M2 and it works like a charm out of the box (no need to provide additionnal annotation to provide the parameterized type, it will be automatically resolved by new MessageConverter)

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

回答by waxwing

This question is already old, but I think I can contribute a bit anyway.

这个问题已经很老了,但我想无论如何我都可以贡献一点。

Like StaxMan pointed out, this is due to type erasure. It definitely shouldbe possible, because you canget the generic arguments via reflection from the method definition. However, the problem is the API of the HttpMessageConverter:

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

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

Here, only List.class will be passed to the method. So, as you can see, it is impossible to implement a HttpMessageConverter that calculates the real type by looking at the method parameter type, as that is not available.

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

Nevertheless, it is possible to code your own workaround - you just won't be using HttpMessageConverter. Spring MVC allows you to write your own WebArgumentResolverthat kicks in before the standard resolution methods. You can for example use your own custom annotation (@JsonRequestBody?) that directly uses an ObjectMapper to parse your value. You will be able to provide the parameter type from the method:

不过,您可以编写自己的解决方法 - 您只是不会使用 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;
    }
});

Not really the way TypeReference was intended to be used I presume, but ObjectMapper doesn't provide a more suitable method.

我认为 TypeReference 的使用方式并不是真的,但是 ObjectMapper 没有提供更合适的方法。

回答by skaffman

Have you tried declaring the method as:

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

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

I haven't tried it, but based on your question it's the first thing I wouldtry.

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