强制JAX-RS将我的类序列化为JSON对象

时间:2015-03-22 18:34:57

标签: java json serialization jax-rs

我有一个类,它是一个内部列表的装饰器。我想在我的JAX-RS服务中将此类用作DTO。其代码如下:

@XmlRootElement(name = "movies")
public class MoviesResponse implements List<Movie> {

    @XmlElement(name = "movie")
    protected List<Movie> movies;

    /* tons of delegate methods */

}

我需要同时支持application / xml和application / json。 格式是固定的,它必须像

<movies>
 <movie>
  <foo />
 </movie>
 <movie>
  <foo /> 
 </movie>
</movies>

...用XML格式,

{
 "movie": [
 {},{}
 ]
}

...在JSON中。 XML工作得很好,但JSON看起来像这样:

[{},{}]

您可能怀疑,如果我没有实现List接口,它会生成我需要的格式。所以我猜序列化器是聪明的,并将其视为List,从而将其序列化为一个数组。但我需要将它序列化为一个对象。我该怎么做,实现List接口?

1 个答案:

答案 0 :(得分:1)

假设Jackson是您的序列化程序,您可以将ObjectMapper配置为WRAP_ROOT_VALUE。你会在ContextResolver中做到这一点。因此,所有类型都不使用相同的配置,您可以使用两个不同的已配置ObjectMapper,一个用于列表类,另一个用于其余类型。例如

@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方法,传入它正在尝试编组的类。根据结果​​,即将使用的ObjectMapperWRAP_ROOT_VALUE的作用是将根值包装在对象中,其名称为@JsonRootName@XmlRootElement中的值(给定JAXB注释支持已启用 - 请参阅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 "Accept:application/json" http://localhost:8080/api/movies
  的结果:
  { "movies" : [ { "name" : "I Origins" }, { "name" : "Imitation Game" } ] }

更新

所以我注意到你的列表是protected。也许你以后可能想要扩展MovieList类。在这种情况下,这个

if (type == MovieList.class) {
    return listMapper;
}

将是可行的。您需要检查类型isAssignableFrom

if (MovieList.class.isAssignableFrom(type)) {
    return listMapper;
}