使用 Jackson 往返 JSON,其中每个 class 实现相同的接口
Using Jackson to / from JSON where each class implements the same interface
我正在尝试使用 Jackson 反序列化一个相当复杂的 JSON 结构。
序列化工作正常:
参数接口:
public interface Param<T> {
}
Not.java:
public class Not implements Param<Param<?>> {
private Param not;
public Not(){
}
public Not(Param not) {
this.not = not;
}
public Param getNot() {
return not;
}
}
And.java:
public class And implements Param<List<?>> {
private List<Param> and;
public List<Param> getAnd() {
return and;
}
public List<Param> add(Param ... params){
for (Param param : params){
this.and.add(param);
}
return this.and;
}
public And() {
this.and = new ArrayList<>();
}
public And(Param ... params){
this.and = new ArrayList<>();
for (Param param : params){
this.and.add(param);
}
}
}
Company.java:
public class CompanyName implements Param<String> {
private String companyName;
public CompanyName(String value) {
this.companyName = value;
}
public String getCompanyName() {
return companyName;
}
}
序列化:
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(new And(new Or(new CompanyName("ABC"), new CompanyName("DEF")), new Not(new CompanyName("GHI")))));
打印:
{"and":[{"or":[{"companyName":"ABC"},{"companyName":"DEF"}]},{"not":{"companyName":"GHI"}}]}
现在反序列化,Jackson 怎么知道如何映射和/或/companyName/不返回他们的对象?
And and = mapper.readValue(json, And.class);
Exception in thread "main"
com.fasterxml.jackson.databind.JsonMappingException: Can not construct
instance of com.ahp.messaging.param.Param, problem: abstract types
either need to be mapped to concrete types, have custom deserializer,
or be instantiated with additional type information at [Source:
{"and":[{"or":[{"companyName":"ABC"},{"companyName":"DEF"}]},{"not":{"companyName":"GHI"}}]};
line: 1, column: 9] (through reference chain:
com.ahp.messaging.param.And["and"]->java.util.ArrayList[0])
为了消除异常,我修改了Param接口如下:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "T", visible = false)
@JsonSubTypes({
@JsonSubTypes.Type(value = Not.class, name = "not"),
@JsonSubTypes.Type(value = And.class, name = "and"),
@JsonSubTypes.Type(value = Or.class, name = "or"),
@JsonSubTypes.Type(value = CompanyName.class, name = "companyName")
})
public interface Param<T> {
}
现在序列化为:
{"T":"and","and":[{"T":"or","or":[{"T":"companyName","companyName":"ABC"},{"T":"companyName","companyName":"DEF"}]},{"T":"not","not":{"T":"companyName","companyName":"GHI"}}]}
反序列化完美,但所有内容都有类型信息,有没有办法摆脱类型信息,只在真正需要的地方使用它?
简答,需要类型信息。
使用 XML 可以获取每个元素的类型信息,使用 JSON 可以为更小的表示牺牲类型信息,但在这种情况下,废弃类型信息意味着没有办法推断 class 它应该映射到什么。
我正在尝试使用 Jackson 反序列化一个相当复杂的 JSON 结构。
序列化工作正常:
参数接口:
public interface Param<T> {
}
Not.java:
public class Not implements Param<Param<?>> {
private Param not;
public Not(){
}
public Not(Param not) {
this.not = not;
}
public Param getNot() {
return not;
}
}
And.java:
public class And implements Param<List<?>> {
private List<Param> and;
public List<Param> getAnd() {
return and;
}
public List<Param> add(Param ... params){
for (Param param : params){
this.and.add(param);
}
return this.and;
}
public And() {
this.and = new ArrayList<>();
}
public And(Param ... params){
this.and = new ArrayList<>();
for (Param param : params){
this.and.add(param);
}
}
}
Company.java:
public class CompanyName implements Param<String> {
private String companyName;
public CompanyName(String value) {
this.companyName = value;
}
public String getCompanyName() {
return companyName;
}
}
序列化:
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(new And(new Or(new CompanyName("ABC"), new CompanyName("DEF")), new Not(new CompanyName("GHI")))));
打印:
{"and":[{"or":[{"companyName":"ABC"},{"companyName":"DEF"}]},{"not":{"companyName":"GHI"}}]}
现在反序列化,Jackson 怎么知道如何映射和/或/companyName/不返回他们的对象?
And and = mapper.readValue(json, And.class);
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.ahp.messaging.param.Param, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information at [Source: {"and":[{"or":[{"companyName":"ABC"},{"companyName":"DEF"}]},{"not":{"companyName":"GHI"}}]}; line: 1, column: 9] (through reference chain: com.ahp.messaging.param.And["and"]->java.util.ArrayList[0])
为了消除异常,我修改了Param接口如下:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "T", visible = false)
@JsonSubTypes({
@JsonSubTypes.Type(value = Not.class, name = "not"),
@JsonSubTypes.Type(value = And.class, name = "and"),
@JsonSubTypes.Type(value = Or.class, name = "or"),
@JsonSubTypes.Type(value = CompanyName.class, name = "companyName")
})
public interface Param<T> {
}
现在序列化为:
{"T":"and","and":[{"T":"or","or":[{"T":"companyName","companyName":"ABC"},{"T":"companyName","companyName":"DEF"}]},{"T":"not","not":{"T":"companyName","companyName":"GHI"}}]}
反序列化完美,但所有内容都有类型信息,有没有办法摆脱类型信息,只在真正需要的地方使用它?
简答,需要类型信息。
使用 XML 可以获取每个元素的类型信息,使用 JSON 可以为更小的表示牺牲类型信息,但在这种情况下,废弃类型信息意味着没有办法推断 class 它应该映射到什么。