Jaxb JAX-RS:如何在返回响应对象时自动序列化集合?
我有一个JAXB注释的employee类:Jaxb JAX-RS:如何在返回响应对象时自动序列化集合?,jaxb,jersey,jax-rs,Jaxb,Jersey,Jax Rs,我有一个JAXB注释的employee类: @XmlRootElement(name=“employee”) 公营雇员{ 私有整数id; 私有字符串名称; ... @xmlement(name=“id”) 公共int getId(){ 返回此.id; } …//name、equals、hashCode和toString的setter和getter } 和一个JAX-RS资源对象(我使用的是Jersey 1.12) @GET @使用({MediaType.APPLICATION\uxml,Med
@XmlRootElement(name=“employee”)
公营雇员{
私有整数id;
私有字符串名称;
...
@xmlement(name=“id”)
公共int getId(){
返回此.id;
}
…//name、equals、hashCode和toString的setter和getter
}
和一个JAX-RS资源对象(我使用的是Jersey 1.12)
@GET
@使用({MediaType.APPLICATION\uxml,MediaType.APPLICATION\ujson})
@产生({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
@路径(“/”)
公开名单查找员工(
@QueryParam(“名称”)字符串名称,
@QueryParam(“页面”)字符串页码,
@QueryParam(“pageSize”)字符串(pageSize){
...
List employees=employeeService.findeemployees(…);
返回员工;
}
这个端点工作得很好。我明白了
2.
安娜
但是,如果我更改方法以返回响应
对象,并将员工列表放入响应正文中,如下所示:
@GET
@使用({MediaType.APPLICATION\uxml,MediaType.APPLICATION\ujson})
@产生({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
@路径(“/”)
公众对雇主的反应(
@QueryParam(“名称”)字符串名称,
@QueryParam(“页面”)字符串页码,
@QueryParam(“pageSize”)字符串(pageSize){
...
List employees=employeeService.findeemployees(…);
返回Response.ok().entity(employees.build();
}
由于以下异常,终结点导致HTTP 500:
javax.ws.rs.WebApplicationException:com.sun.jersey.api.MessageException:Java类Java.util.ArrayList、Java类Java.util.ArrayList和MIME媒体类型application/xml的消息体编写器未找到
在第一种情况下,JAX-RS显然已经安排了适当的消息编写器在返回集合时启动。当集合放置在实体体中时,这种情况不会发生,这似乎有点不一致。在返回响应时,我可以采取什么方法来实现列表的自动JAXB序列化
我知道我可以
- 只需从资源方法返回列表
- 创建一个单独的
类EmployeeList
但是我想知道是否有一种很好的方法可以使用
响应
对象并让列表序列化,而无需创建自己的包装类。您可以将列表
包装在GenericEntity
的实例中,以保留类型信息:
public void writeTo(Object value, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String,Object> httpHeaders, OutputStream entityStream) throws IOException {
/* 27-Feb-2009, tatu: Where can we find desired encoding? Within
* HTTP headers?
*/
ObjectMapper mapper = locateMapper(type, mediaType);
JsonEncoding enc = findEncoding(mediaType, httpHeaders);
JsonGenerator jg = mapper.getJsonFactory().createJsonGenerator(entityStream, enc);
jg.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
// Want indentation?
if (mapper.getSerializationConfig().isEnabled(SerializationConfig.Feature.INDENT_OUTPUT)) {
jg.useDefaultPrettyPrinter();
}
// 04-Mar-2010, tatu: How about type we were given? (if any)
JavaType rootType = null;
if (genericType != null && value != null) {
/* 10-Jan-2011, tatu: as per [JACKSON-456], it's not safe to just force root
* type since it prevents polymorphic type serialization. Since we really
* just need this for generics, let's only use generic type if it's truly
* generic.
*/
if (genericType.getClass() != Class.class) { // generic types are other impls of 'java.lang.reflect.Type'
/* This is still not exactly right; should root type be further
* specialized with 'value.getClass()'? Let's see how well this works before
* trying to come up with more complete solution.
*/
//**where the magic happens**
//if the type to instantiate implements collection interface (List, Set and so on...)
//Java applies Type erasure from Generic: e.g. List<BaseRealEstate> is seen as List<?> and so List<Object>, so Jackson cannot determine @JsonTypeInfo correctly
//so, in this case we must determine at runtime the right object type to set
if(Collection.class.isAssignableFrom(type))
{
Collection<?> converted = (Collection<?>) type.cast(value);
Class<?> elementClass = Object.class;
if(converted.size() > 0)
elementClass = converted.iterator().next().getClass();
//Tell the mapper to create a collection of type passed as parameter (List, Set and so on..), containing objects determined at runtime with the previous instruction
rootType = mapper.getTypeFactory().constructCollectionType((Class<? extends Collection<?>>)type, elementClass);
}
else
rootType = mapper.getTypeFactory().constructType(genericType);
/* 26-Feb-2011, tatu: To help with [JACKSON-518], we better recognize cases where
* type degenerates back into "Object.class" (as is the case with plain TypeVariable,
* for example), and not use that.
*/
if (rootType.getRawClass() == Object.class) {
rootType = null;
}
}
}
// [JACKSON-578]: Allow use of @JsonView in resource methods.
Class<?> viewToUse = null;
if (annotations != null && annotations.length > 0) {
viewToUse = _findView(mapper, annotations);
}
if (viewToUse != null) {
// TODO: change to use 'writerWithType' for 2.0 (1.9 could use, but let's defer)
ObjectWriter viewWriter = mapper.viewWriter(viewToUse);
// [JACKSON-245] Allow automatic JSONP wrapping
if (_jsonpFunctionName != null) {
viewWriter.writeValue(jg, new JSONPObject(this._jsonpFunctionName, value, rootType));
} else if (rootType != null) {
// TODO: change to use 'writerWithType' for 2.0 (1.9 could use, but let's defer)
mapper.typedWriter(rootType).withView(viewToUse).writeValue(jg, value);
} else {
viewWriter.writeValue(jg, value);
}
} else {
// [JACKSON-245] Allow automatic JSONP wrapping
if (_jsonpFunctionName != null) {
mapper.writeValue(jg, new JSONPObject(this._jsonpFunctionName, value, rootType));
} else if (rootType != null) {
// TODO: change to use 'writerWithType' for 2.0 (1.9 could use, but let's defer)
mapper.typedWriter(rootType).writeValue(jg, value);
} else {
mapper.writeValue(jg, value);
}
}
}
public void writeTo(对象值、类类型、类型genericType、注释[]注释、MediaType MediaType、多值Map HttpHeader、OutputStream entityStream)引发IOException{
/*2009年2月27日,塔图:我们在哪里可以找到想要的编码?在
*HTTP头?
*/
ObjectMapper mapper=locateMapper(类型,mediaType);
JsonEncoding enc=findEncoding(mediaType,httpHeaders);
JsonGenerator jg=mapper.getJsonFactory().createJsonGenerator(entityStream,enc);
禁用(jsonggenerator.Feature.AUTO\u CLOSE\u目标);
//想要缩进吗?
if(mapper.getSerializationConfig().isEnabled(SerializationConfig.Feature.INDENT_输出)){
jg.useDefaultPrettyPrinter();
}
//2010年3月4日,塔图:我们得到的类型如何?(如果有的话)
JavaType rootType=null;
if(genericType!=null&&value!=null){
/*2011年1月10日,塔图:根据[JACKSON-456],仅仅强制root是不安全的
*类型,因为它阻止多态类型序列化
*对于泛型,我们只需要使用泛型类型,如果它确实是
*通用的。
*/
if(genericType.getClass()!=Class.Class){//泛型类型是'java.lang.reflect.Type'的其他impl
/*这仍然不完全正确;根类型应该更进一步吗
*专用于“value.getClass()”?让我们看看之前的工作情况
*试图提出更完整的解决方案。
*/
//**魔法发生在哪里**
//如果要实例化的类型实现了集合接口(列表、集合等…)
//Java从泛型中应用类型擦除:例如,List被视为List和so List,因此Jackson无法正确确定@JsonTypeInfo
//因此,在这种情况下,我们必须在运行时确定要设置的正确对象类型
if(Collection.class.isAssignableFrom(type))
{
已转换的集合=(集合)类型.cast(值);
Class elementClass=Object.Class;
如果(已转换.size()>0)
elementClass=converted.iterator().next().getClass();
//告诉映射程序创建一个作为参数传递的类型集合(List、Set等…),其中包含在运行时使用上一条指令确定的对象
rootType=mapper.getTypeFactory().ConstructionCollectionType((类>)类型,elementClass);
}
其他的
rootType=mapper.getTypeFactory().constructType(genericType);
/*2011年2月26日,塔图:为了帮助[JACKSON-518],我们更好地识别
*类型退化回“Object.class”(与普通TypeVariable一样,
*例如),不要使用它。
*/
if(rootType.getRawClass()==Object.class){
rootType=null;
}
}
}
//[JACKSON-578]:允许在资源方法中使用@JsonView。
类viewToUse=null;
我
@GET
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Path("/")
public Response findEmployees(
@QueryParam("name") String name,
@QueryParam("page") String pageNumber,
@QueryParam("pageSize") String pageSize) {
...
List<Employee> employees = employeeService.findEmployees(...);
GenericEntity<List<Employee>> entity = new GenericEntity<List<Employee>>(Lists.newArrayList(employees))
return Response.ok().entity(entity).build();
}