改造 GSON 响应抽象映射
Retrofit GSON response abstract mapping
我通过改造发出了一个简单的 HTTP GET 请求,并尝试将 json 响应映射到我的模型。问题是,json return 一个数组的倍数 Shapes,Shape 是一个抽象的 class,所以它可以是 Square,Circle 等。每个 shape 都有自己指定的模型,所以不同的领域。如何将这个 Shape 数组映射到模型?
Web 服务 json 响应
{
"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;
}
摘要class:
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...
}
正方形:
public class Square {
@SerializedName("code") private int code;
@SerializedName("size") private int size;
// + getters...
}
您可以实现一个像工厂一样的自定义形状反序列化器。基于形状对象的键,您可以将其反序列化为相应的类型。
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 名称完全匹配,您可以直接使用 Class.forName
(您需要首先将密钥大写)。
另请注意:
- 你可以将
code
属性 移动到摘要 Shape
class 中,如果它出现在每个子classes
- 我假设您有一个且只有一个形状与键关联。如果您可以在与键 "circle" 关联的同一个 JsonObject 中有两个圆圈,您将需要更复杂的逻辑来解析它。如果不是这种情况(尽管 RFC 不建议使用具有相同键的不同键值对),它应该可以正常工作。
我通过改造发出了一个简单的 HTTP GET 请求,并尝试将 json 响应映射到我的模型。问题是,json return 一个数组的倍数 Shapes,Shape 是一个抽象的 class,所以它可以是 Square,Circle 等。每个 shape 都有自己指定的模型,所以不同的领域。如何将这个 Shape 数组映射到模型?
Web 服务 json 响应
{
"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;
}
摘要class:
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...
}
正方形:
public class Square {
@SerializedName("code") private int code;
@SerializedName("size") private int size;
// + getters...
}
您可以实现一个像工厂一样的自定义形状反序列化器。基于形状对象的键,您可以将其反序列化为相应的类型。
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 名称完全匹配,您可以直接使用 Class.forName
(您需要首先将密钥大写)。
另请注意:
- 你可以将
code
属性 移动到摘要Shape
class 中,如果它出现在每个子classes - 我假设您有一个且只有一个形状与键关联。如果您可以在与键 "circle" 关联的同一个 JsonObject 中有两个圆圈,您将需要更复杂的逻辑来解析它。如果不是这种情况(尽管 RFC 不建议使用具有相同键的不同键值对),它应该可以正常工作。