改造GSON响应摘要映射

Ale*_*x L 5 java gson retrofit

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

Web服务json响应

{
  "requestId": 0,
  "totalShapes": 2,
  "shapes": [
    {
      "circle": {
        "code": 1,
        "radius": 220
        "color" : "blue"
      }
    },
    {
      "square": {
        "code": 1,
        "size": 220
      }
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

主要结果映射:

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

抽象类:

public abstract class Shape implements Serializable {
}
Run Code Online (Sandbox Code Playgroud)

圈数:

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

正方形:

public class Square {
  @SerializedName("code") private int code;
  @SerializedName("size") private int size;
  // + getters...
}
Run Code Online (Sandbox Code Playgroud)

Ale*_* C. 5

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

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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将其注册到解析器中

Gson gson = 
    new GsonBuilder().registerTypeAdapter(Shape.class, new ShapeDeserializer())
                     .create();
Run Code Online (Sandbox Code Playgroud)

然后你使用它:

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}]}
Run Code Online (Sandbox Code Playgroud)

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

另请注意:

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