多级@JsonTypeInfo 和@JsonSubTypes
Multiple level @JsonTypeInfo and @JsonSubTypes
我有 class 层次结构 A <- B <- C。我不想 class A 知道 C,所以我打算使用 A.type=" B" 表示它是 class B,然后 B.type2="C" 表示它是 class C.
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes({@JsonSubTypes.Type(value = B.class, name = "B")})
public abstract class A {
private final String type;
public A(String type) {
this.type = type;
}
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type2")
@JsonSubTypes({@JsonSubTypes.Type(value = C.class, name = "C")})
public class B extends A {
private final String type2;
private final String propertyB;
@JsonCreator
public B(@JsonProperty("type2") String type2,
@JsonProperty("propertyB") String propertyB) {
super("B");
this.type2 = type2;
this.propertyB = propertyB;
}
}
public class C extends B {
private final String propertyC;
@JsonCreator
public C(@JsonProperty("propertyB") String propertyB,
@JsonProperty("propertyC") String propertyC) {
super("C", propertyB);
this.propertyC = propertyC;
}
}
当我将 C 的 JSON 读到 class A 时,实际的 Java 对象是 class B 而不是 C。
@Test
void whenReadCJsonToA_thenObjectIsInstanceOfC() throws JsonProcessingException {
String json = "{\n" +
" \"type\" : \"B\",\n" +
" \"type2\" : \"C\",\n" +
" \"propertyB\" : \"b\",\n" +
" \"propertyC\" : \"c\"\n" +
"}";
A obj = objectMapper.readValue(json, A.class);
assertTrue(obj instanceof B, "obj is not instance of B"); // pass
assertTrue(obj instanceof C, "obj is not instance of C"); // fail
}
使上述测试通过的一种方法是 writing custom deserializer,但如果 class 包含许多字段,则此解决方案很乏味。
有没有可能用更优雅的方式让上面的测试通过?我对级联@JsonTypeInfo 和@JsonSubTypes 的缩进是完全错误的吗?
我的maven项目可以在Github.
中找到
根据this Jackson issue,仅使用一个类型区分符属性 即可支持多级继承。在我的代码中,只保留 属性 type
并删除 属性 type2
.
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes({@JsonSubTypes.Type(value = B.class, name = "B")})
public abstract class A {
private final String type;
public A(String type) {
this.type = type;
}
}
@JsonSubTypes({@JsonSubTypes.Type(value = C.class, name = "C")})
public class B extends A {
private final String propertyB;
@JsonCreator
public B(@JsonProperty("propertyB") String propertyB) {
super("B");
this.propertyB = propertyB;
}
}
public class C extends B {
private final String propertyC;
@JsonCreator
public C(@JsonProperty("propertyB") String propertyB,
@JsonProperty("propertyC") String propertyC) {
super(propertyB);
this.propertyC = propertyC;
}
}
查看 this commit 中的完整代码。
This commit 使用枚举作为类型区分符 属性 类型。
我有 class 层次结构 A <- B <- C。我不想 class A 知道 C,所以我打算使用 A.type=" B" 表示它是 class B,然后 B.type2="C" 表示它是 class C.
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes({@JsonSubTypes.Type(value = B.class, name = "B")})
public abstract class A {
private final String type;
public A(String type) {
this.type = type;
}
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type2")
@JsonSubTypes({@JsonSubTypes.Type(value = C.class, name = "C")})
public class B extends A {
private final String type2;
private final String propertyB;
@JsonCreator
public B(@JsonProperty("type2") String type2,
@JsonProperty("propertyB") String propertyB) {
super("B");
this.type2 = type2;
this.propertyB = propertyB;
}
}
public class C extends B {
private final String propertyC;
@JsonCreator
public C(@JsonProperty("propertyB") String propertyB,
@JsonProperty("propertyC") String propertyC) {
super("C", propertyB);
this.propertyC = propertyC;
}
}
当我将 C 的 JSON 读到 class A 时,实际的 Java 对象是 class B 而不是 C。
@Test
void whenReadCJsonToA_thenObjectIsInstanceOfC() throws JsonProcessingException {
String json = "{\n" +
" \"type\" : \"B\",\n" +
" \"type2\" : \"C\",\n" +
" \"propertyB\" : \"b\",\n" +
" \"propertyC\" : \"c\"\n" +
"}";
A obj = objectMapper.readValue(json, A.class);
assertTrue(obj instanceof B, "obj is not instance of B"); // pass
assertTrue(obj instanceof C, "obj is not instance of C"); // fail
}
使上述测试通过的一种方法是 writing custom deserializer,但如果 class 包含许多字段,则此解决方案很乏味。
有没有可能用更优雅的方式让上面的测试通过?我对级联@JsonTypeInfo 和@JsonSubTypes 的缩进是完全错误的吗?
我的maven项目可以在Github.
中找到根据this Jackson issue,仅使用一个类型区分符属性 即可支持多级继承。在我的代码中,只保留 属性 type
并删除 属性 type2
.
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes({@JsonSubTypes.Type(value = B.class, name = "B")})
public abstract class A {
private final String type;
public A(String type) {
this.type = type;
}
}
@JsonSubTypes({@JsonSubTypes.Type(value = C.class, name = "C")})
public class B extends A {
private final String propertyB;
@JsonCreator
public B(@JsonProperty("propertyB") String propertyB) {
super("B");
this.propertyB = propertyB;
}
}
public class C extends B {
private final String propertyC;
@JsonCreator
public C(@JsonProperty("propertyB") String propertyB,
@JsonProperty("propertyC") String propertyC) {
super(propertyB);
this.propertyC = propertyC;
}
}
查看 this commit 中的完整代码。
This commit 使用枚举作为类型区分符 属性 类型。