【问题标题】:How to serialize/ deserialize via jackson when class contains variables of type interface?当类包含接口类型的变量时,如何通过杰克逊进行序列化/反序列化?
【发布时间】:2020-03-19 21:27:19
【问题描述】:

有一个接口,假设是 A。我有多个实现该接口 A 的类。这些类还包含 A 类型的类变量。所以,就像:

@JsonTypeInfo(use = JsonTypeInfo.Id.Class, include = JsonTypeInfo.As.Property, property = "className")

@JsonSubType({
 @Type(value = abstractClass.class, name = "abstractClass"),
 @Type(value = subClass1.class, name = "subClass1"),
 @Type(value = subClass2.class, name = "subClass2"),
 '
 '
 '
})
interface A {
 func1();
 func2();
}

abstract class abstractClass implements A {
 int abstractvar1;
 func1(){//code} 
}

class subClass1 extends abstractClass {
  int var1;
  int var2;
  A var3;
  A var4;
}

class subClass2 extends abstractClass {
  int var1;
  int var2;
  A var3;
}

class subClass3 extends abstractClass {
  float var1;
  int var2;
  A var3;
}

 and more classes defined trying to extend abstractClass..

构造函数、getter 和 setter 已经定义。

由所有变量组成的类

class Implementor {
 int implementorVar1;
 String implementorVar2;
 A implementorVar3;
 int implementorVar4;
}

所以,我想将 Implementor 类序列化为 JSON。我也在用杰克逊。 所以,我在接口中添加了@jsonTypeInfo 和@type,这样它们就有了一个具体的类来处理。 但是当我尝试序列化子类时,只有 int 类型的 var1 和 var2 被序列化,而不是 A 类型的 var3/var4。 我怎样才能序列化这些变量呢?

如果我尝试序列化实施者,我会得到 Json:

{
  "implementorVar1": 1,
  "implementorVar2": "hello",
  "implementorVar3": {
    "className": "subClass2",
    "abstractVar1": 45,
  },
  "implementorVar4": 1000
}

我期待的Json:

{
  "implementorVar1": 1,
  "implementorVar2": "hello",
  "implementorVar3": {
    "className": "subClass2",
    "abstractVar1" : 45,
    "var1": 45,
    "var2": 56,
    "var3": {
      "className": "subClass3",
      "var1": 2,
      "var2": 5,
      "var3" : {
        "className" : "" ...
     }
    }
  },
  "implementorVar4": 1000
}

【问题讨论】:

