改进GSON响应抽象映射

时间:2015-12-02 20:22:51

标签: java gson retrofit

我通过改造创建一个简单的HTTP GET请求,并尝试将json响应映射到我的模型。问题是,json返回一个多个Shapes的数组,Shape是一个抽象类,所以它可以是Square,Circle等。每个形状都有自己指定的模型,所以不同的字段。如何将此Shape数组映射到模型?

Web服务json响应

window.onhashchange

主要结果映射:

{
  "requestId": 0,
  "totalShapes": 2,
  "shapes": [
    {
      "circle": {
        "code": 1,
        "radius": 220
        "color" : "blue"
      }
    },
    {
      "square": {
        "code": 1,
        "size": 220
      }
    }
  ]
}

抽象类:

public class Result {
  @SerializedName("requestId") private int requestId;
  @SerializedName("totalShapes") private int totalShapes;
  @SerializedName("shapes") private List<Shape> shapes;
}

圈子:

public abstract class Shape implements Serializable {
}

广场:

public class Circle {
  @SerializedName("code") private int code;
  @SerializedName("radius") private int radius;
  @SerializedName("color") private String color;
  // + getters...
}

1 个答案:

答案 0 :(得分:3)

您可以实现一个像工厂一样的自定义形状反序列化器。根据形状对象的键,您可以将其反序列化为相应的类型。

class ShapeDeserializer implements JsonDeserializer<Shape> {
    @Override
    public Shape deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        Map.Entry<String, JsonElement> entry = json.getAsJsonObject().entrySet().iterator().next();
        switch(entry.getKey()) {
            case "circle":
                return context.deserialize(entry.getValue(), Circle.class);
            case "square":
                return context.deserialize(entry.getValue(), Square.class);
            default:
                throw new IllegalArgumentException("Can't deserialize " + entry.getKey());
        }
    }
}

然后在解析器中注册

Gson gson = 
    new GsonBuilder().registerTypeAdapter(Shape.class, new ShapeDeserializer())
                     .create();

你用它:

Result result = gson.fromJson(myJson, Result.class);
//Result{requestId=0, totalShapes=2, shapes=[Circle{code=1, radius=220, color='blue'}, Square{code=2, size=220}]}

如果密钥与类名完全匹配,则可以直接使用Class.forName(您需要首先将密钥大写)。

另请注意:

  • 如果它出现在每个子类中,您可以将code属性移动到抽象Shape类中
  • 我假设您有一个且只有一个与键相关联的形状。如果你可以在与键“circle”关联的同一个JsonObject中有两个圆圈,那么你需要一个更复杂的逻辑来解析它。如果不是这种情况(尽管RFC不建议使用相同的键具有不同的键值对),它应该可以正常工作。