我通过在基类上添加注释来启用Polymorphic序列化支持。我能够成功地对单个对象进行串行化,并且它将类型信息作为序列化数据的一部分进行编写。但是,如果我将对象存储在列表中并将其序列化,则不会发生同样的情况。
似乎这个问题已在1.6.3(http://jira.codehaus.org/browse/JACKSON-362)
中修复我正在使用Jackson 2.3.2并且仍然面临这个问题。
有人知道如何解决这个问题吗?
代码:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY,property = "type")
@JsonSubTypes({@Type(value = Derived.class, name = "derived")})
public abstract class Base {
}
public class Derived extends Base {
private String field;
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
}
public class Test {
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Derived d = new Derived();
d.setField("Name");
Base b = d;
System.out.println(mapper.writeValueAsString(b));
List<Base> list = new ArrayList<Base>();
list.add(d);
System.out.println(mapper.writeValueAsString(list));
}
}
输出:
{&#34;类型&#34;:&#34;衍生&#34;&#34;字段&#34;:&#34;名称&#34;}
[{&#34;字段&#34;:&#34;名称&#34;}]
谢谢,
普利文
答案 0 :(得分:1)
答案是https://github.com/FasterXML/jackson-databind/issues/699
这是由于Java类型擦除:当序列化List时,所有Jackson看到的类型都是List(大致相当于List)。由于类型Object没有多态类型信息(注释),因此不会写入任何内容。 所以这不是杰克逊的错误,而是Java Type Erasure的一个不幸特征。 它不适用于数组,因为它们保留了元素类型信息(数组不是通用的;不同类型的数组是不同的类,而泛型类型主要是编译时语法糖)。
有三种主要方法可以解决这个问题:
pass full generic type using TypeReference (ObjectMapper has method like mapper.writerFor(new TypeReference<List<Base>>() { }).writeValue(....)
Sub-class List to something like public class BaseList extends ArrayList<Base>() { }, and pass that: this type WILL retain type information
Avoid using root-level List and Maps
我个人建议做(3),因为这样可以避免类型擦除的所有相关问题。 在我看来,JSON根值应始终是一个JSON对象,通常序列化为POJO。
然而,方法(2)将起作用,这是大多数用户所做的。它确实需要使用额外的助手类。方法(1)可能有效也可能无效;问题是强制类型信息也会影响实际值序列化。因此,虽然它会添加类型ID,但可能会导致某些属性未被序列化。
答案 1 :(得分:1)
这个问题可以通过使用数组而不是列表来解决(因为列表确实键入了擦除):
例如,您的上述测试用例可以写成:public class Test {
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Derived d = new Derived();
d.setField("Name");
Base b = d;
System.out.println(mapper.writeValueAsString(b));
List<Base> list = new ArrayList<Base>();
list.add(d);
System.out.println(mapper.writeValueAsString(
list.toArray(new Base[list.size]) // <--This Part
));
}
}
答案 2 :(得分:0)
我对象数组有同样的问题。对象[]不携带类型信息,但单个对象可以。令人遗憾的是杰克逊没有自动处理这个问题。
两种可能的解决方案: 1.类型化数组序列化工作正常:
[HttpGet]
[Route("students")]
[SwaggerOperation(Tags = new[] { "Student" })]
[SwaggerResponse(HttpStatusCode.OK, Type = typeof(ResponseModel<IList<Student>>))]
[SwaggerResponseExample(HttpStatusCode.OK, typeof(StudentResponseExample))]
[SwaggerResponse(HttpStatusCode.InternalServerError)]
public IHttpActionResult SearchStudent(long? SyncDate = null,int? OffSet = null,int? Limit = null)
{
// Use the variables now here
.
.
.
}
这实际上会产生预期的结果,因为Base []具有类型信息。
Serializer:
Base[] myArray = Base[]{d};
mapper.writeValueAsString(myArray)
ObjectMapper配置:
public class ObjectArraySerializer extends StdSerializer<Object[]> {
public ObjectArraySerializer(final Class<Object[]> vc) {
super(vc);
}
@Override
public void serialize(
final Object[] data,
final JsonGenerator gen,
final SerializerProvider provider) throws IOException {
gen.writeStartArray();
for (Object obj : data) {
gen.writeObject(obj);
}
gen.writeEndArray();
}
}