  • 由于接口没有属性,我猜 var3 和 var4 充其量会被序列化为空对象。你想要这样的结果吗?如果您在另一端反序列化为 subClass1 和 subClass2 的实例,那么这些空属性的存在与否没有区别。也许这是 Jackson 不包括它们的原因,但是如果您创建一个 subClass2 的实例,其中 var3 使用具有属性的 A 的实现(例如 subClass1)进行初始化,会发生什么我相当肯定 Jackson 会将 var3 作为具有 var1 和 var2 作为嵌套属性的对象,但我
  • @Chris 你想要那个结果吗? --> 不,我希望 var3、var4 的值在 JSON 本身中可用,同时也可以反序列化它。
  • @Chris 但是,例如,如果您创建一个 subClass2 的实例,其中 var3 使用具有属性(例如 subClass1)的 A 的实现来初始化,会发生什么我很确定 Jackson 会将 var3 作为对象包含在内将 var1 和 var2 作为嵌套属性 --> 是的,var1 和 var2 肯定会被正确序列化和反序列化,但是 var3/var4 不会被序列化/反序列化,因此如果有一个 subClass3 的属性在 subClass1 中定义,那么就赢了'不要被序列化,这意味着我最终会丢失信息。
  • 嗨,我和你在一起,直到关于 subClass3 的最后一点 - 我想我明白你在问什么,但要澄清一下,接口的实现可能有也可能没有属性。如果是这样,据我所知,它们会被序列化,但如果它只是实现没有任何属性的行为,那么它就不会。那么问题是在反序列化时如何填充 var3 - 如果没有信息,要实例化什么类型。这就是我认为可以将类型信息作为伪属性添加到序列化 JSON 的地方 - 这就是你的意思,我可以查找参考
  • 所以你提到了你对注释的使用,你能包括注释代码的例子,以及任何生成的 JSON 吗?可能有助于澄清

标签: java json interface jackson json-serialization


【解决方案1】:

我复制了您的代码并进行了一些更改,并且在实现如下(序列化和反序列化)时它适用于我,因此请告诉我这是否符合您的期望。需要注意的要点是对注释的一些小的更正,我发现在默认配置下,拥有正确的 getter 和 setter 绝对至关重要,否则属性将不会被序列化——这似乎是最有可能出现的问题。

就我个人而言,我会考虑使用配置来允许杰克逊直接使用属性,因为我讨厌公开泄漏所有内部状态而不是封装它并暴露特定行为的毯子 getter 和 setter,但这只是意见 - 与您的问题无关!

输出:

{
  "implementorVar1" : 1,
  "implementorVar2" : "hello",
  "implementorVar3" : {
    "className" : "subClass2",
    "var1" : 1,
    "var2" : 2,
    "var3" : {
      "className" : "subClass3",
      "var1" : 1.0,
      "var2" : 2,
      "var3" : {
        "className" : "subClass1",
        "var1" : 1,
        "var2" : 2
      }
    }
  },
  "implementorVar4" : 1000
}

代码sn-ps:

public static void main(String[] args) {
    Implementor target = new Implementor(1, "hello",
            new SubClass2(1, 2,
                    new SubClass3(1F, 2,
                            new SubClass1(1, 2))),
            1000);
    try {
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper
                .writerWithDefaultPrettyPrinter()
                .writeValueAsString(target);
        Implementor deserialised = mapper.readValue(json, Implementor.class);
        System.out.println(json);
        System.out.println(deserialised);
    } catch (Exception e) {
        e.printStackTrace();
    }
}


class Implementor {
    private int implementorVar1;
    private String implementorVar2;
    private A implementorVar3;
    private int implementorVar4;

    public Implementor() {}

    public Implementor(int implementorVar1, String implementorVar2, A implementorVar3, int implementorVar4) {
        this.implementorVar1 = implementorVar1;
        this.implementorVar2 = implementorVar2;
        this.implementorVar3 = implementorVar3;
        this.implementorVar4 = implementorVar4;
    }

    public int getImplementorVar1() {
        return implementorVar1;
    }

    public void setImplementorVar1(int implementorVar1) {
        this.implementorVar1 = implementorVar1;
    }
    // Other getters/setters omitted
    // Default configuration ABSOLUTELY requires getters and setters for all properties in all serialised classes
}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "className")
@JsonSubTypes({
        @JsonSubTypes.Type(value = SubClass1.class, name = "subClass1"),
        @JsonSubTypes.Type(value = SubClass2.class, name = "subClass2"),
        @JsonSubTypes.Type(value = SubClass3.class, name = "subClass3")
})
interface A {
    int func1();
    int func2();
}


class SubClass1 extends AbstractClass {
    private int var1;
    private int var2;

    public SubClass1() {}

    public SubClass1(int var1, int var2) {
        this.var1 = var1;
        this.var2 = var2;
    }

    @Override
    public int func1() {
        return 0;
    }

    @Override
    public int func2() {
        return 0;
    }

    // getters and setters omitted but they HAVE to be there
}

class SubClass2 extends AbstractClass {
    private int var1;
    private int var2;
    private A var3;

    public SubClass2() {}

    public SubClass2(int var1, int var2, A var3) {
        this.var1 = var1;
        this.var2 = var2;
        this.var3 = var3;
    }
    // getters and setters omitted but they HAVE to be there
}

class SubClass3 extends AbstractClass {
    private float var1;
    private int var2;
    private A var3;

    public SubClass3() {}

    public SubClass3(float var1, int var2, A var3) {
        this.var1 = var1;
        this.var2 = var2;
        this.var3 = var3;
    }

    @Override
    public int func1() {
        return 0;
    }

    @Override
    public int func2() {
        return 0;
    }
    // getters and setters omitted but they HAVE to be there
}

【讨论】:

  • 对不起,错过了 AbstractClass 但里面没有什么重要的东西
猜你喜欢
  • 2021-09-09
  • 1970-01-01
  • 2016-11-11
  • 1970-01-01
  • 1970-01-01
  • 2021-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多