简体   繁体   English

多种类型的 Jackson 反序列化接口

[英]Jackson deserialization interface on multiple types

I'm experimenting some troubles with Jackson deserialization in Java.我正在尝试在 Java 中使用 Jackson 反序列化遇到一些麻烦。 I've made 2 solutions, and I can't resolve the problem.我已经提出了 2 个解决方案,但我无法解决问题。 Problem?问题? I got my result with the property duplicated, a field it's duplicated after jackson deserialization.我得到了重复属性的结果,这是杰克逊反序列化后重复的字段。 (My problem is exact the same as this question: Avoid duplicate field generated by JsonTypeInfo in Jackson and no one could give you an answer at the time) (我的问题和这个问题完全一样: 避免JsonTypeInfo在Jackson中生成的重复字段,当时没有人可以给你答案)

First at all, I have the following class:首先,我有以下课程:

@JsonIgnoreProperties(ignoreUnknown = true)
public class Instance {

    @JsonProperty("id")
    private String id;
 
    @JsonProperty("name")
    private String name;

    @JsonProperty("type")
    private InstanceType type;
 }

What I'm triying to do, is just instantiate an object of type 'Instance', save it and read it.我正在尝试做的只是实例化一个“实例”类型的对象,保存并读取它。 And with solution 2, the object is saved with the type duplicated (type appear as array that contain 'name', 'firs_type', for example or 'second_type) depends on what I create.使用解决方案 2,对象以重复类型保存(类型显示为包含“名称”、“firs_type”或“second_type”的数组)取决于我创建的内容。 With solution 1, I can save the object ok, but when I try to read it, I fall on a jackson exception casting.使用解决方案 1,我可以保存对象,但是当我尝试读取它时,我遇到了 jackson 异常转换。

Solution 1:解决方案1:

@JsonDeserialize(using = InstanceTypeDeserializer.class)
public interface InstanceType {
    String value();
}

@JsonDeserialize(as = HardInstanceType.class)
public enum HardInstanceType implements InstanceType {
    FIRST_TYPE("first_type"),
    SECOND_TYPE("second_type")
    private String value;

    HardInstanceType(String value) {
        this.value = value;
    }

    @JsonValue
    public String value() {
       return value;
    }
}

@JsonDeserialize(as = SoftInstanceType.class)
public enum SoftInstanceType implements InstanceType {
    //.. types implementaion similar as HardInstanceType
}

public class InstanceTypeDeserializer extends JsonDeserializer<InstanceType> {
    @Override
    public InstanceType deserialize(JsonParser jp,  DeserializationContext ctxt) throws IOException, JsonProcessingException {
        ObjectMapper mapper = (ObjectMapper) jp.getCodec();
        ObjectNode root = (ObjectNode) mapper.readTree(jp);
        
        if(root.get("name").asText().equals("hard")) {
            return mapper.readValue(root.toString(), HardInstanceType.class);
        } else { 
            return mapper.readValue(root.toString(), SoftInstanceType.class);
        }
    }
}

The problem with this solution, is that when I try to get the data stored, and map to the class, I get the following error:此解决方案的问题在于,当我尝试存储数据并映射到类时,出现以下错误:

exception parsing json: com.fasterxml.jackson.databind.JsonMappingException: class com.fasterxml.jackson.databind.node.TextNode cannot be cast to class com.fasterxml.jackson.databind.node.ObjectNode (com.fasterxml.jackson.databind.node.TextNode and com.fasterxml.jackson.databind.node.ObjectNode are in unnamed module of loader org.springframework.boot.loader.LaunchedURLClassLoader @1a3e8e24) (through reference chain: java.util.ArrayList[0]->com.project.package.xxxx.Instance["type"])异常解析 json: com.fasterxml.jackson.databind.JsonMappingException: 类 com.fasterxml.jackson.databind.node.TextNode 不能转换为类 com.fasterxml.jackson.databind.node.ObjectNode (com.fasterxml.jackson.databind .node.TextNode 和 com.fasterxml.jackson.databind.node.ObjectNode 在加载器 org.springframework.boot.loader.LaunchedURLClassLoader @1a3e8e24 的未命名模块中(通过参考链:java.util.ArrayList[0]->com .project.package.xxxx.Instance["type"])

Solution 2解决方案2

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "name")
@JsonSubTypes({
    @JsonSubTypes.Type(value = HardInstanceType.class, name = "hard") })
public interface InstanceType {
   String value();
}

The problem with this solution, is that when I save the data, when I create an Instance object, and store it, in the data Stored, I get the following:这个解决方案的问题是,当我保存数据时,当我创建一个实例对象并将它存储在数据存储中时,我得到以下信息:

      "id": "1",
      "name": "hard",
      "type": [
        "hard",
        "first_type"
      ]

what is not correct, in type should be store just "first_type" (what is stored with solution 1, but I can't read it haha).什么是不正确的,类型应该只存储“first_type”(解决方案 1 存储了什么,但我看不懂哈哈)。

Of course, Instace class is more complex and with more fields, I reduce it here, just for the example.当然,Instace 类比较复杂,字段也比较多,我这里简化一下,仅举个例子。

I need help with this, thank you very much in advance.我需要这方面的帮助,在此先非常感谢您。

Finally, I could solve the problem.最后,我可以解决问题。 I post this just in case someone else need it.我发布这个以防万一其他人需要它。

  1. Add a property to my HardInstanceType class.向我的 HardInstanceType 类添加一个属性。

    public enum HardInstanceType implements InstanceType {公共枚举 HardInstanceType 实现 InstanceType {

     FIRST_TYPE("first_type"), SECOND_TYPE("second_type"); private String value; public String hardTypeIdentifierSer = "hardTypeIdentifierSer"; HardInstanceType(String value) { this.value = value; } @JsonValue public String value() { return value; }

    } }

  2. Then, in the deserializer:然后,在解串器中:

    public class InstanceTypeDeserializer extends JsonDeserializer {公共类 InstanceTypeDeserializer 扩展 JsonDeserializer {

     @Override public InstanceType deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { TreeNode node = jp.readValueAsTree(); if (node.get("hardTypeIdentifierSer") != null) { return jp.getCodec().treeToValue(node, HardInstanceType.class); }

    } }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM