[英]Jersey Jackson Custom Response with Generics in JSON and XML
我已经尝试了一段时间,想出一种方法来返回带有数据属性的自定义响应对象,该数据属性可以是对象或列表。 这是一些简化的相关类。 我正在使用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);
}
}
我已经尝试了一些教程/问题中的内容,例如here , here , here等。(我已经尝试了很多……)
我似乎无法在两种格式之间获得统一的响应。 当我尝试将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
与自定义序列化,但我似乎无法压平。
所需的样本响应,用于唯一的Person id的响应
{
"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>
答案是使用ListWrapper<T>
类,并使用@JsonValue
以及@XmlAnyElement(lax = true)
注释getter。 这些将创建格式正确的JSON和XML响应。 该类应该看起来像这样
import java.util.List;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlRootElement;
import com.fasterxml.jackson.annotation.JsonValue;
@XmlRootElement(name = "data")
public class ListWrapper<T> {
private List<T> list;
public ListWrapper() {}
public ListWrapper(List<T> list) {
this.list = list;
}
/**
* @return the list
*/
@XmlAnyElement(lax = true)
@JsonValue
public List<T> getList() {
return list;
}
/**
* @param list
* the list to set
*/
public void setList(List<T> list) {
this.list = list;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.