强制JAX-RS将我的类序列化为JSON对象 [英] Force JAX-RS to serialize my class to a JSON object

查看:182
本文介绍了强制JAX-RS将我的类序列化为JSON对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类,它是一个内部列表的装饰器。我想在我的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 ObjectMappers, 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