Как сериализовать / десериализовать через Джексона, когда класс содержит переменные типа interface? - PullRequest
0 голосов
/ 20 марта 2020

Есть интерфейс, скажем, 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..

Конструкторы, геттеры и сеттеры уже определены.

Класс, который состоит из всех переменных

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

Итак, я хочу сериализовать класс Implementor в JSON. Я использую Джексона для того же. Итак, я добавил @jsonTypeInfo и @type для интерфейса, чтобы у них был конкретный класс для работы. Но когда я пытаюсь сериализовать подклассы, сериализуются только var1 и var2 типа int, а не var3 / var4 типа A. Как я тоже могу сериализовать эти переменные?

Json I получаю, если я пытаюсь сериализовать реализатор:

{
  "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
}

1 Ответ

1 голос
/ 24 марта 2020

Я воспроизвел ваш код с некоторыми изменениями, и он работает для меня, когда реализован, как показано ниже (сериализация и десериализация), поэтому дайте мне знать, если это соответствует вашим ожиданиям. Основные моменты, на которые следует обратить внимание, - это несколько небольших исправлений к аннотациям, и я обнаружил, что при конфигурации по умолчанию абсолютно важно иметь правильные методы получения и установки, иначе свойства НЕ БУДУТ сериализованы - это кажется наиболее вероятной проблемой.

Лично я хотел бы изучить использование конфигурации, чтобы позволить Джексону использовать свойства напрямую, так как я ненавижу общепринятые методы получения и установки, которые публично пропускают все ваше внутреннее состояние, вместо того, чтобы инкапсулировать его и подвергать конкретному поведению c, но это только мнение - не имеет отношения к вашему вопросу!

Вывод:

{
  "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
}

Фрагменты кода:

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
}
...