user3431327
user3431327

Reputation: 155

Gson: deserialize list of abstract subclass from wrapper class

I'm pretty new to Gson and JSON all together. My problem is when create a list of generic class and store it in the wrapper obj, i cant deserialize back into the child obj.

Here is the main code

public static void main(String[] arg) {
    block b = new block();

    List<Shape> shapes = new ArrayList<Shape>();

    Circle c = new Circle();
    c.setRadius(1);
    c.setType("cir");
    Square s = new Square();
    s.setSide(4);
    s.setType("sq");

    shapes.add(c);
    shapes.add(s);

    b.setShape(shapes);

    String json = new Gson().toJson(b);
    System.out.println(json);

    Object obj = new Gson().fromJson(json, block.class);
    block bobj = (block) obj;

    List<Shape> li = bobj.getShape();
    Shape sh = (Shape)li.get(0);

    System.out.println(sh.getClass().getCanonicalName());
    System.out.println(sh.toString());
}

I get this as output

{"shape":[{"radius":1,"type":"cir"},{"side":4,"type":"sq"}]}
    com.ups.pcs.test.TestTypeAdaptor.Shape
     com.ups.pcs.test.TestTypeAdaptor$Shape@3c6f579

here are my rest of the code:

static class block implements Serializable {
      List<Shape> shape = null;

    public block() {

    }

    public List<Shape> getShape() {
        return shape;
    }

    public void setShape(List<Shape> shape) {
        this.shape = shape;
    }

  }

  static class Shape implements Serializable{
    String type;

    public Shape(){}
    public void setType(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }

  }

  private static final class Circle extends Shape implements Serializable{
    int radius;

    public Circle(){}
    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    public String toString() {
        return "t: " + type + "r: " + radius;
    }
  }

  private static final class Square extends Shape implements Serializable{
    int side;

    public Square(){}
    public int getSide() {
        return side;
    }

    public void setSide(int side) {
        this.side = side;
    }

    public String toString() {
        return "t: " + type + "s: " + side;
    }
  }

i've seen some post talking about using custom typeAdaptor ortypeAdaptorFactory, which i'm not sure how to use. Btw i'm using Gson2.2.2 version

Upvotes: 2

Views: 1031

Answers (1)

user3431327
user3431327

Reputation: 155

This is the best answer i found so far... Please let me know if anyone find better solution then this. And I haven't tested to know how fast it will run.

Basically create custom deserializer for your main object and determine property class when looking at each object.

  public static class BlockDeserializer implements JsonDeserializer<Block> {

    @Override
    public Block deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json == null)
            return null;
        else {
            Block block = new Block();
            JsonObject jo = json.getAsJsonObject();
            JsonArray ja = jo.getAsJsonArray("shape");

            List<Shape> shapes = new ArrayList<Shape>();

            for(JsonElement je : ja) {
                JsonObject jeo = je.getAsJsonObject();

                if(jeo.get("radius") != null) {             
                    shapes.add(new Gson().fromJson( jeo , Circle.class));                       
                } else {
                    shapes.add(new Gson().fromJson( jeo , Square.class));           
                }
            }

            block.shape = shapes;

            return block;
        }
    }
}   

Upvotes: 2

Related Questions