我正在尝试通过 Spring Rest 模板编组一个列表:List
对象。
我可以传递简单的 Pojo
对象,但我找不到任何描述如何发送 List
对象的文档。
Spring 使用 Jackson JSON 来实现 HttpMessageConverter 。杰克逊文档涵盖了这一点:
除了绑定到 POJO 之外,
“简单”类型,有一种
附加变体:绑定到
通用(类型化)容器。这个案例
需要特殊处理,因为
所谓的类型擦除(Java 使用
在某种程度上实现泛型
向后兼容的方式),其中
阻止你使用类似的东西
Collection.class
(这确实
未编译)。
所以如果你想将数据绑定到
Map
您需要使用:
地图<字符串,用户> result = mapper.readValue(src, new TypeReference
其中 TypeReference
只需要
传递泛型类型定义(通过
在这种情况下是任意内部类):
重要的部分是
定义类型
绑定到。
这个可以在Spring模板中完成吗?我看了一眼代码,它让我觉得不舒服,但也许我只是不知道一些技巧。
解决方案
感谢下面的有用答案,最终的解决方案是不发送 List,而是发送一个简单扩展 List 的单个对象,例如: class PojoList extends ArrayList ;。 Spring 可以成功地编组这个对象,并且它完成与发送 List
相同的事情,尽管它是一个不太干净的解决方案。我还在 Spring 发布了一个 JIRA,以解决他们的 HttpMessageConverter 接口中的这个缺点。
I'm trying to marshal a list: List<Pojo>
objects via the Spring Rest Template.
I can pass along simple Pojo
objects, but I can't find any documentation that describes how to send a List<Pojo>
objects.
Spring is using Jackson JSON to implement the HttpMessageConverter
. The jackson documentation covers this:
In addition to binding to POJOs and
"simple" types, there is one
additional variant: that of binding to
generic (typed) containers. This case
requires special handling due to
so-called Type Erasure (used by Java
to implement generics in somewhat
backwards compatible way), which
prevents you from using something like
Collection<String>.class
(which does
not compile).
So if you want to bind data into a
Map<String,User>
you will need to use:
Map<String,User> result = mapper.readValue(src, new TypeReference<Map<String,User>>() {});
where TypeReference
is only needed to
pass generic type definition (via
anynomous inner class in this case):
the important part is
<Map<String,User>>
which defines type
to bind to.
Can this be accomplished in the Spring template? I took a glance at the code and it makes me thing not, but maybe I just don't know some trick.
Solution
The ultimate solution, thanks to the helpful answers below, was to not send a List, but rather send a single object which simply extends a List, such as: class PojoList extends ArrayList<Pojo>
. Spring can successfully marshal this Object, and it accomplishes the same thing as sending a List<Pojo>
, though it be a little less clean of a solution. I also posted a JIRA in spring for them to address this shortcoming in their HttpMessageConverter
interface.
发布评论
评论(4)
在 Spring 3.2 中,现在使用
RestTemplate
上的新exchange()
方法支持泛型类型:非常有用!
In Spring 3.2 there is now support for generic types using the new
exchange()
-methods on theRestTemplate
:Works like a charm!
确保包含泛型类型参数的一种方法是实际上对 List 或 Map 类型进行子类化,这样您就有类似:
并返回该列表的实例。
那么为什么这会产生影响呢?因为泛型类型信息只保留在几个地方:方法和字段声明以及超类型声明。因此,虽然“原始”列表不包含任何运行时类型信息,但“MyStringList”的类定义通过其超类型声明包含任何运行时类型信息。
请注意,对看似类型化的变量进行赋值并没有帮助:它只会创建更多编译时语法糖:真正的类型信息仅通过 Class 实例(或其 lib 提供的扩展,例如 Jackson 中的 JavaType 和 TypeReference)传递。
除此之外,您还需要弄清楚如何传递 Jackson
JavaType
或TypeReference
来伴随值。One way to ensure that generic type parameters are included is to actually sub-class List or Map type, such that you have something like:
and return instance of that list.
So why does this make a difference? Because generic type information is retained in just a couple of places: method and field declarations, and super type declarations. So whereas "raw" List does NOT include any runtime type information, class definition of "MyStringList" does, through its supertype declarations.
Note that assignments to seemingly typed variables do not help: it just creates more compile-time syntactic sugar: real type information is only passed with Class instances (or lib-provided extensions thereof, like JavaType and TypeReference in Jackson's case).
Other than this, you would need to figure out how to pass Jackson either
JavaType
orTypeReference
to accompany value.如果我阅读
MappingJacksonHttpMessageConverter
的文档正确,您必须创建并注册MappingJacksonHttpMessageConverter
的子类并覆盖getJavaType(类)
方法:If I read the docs for
MappingJacksonHttpMessageConverter
right, you will have to create and register a subclass ofMappingJacksonHttpMessageConverter
and override thegetJavaType(Class<?>)
method:我通过使用以下配置解决了这个问题:
其中
PojoArrayList
是扩展ArrayList
的最终类。I have solved this problem by using the following configuration:
where
PojoArrayList
is a final class that extendsArrayList<Pojo>
.