【发布时间】:2018-05-01 21:46:34
【问题描述】:
假设我有一个带有 2 个对象的 json,“header”和“data”。它们都具有等效的模型,但只有 Data 具有可变属性,而 Header 属性始终相同。 “data”上的属性是可变的,应该根据“header”中的一个字段进行反序列化,例如:
// this should be deserialized to SuperPojo
{
"header": {
"type": "y" // this should be used as a rule for deserializing object "data"
},
"data": { // this should be deserialized into any Data subclass
// variable data
}
}
这些是我想将上述 JSON 反序列化为的 bean:
// wrapper object
@JsonIgnoreProperties(ignoreUnknown = true)
public class SuperPojo<T extends Data> {
private Header header;
private T data;
// getters & setters
}
@JsonIgnoreProperties(ignoreUnknown = true)
public class Header implements Serializable {
private String type;
// getters & setters
}
// Marker class without fields. Used for inheritance and polymorphism purposes only
// the issue here is that Jackson tries to find a field named "type"
// within "Data" subclasses. What I want is for it to search the "type"
// attribute in class "Header".
@JsonTypeInfo(
use = JsonTypeInfo.Id.CLASS,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = DataX.class, name="x"), // how do I make this refer to field "type" in object "Header"?
@JsonSubTypes.Type(value = DataY.class, name="y")
})
public class Data implements Serializable { }
// should be deserialized into my SuperPojo when header.type equals "x"
@JsonTypeName("x")
public class DataX extends Data {
private long id;
private String name;
// getters & setters
}
// should be deserialized into my SuperPojo when header.type equals "y"
@JsonTypeName("y")
public class DataY extends Data {
@JsonProperty("registration_date")
private LocalDateTime registrationDate;
private Country country; // enum
// getters & setters
}
最后,这就是我尝试执行反序列化的方式:
// JSON X
{
"header": {
"type": "x"
},
"data": {
"id": "12345",
"name":"Jackson"
}
}
// JSON Y
{
"header": {
"type": "y"
},
"data": {
"registration_date": "2018-05-01T18:10:00",
"country":"BRAZIL"
}
}
@Service
public class MyTest {
@Autowired
private ObjectMapper mapper;
void doStuff() {
String jsonX = getJsonX(); // JSON X
String jsonY = getJsonY(); // JSON Y
SuperPojo<? extends Data> bigPojoX = mapper.readValue(jsonX, new TypeReference<SuperPojo<? extends Data>>() { });
SuperPojo<? extends Data> bigPojoY = mapper.readValue(jsonY, new TypeReference<SuperPojo<? extends Data>>() { });
DataX subPojoX = (DataX) bigPojoX.getData(); // throws ClassCastException
DataY subPojoY = (DataY) bigPojoY.getData(); // throws ClassCastException
}
}
我现在正在做的,因为我想不出一种方法来完成这项工作:我将我的 json 反序列化为一个包装类,其中包含一个“Header”类型的字段,然后获取并检查来自它的“类型”并将json再次反序列化为上述包装类的子类,并具有正确数据实现的属性。
我确信这不是最好的方法,也不是一个好的设计选择,但这是我可以解决这个问题的唯一方法。
我已经搜索了一些可能的解决方案,但问题与我的有点不同,所以它们没有奏效:
【问题讨论】:
标签: java json spring serialization jackson