"result" : {
"id" : "123",
"category" : "typeA",
"value" : {
"typeAField" : "123"
}
}
"result" : {
"id" : "321",
"category" : "typeB",
"value" : {
"typeBAField1" : "123",
"typeBAField2" : true
}
}
我想将这样的json结构更改为java对象。 结果有 id、类别和值,值中对象的类型根据类别而变化。
所以我创建了这样的对象: 当类别的值为typeA时,我想使用TypeA.java对象,当类别的值为typeB时,我想使用TypeB.java对象。
public class Result {
String id;
String category;
Values value;
}
public abstract class Values {
}
public TypeA extends Values {
String typeAField;
}
public TypeB extends Values {
String typeBField1;
String typeBField2;
}
输入如下:
"result" : {
"id" : "123",
"category" : "typeA",
"value" : {
"typeAField" : "123"
}
}
输入文本时,我想编写代码将其反序列化为 Result.java 对象。
@Data
class Result {
private String id;
private String category;
private Values value;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT, property = "category")
@JsonSubTypes({
@JsonSubTypes.Type(value = TypeA.class, name = "typeA"),
@JsonSubTypes.Type(value = TypeB.class, name = "typeB")
})
abstract class Values {}
@Data
class TypeA extends Values {
private String typeAField;
}
@Data
class TypeB extends Values {
private String typeBAField1;
private boolean typeBAField2;
}
String json1 = "{\"id\":\"123\",\"category\":\"typeA\",\"value\":{\"typeAField\":\"123\"}}";
String json2 = "{\"id\":\"321\",\"category\":\"typeB\",\"value\":{\"typeBAField1\":\"123\",\"typeBAField2\":true}}";
ObjectMapper objectMapper = new ObjectMapper();
Result result1 = objectMapper.readValue(json1, Result.class); // error
Result result2 = objectMapper.readValue(json2, Result.class);
错误详情
com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'typeAField' as a subtype of `Values`: known type ids = [typeA, typeB] (for POJO property 'value')
at [Source: (String)"{"id":"123","category":"typeA","value":{"typeAField":"123"}}"; line: 1, column: 41] (through reference chain: Result["value"])
@Data
class Result {
private String id;
private String category;
private Values value;
@JsonSetter("value")
public void setValue(Map<String, Object> valueMap) {
ObjectMapper objectMapper = new ObjectMapper();
try {
if (valueMap.containsKey("typeAField")) {
this.value = objectMapper.convertValue(valueMap, TypeA.class);
}
else {
this.value = objectMapper.convertValue(valueMap, TypeB.class);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
abstract class Values {}
@Data
class TypeA extends Values {
private String typeAField;
}
@Data
class TypeB extends Values {
private String typeBAField1;
private boolean typeBAField2;
}
它可以工作,但设置器部分似乎不干净。 还有更好的办法吗? 我有很多不足,但我想得到帮助 提前谢谢你
在第一种方法中,您使用的是
JsonTypeInfo.As.WRAPPER_OBJECT
,如果 JSON 数据如下所示,它将起作用:
{
"result": {
"id": "321",
"category": "typeB",
"value": {
"typeB": {
"typeBAField1": "123",
"typeBAField2": true
}
}
}
}
现在,您可以使用
JsonTypeInfo.As.EXTERNAL_PROPERTY
,根据 JavaDocs,它只能用于属性,不能用于类型(类)。
公共静态最终 JsonTypeInfo.As EXTERNAL_PROPERTY
包含机制与 PROPERTY 类似,不同之处在于属性包含在层次结构中的更高一级,即作为与要键入的 JSON 对象处于同一级别的同级属性。请注意,此选择只能用于属性,不能用于类型(类)。尝试将其用于课程将导致基本 PROPERTY 的包含策略
因此,您必须使用
JsonTypeInfo.As.EXTERNAL_PROPERTY
注释 Result 类的 value 属性,并删除抽象 Values 类注释。然后就可以反序列化 JSON 数据而不会出错。
@Data
public class Result {
private String id;
private String category;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "category")
@JsonSubTypes({
@JsonSubTypes.Type(value = TypeA.class, name = "typeA"),
@JsonSubTypes.Type(value = TypeB.class, name = "typeB")
})
private Values value;
}
abstract class Values {}