Я некоторое время пытался придумать способ вернуть объект пользовательского ответа с атрибутом данных, который является либо объектом, либо списком.Вот несколько упрощенных соответствующих классов.Я использую Jersey v2.27 и Jackson v2.9 +
@XmlRootElement(name = "response")
public class ResponseEnvelope<T> {
private Metadata metadata;
private T data;
public ResponseEnvelope(Metadata metadata, T data) {
this.metadata = metadata;
this.data = data;
}
}
@XmlRootElement
public class Person {
private String name;
private int age;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
}
@XmlRootElement
public class ListWrapper<T> {
private List<T> list;
public ListWrapper(List<T> list) {this.list = list;}
}
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public class PersonResource {
private List<Person> getPeople() {
return Arrays.asList(new Person(20, "Monty Python"), new Person(25, "Brian");
}
@GET
public Response getAllPeople() {
ResponseEnvelope<ListWrapper<Person> response = new ResponseEnvelope<ListWrapper<Person>>(new Metadata(), new ListWrapper(getPeople());
return Response.status(200).entity(response).build();
}
@GET
@Path("{id}")
public Response getExampleById(@PathParam("id") String id) {
ResponseEnvelope<Person> response = new ResponseEnvelope<Person>(new Metadata(), getPeople().get(0));
return Response.status(200).entity(response).build();
}
}
@Provider
@Produces(MediaType.APPLICATION_XML)
public class CustomResolver implements ContextResolver<JAXBContext> {
private JAXBContext context;
public CustomResolver() {
try {
this.context = JAXBContext.newInstance(
ArrayList.class,
Person.class,
ListWrapper.class,
ResponseEnvelope.class
);
}
catch (JAXBException e) {
throw new RuntimeException(e);
}
}
@Override
public JAXBContext getContext(Class<?> type) {
return (type.equals(ResponseEnvelope.class)) ? context : null;
}
}
@ApplicationPath("")
public class ServerConfig extends ResourceConfig {
public ServerConfig() {
this.packages(true,"com.example");
this.register(JacksonFeature.class);
}
}
Я пробовал вещи из нескольких уроков / вопросов, таких как здесь , здесь , здесь и т. Д. (Я много пробовал ...)
Не получается получить единый ответ между двумя форматами.Когда я пытаюсь использовать List
непосредственно как T data
, JAXB жалуется на отсутствие контекста для ArrayList (когда я его помещаю туда, он не выводит сами элементы).
Когда я использую класс GenericEntity
непосредственно в ответе, например, с
GenericEntity<List<Person>> list = new GenericEntity<List<Person>>(people){};
return Response.status(200).entity(list).build();`
Вывод корректен как для json, так и для xml.Однако, если я использую это в своем поле T data
, я получаю исключение JAXB, что он не может найти мой класс ресурсов (кажется, вы не можете использовать GenericEntity
в универсальном классе?).
Если я использую универсальный класс ListWrapper
для размещения своих коллекций, я могу создавать действительные xml и json и, используя различные аннотации (@XmlAnyElement(lax = true)
или @XmlElements({@XmlElement(name = "person", type = Person.class)}
), могу правильно отформатировать XML, но jsonвключает в себя дополнительное свойство ListWrapper<T> list
(то есть {"data": {"list": []}}
вместо {"data": []}
. Я пытался использовать для этого @JsonUnwrapped
и @JsonSerialize
с пользовательским сериализатором, но я не могу его сгладить.
Требуемый пример ответа для уникального идентификатора человека
{
"metadata": {
// some content
},
"data": {
"age": 20,
"name": "Monty Python"
}
}
и XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<response>
<data>
<age>20</age>
<name>Monty Python</name>
</data>
<metadata>
<!-- some content -->
</metadata>
</response>
и списка людей:
{
"metadata": {
// some content
},
"data": [
{
"age": 20,
"name": "Monty Python"
},
{
"age": 25,
"name": "Brian"
}
]
}
и XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<response>
<data>
<person>
<age>20</age>
<name>Monty Python</name>
</person>
<person>
<age>25</age>
<name>Brian</name>
</person>
</data>
<metadata>
<!-- some content -->
</metadata>
</response>