强制JAX-RS将我的类序列化为JSON对象 [英] Force JAX-RS to serialize my class to a JSON object
问题描述
我有一个类,它是一个内部列表的装饰器。我想在我的JAX-RS服务中将此类用作DTO。它的代码如下:
I have class which is a decorator around an inner list. I would like to use this class as a DTO in my JAX-RS service. Its code as follows:
@XmlRootElement(name = "movies")
public class MoviesResponse implements List<Movie> {
@XmlElement(name = "movie")
protected List<Movie> movies;
/* tons of delegate methods */
}
我需要同时支持application / xml和application / json。
格式是固定的,它必须像
I need to support both application/xml, and application/json. The format is fixed, it has to be like
<movies>
<movie>
<foo />
</movie>
<movie>
<foo />
</movie>
</movies>
... XML格式,
... in XML, and
{
"movie": [
{},{}
]
}
...在JSON中。
XML工作得很好,但JSON看起来像这样:
...in JSON. XML works perfectly fine, but JSON looks like this:
[{},{}]
您可能怀疑,如果我没有实现List接口,它会生成我需要的格式。所以我猜序列化器是聪明的,并将其视为List,从而将其序列化为一个数组。但是我需要将它序列化为一个对象。我怎么能这样做,实现List接口?
As you may suspect, if I don't implement the List interface, it generates the the format I need. So I guess the serializer is being smart and treating it as List thus serializing it into an array. But I need to serialize it into an object. How can I do this, implementing the List interface?
推荐答案
假设Jackson是你的序列化器,你可以配置 ObjectMapper
到 WRAP_ROOT_VALUE
。您可以在 ContextResolver
。因此,所有类型都不使用相同的配置,您可以使用两个不同的已配置 ObjectMapper
,一个用于列表类,另一个用于其余类型。例如
Assuming Jackson is your serializer, you could configure the ObjectMapper
to WRAP_ROOT_VALUE
. You would do that in the ContextResolver
. So that the same configuration is not used for all types, you can use two different configured ObjectMapper
s, one for the list class, and one for the rest. For example
@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
final ObjectMapper listMapper = new ObjectMapper();
final ObjectMapper defaultMapper = new ObjectMapper();
public ObjectMapperContextResolver() {
listMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
listMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
listMapper.registerModule(new JaxbAnnotationModule());
defaultMapper.registerModule(new JaxbAnnotationModule());
}
@Override
public ObjectMapper getContext(Class<?> type) {
if (type == MovieList.class) {
return listMapper;
}
return defaultMapper;
}
}
MessageBodyWriter
用于编组将调用 getContext
方法,传入它试图编组的类。根据结果,即将使用的 ObjectMapper
。 WRAP_ROOT_VALUE
的作用是将根值包装在一个对象中,其名称是 @JsonRootName
中的值或 @XmlRootElement
(给定JAXB注释支持已启用 - 请参阅这里)
The MessageBodyWriter
used for marshalling will call the getContext
method, passing in the class it's trying to marshal. Based on the the result, that is the ObjectMapper
that will be used. What WRAP_ROOT_VALUE
does, is wrap the root value in a object, with the name being the value in @JsonRootName
or @XmlRootElement
(given JAXB annotation support is enabled- see here)
测试:
@Path("/movies")
public class MovieResource {
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response getMovieList() {
MovieList list = new MovieList();
list.add(new Movie("I Origins"));
list.add(new Movie("Imitation Game"));
return Response.ok(list).build();
}
}
C:\> curl -v -H接受:application / jsonhttp:// localhost:8080 / api / movies
结果:
{
电影:[{
name:I Origins
},{
名称:模拟游戏
}]
}
< h3> UPDATE
所以我注意到你的列表是 protected
。也许您以后可能想要扩展 MovieList
类。在这种情况下,这个
UPDATE
So I noticed you have the list as being protected
. Maybe you might later want to extend the MovieList
class. In which case, this
if (type == MovieList.class) {
return listMapper;
}
可行。您需要检查类型 isAssignableFrom
would bot be viable. You would instead need to check is the type isAssignableFrom
if (MovieList.class.isAssignableFrom(type)) {
return listMapper;
}
这篇关于强制JAX-RS将我的类序列化为JSON对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!