使用 Jackson 库反序列化 JSon

问题描述 投票:0回答:1
"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;
}

它可以工作,但设置器部分似乎不干净。 还有更好的办法吗? 我有很多不足,但我想得到帮助 提前谢谢你

java json jackson
1个回答
0
投票

在第一种方法中,您使用的是

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 {}
© www.soinside.com 2019 - 2024. All rights reserved.