Как настроить сериализацию списка объектов JAXB в JSON?
я использую Джерси для создания веб-службы REST для серверного компонента.
аннотированный объект JAXB, который я хочу сериализовать в списке, выглядит так:
@XmlRootElement(name = "distribution")
@XmlType(name = "tDistribution", propOrder = {
"id", "name"
})
public class XMLDistribution {
private String id;
private String name;
// no-args constructor, getters, setters, etc
}
у меня есть ресурс REST для получения одного дистрибутива, который выглядит так:
@Path("/distribution/{id: [1-9][0-9]*}")
public class RESTDistribution {
@GET
@Produces("application/json")
public XMLDistribution retrieve(@PathParam("id") String id) {
return retrieveDistribution(Long.parseLong(id));
}
// business logic (retrieveDistribution(long))
}
у меня также есть ресурс REST для получения списка всех дистрибутивов, который выглядит следующим образом:
@Path("/distributions")
public class RESTDistributions {
@GET
@Produces("application/json")
public List<XMLDistribution> retrieveAll() {
return retrieveDistributions();
}
// business logic (retrieveDistributions())
}
я использую ContextResolver для настройки сериализации JAXB, которая на данный момент настроено так:
@Provider
@Produces("application/json")
public class JAXBJSONContextResolver implements ContextResolver<JAXBContext> {
private JAXBContext context;
public JAXBJSONContextResolver() throws Exception {
JSONConfiguration.MappedBuilder b = JSONConfiguration.mapped();
b.nonStrings("id");
b.rootUnwrapping(true);
b.arrays("distribution");
context = new JSONJAXBContext(b.build(), XMLDistribution.class);
}
@Override
public JAXBContext getContext(Class<?> objectType) {
return context;
}
}
работают оба ресурса REST, а также распознаватель контекста. Это пример вывода для первого:
// path: /distribution/1
{"id":1,"name":"Example Distribution"}
именно этого я и хочу. Это пример вывода для списка:
// path: /distributions
{"distribution":[{"id":1,"name":"Sample Distribution 1"},{"id":2,"name":"Sample Distribution 2"}]}
это не совсем то, что я хочу.
я не понимаю, почему существует заключительный distribution
тег есть. Я хотел удалить его с .rootUnwrapping(true)
в контексте решателя, но, по-видимому, что удаляет только другой заключительный тег. Это выход с .rootUnwrapping(false)
:
// path: /distribution/1
{"distribution":{"id":1,"name":"Example Distribution"}} // not ok
// path: /distributions
{"xMLDistributions":{"distribution":[{"id":1,"name":"Sample Distribution 1"},{"id":2,"name":"Sample Distribution 2"}]}}
мне также пришлось настроить .arrays("distribution")
всегда получать массив JSON, даже с одним элементом.
в идеале, я хотел бы иметь это в качестве вывода:
// path: /distribution/1
{"id":1,"name":"Example Distribution"} // currently works
// path: /distributions
[{"id":1,"name":"Sample Distribution 1"},{"id":2,"name":"Sample Distribution 2"}]
я попытался вернуть List<XMLDistribution>
, a XMLDistributionList
(обертка вокруг списка), a XMLDistribution[]
, но я не мог найти способ получить простой массив дистрибутивов JSON в требуемом формате.
я также попробовал другой Примечания, возвращаемые JSONConfiguration.natural()
, JSONConfiguration.mappedJettison()
и т. д., и не смог получить ничего похожего на то, что мне нужно.
кто-нибудь знает, можно ли настроить JAXB для этого?
2 ответов
Я нашел решение: замените сериализатор JAXB JSON на более поведенческий сериализатор JSON, такой как Jackson. Простой способ-использовать jackson-jaxrs, который уже сделал это для вас. Класс JacksonJsonProvider. Все, что вам нужно сделать, это изменить веб-проекта.xml так, что Джерси (или другая реализация JAX-RS) сканирует его. Вот что вам нужно добавить:
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>your.project.packages;org.codehaus.jackson.jaxrs</param-value>
</init-param>
и это все. Джексон будет использоваться для сериализации JSON, и он работает так, как вы ждать списков и массивов.
более длинный способ-написать собственный пользовательский MessageBodyWriter, зарегистрированный для создания "application / json". Вот пример:
@Provider @Produces("application/json") public class JsonMessageBodyWriter implements MessageBodyWriter { @Override public long getSize(Object obj, Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { return -1; } @Override public boolean isWriteable(Class type, Type genericType, Annotation annotations[], MediaType mediaType) { return true; } @Override public void writeTo(Object target, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream outputStream) throws IOException { new ObjectMapper().writeValue(outputStream, target); } }
вам нужно будет убедиться, что ваш веб.xml включает в себя пакет, как и для готового решения выше.
в любом случае: вуаля! Вы увидите правильно сформированный JSON.
Вы можете скачать Jackson отсюда: http://jackson.codehaus.org/
ответ Jonhatan велик, и это было очень полезно для меня.
просто модернизация:
Если вы используете версию 2.x Джексона (например, версия 2.1) класс com.fasterxml.Джексон.jaxrs.формат JSON.JacksonJaxbJsonProvider, следовательно, сеть.xml:
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>your.project.packages;com.fasterxml.jackson.jaxrs.json</param-value>
</init-param>