我有一个类,它是一个内部列表周围的装饰器。我想在我的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接口?
假设Jackson是您的序列化器,则可以将设置ObjectMapper为WRAP_ROOT_VALUE。您将在ContextResolver。为了不将相同的配置用于所有类型,可以使用两个不同的configure ObjectMappers,一个用于list类,另一个用于其余类。例如
ObjectMapper
WRAP_ROOT_VALUE
ContextResolver
@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给出注释支持是enabled-见这里)
MessageBodyWriter
getContext
@JsonRootName
@XmlRootElement
测试:
@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" } ] }
C:\>curl -v -H "Accept:application/json" http://localhost:8080/api/movies
{ "movies" : [ { "name" : "I Origins" }, { "name" : "Imitation Game" } ] }
因此,我注意到您的清单已经存在protected。也许您稍后可能想扩展MovieList该类。在这种情况下
protected
MovieList
if (type == MovieList.class) { return listMapper; }
该机器人将是可行的。您需要检查的是类型isAssignableFrom
isAssignableFrom
if (MovieList.class.isAssignableFrom(type)) { return listMapper; }