Jackson typeId 未包含在生成的 json 中
Jackson typeId is not included in generated json
有以下课程:
public class BaseEntity<E> {
public TrackedChange<E> trackChange;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({ @JsonSubTypes.Type(value=B.class, name="b_type") })
public abstract class A extends BaseEntity<A> implements Cloneable{
public String aFoo;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
@JsonTypeName("b_type")
public class B extends A {
public String bFoo;
}
public class TrackedChange<E> {
public E tracked;
}
public class Runner {
public static void main(String[] args) throws JsonProcessingException, CloneNotSupportedException {
B bInstance = new B();
bInstance.bFoo = "bFoo";
bInstance.aFoo = "aFoo";
B clone = (B) bInstance.clone();
bInstance.trackChange = new TrackedChange<A>();
bInstance.trackChange.tracked = clone;
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(bInstance));
}
}
生成的JSON为:
{
"type":"b_type",
"trackChange":{
"tracked":{
"trackChange":null,
"aFoo":"aFoo",
"bFoo":"bFoo"
}
},
"aFoo":"aFoo",
"bFoo":"bFoo"
}
类型 ("type":"b_type")
信息未包含在 trackChange.tracked 对象中。如何解决这个问题?
编辑:最后我使用了 JsonTypeInfo.As.EXISTING_PROPERTY
,它是在 2.3.0 版本之后引入的。它利用现有属性来确定实际类型。
TrackedChange.tracked
上的类型擦除是您的问题。在运行时,您的类型由于类型擦除而丢失,并且 Jackson 序列化程序无法确定类型,因此无法将其识别为 B
并且找不到它的 @JsonTypeInfo
;因此在运行时杰克逊读取 TrackedChange.tracked
类型 Object
.
有多种方法可以减轻 Jackson 中的类型擦除,但它们通常围绕集合的泛型。
只有一种方法可以基本实现你的目标,你可以像这样配置 ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
TypeResolverBuilder<?> typer = new ObjectMapper.DefaultTypeResolverBuilder(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
typer = typer.init(JsonTypeInfo.Id.CLASS, null);
typer = typer.inclusion(JsonTypeInfo.As.PROPERTY);
typer = typer.typeProperty("type");
mapper.setDefaultTyping(typer);
这将在序列化期间为对象和非具体类型注册类型映射器配置(这涵盖了 TrackedChange.tracked
情况)。不幸的是,我没有看到任何方式来预先注册此配置将使用匹配的 b_type
名称,如您的示例所示。我的最佳建议是更改您的 class 配置以使用以下内容,这与上面配置的行为相匹配:
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type")
给你这样的输出:
{
"type" : "so.json.typeinfo.B",
"trackChange" : {
"tracked" : {
"type" : "so.json.typeinfo.B",
"trackChange" : null,
"aFoo" : "aFoo",
"bFoo" : "bFoo"
}
},
"aFoo" : "aFoo",
"bFoo" : "bFoo"
}
有以下课程:
public class BaseEntity<E> {
public TrackedChange<E> trackChange;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({ @JsonSubTypes.Type(value=B.class, name="b_type") })
public abstract class A extends BaseEntity<A> implements Cloneable{
public String aFoo;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
@JsonTypeName("b_type")
public class B extends A {
public String bFoo;
}
public class TrackedChange<E> {
public E tracked;
}
public class Runner {
public static void main(String[] args) throws JsonProcessingException, CloneNotSupportedException {
B bInstance = new B();
bInstance.bFoo = "bFoo";
bInstance.aFoo = "aFoo";
B clone = (B) bInstance.clone();
bInstance.trackChange = new TrackedChange<A>();
bInstance.trackChange.tracked = clone;
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(bInstance));
}
}
生成的JSON为:
{
"type":"b_type",
"trackChange":{
"tracked":{
"trackChange":null,
"aFoo":"aFoo",
"bFoo":"bFoo"
}
},
"aFoo":"aFoo",
"bFoo":"bFoo"
}
类型 ("type":"b_type")
信息未包含在 trackChange.tracked 对象中。如何解决这个问题?
编辑:最后我使用了 JsonTypeInfo.As.EXISTING_PROPERTY
,它是在 2.3.0 版本之后引入的。它利用现有属性来确定实际类型。
TrackedChange.tracked
上的类型擦除是您的问题。在运行时,您的类型由于类型擦除而丢失,并且 Jackson 序列化程序无法确定类型,因此无法将其识别为 B
并且找不到它的 @JsonTypeInfo
;因此在运行时杰克逊读取 TrackedChange.tracked
类型 Object
.
有多种方法可以减轻 Jackson 中的类型擦除,但它们通常围绕集合的泛型。
只有一种方法可以基本实现你的目标,你可以像这样配置 ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
TypeResolverBuilder<?> typer = new ObjectMapper.DefaultTypeResolverBuilder(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
typer = typer.init(JsonTypeInfo.Id.CLASS, null);
typer = typer.inclusion(JsonTypeInfo.As.PROPERTY);
typer = typer.typeProperty("type");
mapper.setDefaultTyping(typer);
这将在序列化期间为对象和非具体类型注册类型映射器配置(这涵盖了 TrackedChange.tracked
情况)。不幸的是,我没有看到任何方式来预先注册此配置将使用匹配的 b_type
名称,如您的示例所示。我的最佳建议是更改您的 class 配置以使用以下内容,这与上面配置的行为相匹配:
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type")
给你这样的输出:
{
"type" : "so.json.typeinfo.B",
"trackChange" : {
"tracked" : {
"type" : "so.json.typeinfo.B",
"trackChange" : null,
"aFoo" : "aFoo",
"bFoo" : "bFoo"
}
},
"aFoo" : "aFoo",
"bFoo" : "bFoo"
}