Search code examples
javajsongsondeserialization

gson deserialization polymorphic type assembly problem


this is pojo

class Mother {
    //..
}

@Data
@AllArgsConstructor
class Son extends Mother {
    private int age;
}

@Data
@AllArgsConstructor
class Daughter extends Mother {
    private int age;
}

this is main

public static void main(String[] args) {
    List<Son> sons = new ArrayList<>();
        sons.add(new Son(12));
        sons.add(new Son(13));

    List<Daughter> daughters = new ArrayList<>();
        daughters.add(new Daughter(5));
        daughters.add(new Daughter(6));

    Map<String,List<? extends Mother>> map = new HashMap<>();
        map.put("ex-husband",sons);
        map.put("husband",daughters);

    Gson gson = new Gson();
    String json = gson.toJson(map);

    System.out.println(json);
    //ok

    Gson gson1 = new Gson();
    Type type = new TypeToken<Map<String,List<? extends Mother>>>() {}.getType();

    Map<String,List<? extends Mother>> map1 = gson1.fromJson(json,type);

    List<Son> sons1 = (List<Son>) map1.get("ex-husband");
    System.out.println(sons1.get(0).getAge());
    //error
}

this is error

java.lang.ClassCastException: Mother cannot be cast to Son

This is the json after formatting

{
    "ex-husband": [
        {
            "age": 12
        },
        {
            "age": 13
        }
    ],
    "husband": [
        {
            "age": 5
        },
        {
            "age": 6
        }
    ]
}

It is structured around the following. Map<String, List<? extends Mother>>

gson can be serialized to json normally, but in turn it does not recognize the specific Son and Daughter types, and therefore cannot read the values of specific properties

My expectation is that it is possible to read subclass attributes after deserialization, but it reports an error, guys, how can this be corrected, is there a good way to do it?


Solution

  • ok, i got it,haha

    @Setter
    @Getter
    class Mother {
        private String className;//---------------------
        //..
    }
    
    @Data
    @AllArgsConstructor
    @Builder
    class Son extends Mother {//------------------------
        private int age;
    }
    
    @Data
    @AllArgsConstructor
    class Daughter extends Mother {
        private int age;
    }
    
    public class Test2 {
        public static void main(String[] args) {
            List<Son> sons = new ArrayList<>();
            Son son = new Son(11);
            Son son2 = new Son(12);
            son.setClassName("Son");//----------------------
            son.setClassName("Son");
            sons.add(son);
            sons.add(son2);
    
            List<Daughter> daughters = new ArrayList<>();
            Daughter daughter = new Daughter(5);
            Daughter daughter1 = new Daughter(6);
            daughter.setClassName("Daughter");//-----------------------
            daughter1.setClassName("Daughter");
            daughters.add(daughter);
            daughters.add(daughter1);
    
            Map<String,List<? extends Mother>> map = new HashMap<>();
            map.put("ex-husband",sons);
            map.put("husband",daughters);
    
            Gson gson =  new GsonBuilder().setPrettyPrinting().create();
            String json = gson.toJson(map);
    
            System.out.println(json);
    
            Type type = new TypeToken<Map<String,List<Son>>>() {}.getType();//----------------------
            Map<String,List<Son>> map1 = gson.fromJson(json,type);
    
            List<Son> sons1 = map1.get("ex-husband");
            for (Son son1 : sons1) {
                if (son1 instanceof Son)
                    System.out.println(son1.getAge());
            }
    
            Type type2 = new TypeToken<Map<String,List<Daughter>>>() {}.getType();//--------------------
            Map<String,List<Daughter>> map2 = gson.fromJson(json,type2);
    
            List<Daughter> daughters1 = map2.get("husband");
            for (Daughter d1 : daughters1) {
                if (d1 instanceof Daughter)
                    System.out.println(d1.getAge());
            }
        }
    }
    

    result:

    {
      "ex-husband": [
        {
          "age": 11,
          "className": "Son"
        },
        {
          "age": 12
        }
      ],
      "husband": [
        {
          "age": 5,
          "className": "Daughter"
        },
        {
          "age": 6,
          "className": "Daughter"
        }
      ]
    }
    11
    12
    5
    6