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;
}
}
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)
Test:
@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
Result:
{
"movies" : [ {
"name" : "I Origins"
}, {
"name" : "Imitation Game"
} ]
}
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;
}
would bot be viable. You would instead need to check is the type isAssignableFrom
if (MovieList.class.isAssignableFrom(type)) {
return listMapper;
}