Gson 中解决 json 反序列化时相同属性对应不同类型的值的问题

Gson 中解决 json 反序列化时相同属性对应不同类型的值的问题

在实际开发中,我们很容易会遇到一些 json 字符串,在不同的 json 中,相同的字段(或者说是属性)下会有不同的数据类型。如以下例子:

{
	"group_by":[
		{
			"name": "time",
			"group_count": "1",
			"range_size": {
				"value": "1",
				"unit": "seconds"
			}
		},
		{
			"name": "value",
			"range_size": "1"
		}
	]
}

在这个例子中,group_by下是一个数列, 然而这个数列里的每一个值里都包含range_size这个字段。在"name": "time"所在的这个映射(字典)下的range_size对应的值为一个映射(字典),而在"name": "value"所在的这个映射(字典)下的range_size对应的值为一个字符串。

针对这一种问题,我们通过使用gson大致分为两类方法:

  • 方法一:自己实现gson的反序列化操作类并注册到gson里
  • 方法二:借助gson,使用类似DOM的方法来解析json字符串

场景准备

  1. 构造json字符串
private static String json = "{\"group_by\":["
      + "{\"name\": \"time\",\"group_count\": \"1\",\"range_size\": {\"value\": \"1\",\"unit\": \"seconds\"}},"
      + "{\"name\": \"value\",\"range_size\": \"1\"}]}";
  1. 定义GroupBy的类型
public enum GroupByType {
  TIME,
  VALUE
}
  1. 实现GroupBy的父类及其不同类型的子类(getter、setter及构造方法均已隐去)
public abstract class GroupBy {

  private GroupByType type;

}
public class GroupByTime extends GroupBy {

  @SerializedName("group_count")
  private String groupCount;

  @SerializedName("range_size")
  private TimeUnit rangeSize;

  public GroupByTime() {
    super(GroupByType.TIME);
  }

  public void setRangeSize(String value, String unit) {
    this.rangeSize = new TimeUnit();
    rangeSize.setValue(value);
    rangeSize.setUnit(unit);
  }

  @Override
  public String toString() {
    return "name: time\n"
        + "\tgroup_count: " + groupCount + "\n"
        + "\trange_size: " + rangeSize.getValue() + " " + rangeSize.getUnit();
  }

  class TimeUnit {
    private String value;
    private String unit;
  }

}
public class GroupByValue extends GroupBy {

  @SerializedName("range_size")
  private String rangeSize;

  public GroupByValue() {
    super(GroupByType.VALUE);
  }

  @Override
  public String toString() {
    return "name: value\n"
        + "\trange_size: " + rangeSize;
  }
}
  1. 到此,场景准备已结束

反序列化操作类法

  1. 实现反序列化生成的结果类ParseResult
public class ParseResult {

  @SerializedName("group_by")
  private List<GroupBy> groupBy;

  public List<GroupBy> getGroupBy() {
    if (groupBy == null)
      groupBy = new LinkedList<>();
    return groupBy;
  }

  public void addGroupBy(GroupBy groupBy) {
    if (this.groupBy == null)
      this.groupBy = new LinkedList<>();
    this.groupBy.add(groupBy);
  }

}
  1. 完成对结果类的反序列化操作类的实现
public class GroupByDeserializer implements JsonDeserializer<ParseResult> {

  @Override
  public ParseResult deserialize(JsonElement jsonElement, Type type,
      JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {

    JsonArray jsonArray = jsonElement.getAsJsonObject().get("group_by").getAsJsonArray();

    Map<String, GroupByType> mapping = new HashMap<>();
    mapping.put("time", GroupByType.TIME);
    mapping.put("value", GroupByType.VALUE);

    ParseResult result = new ParseResult();

    for (JsonElement element : jsonArray) {
      JsonObject jsonObject = element.getAsJsonObject();
      switch (mapping.get(jsonObject.get("name").getAsString())) {
        case TIME:
          GroupByTime groupByTime = new GroupByTime();
          groupByTime.setGroupCount(jsonObject.get("group_count").getAsString());
          JsonObject temp = jsonObject.getAsJsonObject("range_size");
          groupByTime.setRangeSize(temp.get("value").getAsString(), temp.get("unit").getAsString());
          result.addGroupBy(groupByTime);
          break;
        case VALUE:
          GroupByValue groupByValue = new GroupByValue();
          groupByValue.setRangeSize(jsonObject.get("range_size").getAsString());
          result.addGroupBy(groupByValue);
          break;
        default:
          break;
      }
    }

    return result;
  }
}
  1. 把写好的反翻译类注册到GsonBuilder中
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(ParseResult.class, new GroupByDeserializer());
  1. 反序列化json
Gson gson = gsonBuilder.create();
ParseResult result = gson.fromJson(json, ParseResult.class);
  1. 打印结果
System.out.println("Method 1 ==============================================");
result.getGroupBy().forEach(System.out::println);
System.out.println("=======================================================\n\n\n");
  1. 结果
Method 1 ==============================================
name: time
	group_count: 1
	range_size: 1 seconds
name: value
	range_size: 1
=======================================================

类DOM操作法

相信看到这里的大家都不可能不知道什么是DOM了,不过不知道也不影响我们接下来的实现,不过我还是强烈推荐各位读者,一定要去学习。
另外,这种方法比较简单,就不加过多的解释了,直接上代码吧。

  1. 建立Parser类
public class PrimitiveParser {

  private final String jsonStr;
  private Map<String, GroupByType> mapping;

  public PrimitiveParser(String jsonStr) {
    this.jsonStr = jsonStr;

    mapping = new HashMap<>();
    mapping.put("time", GroupByType.TIME);
    mapping.put("value", GroupByType.VALUE);
  }

  public List<GroupBy> parse() {
    JsonParser parser = new JsonParser();
    JsonObject obj = parser.parse(jsonStr).getAsJsonObject();

    JsonArray array = obj.getAsJsonArray("group_by");

    List<GroupBy> list = new LinkedList<>();

    for (JsonElement element : array) {
      JsonObject jsonObject = element.getAsJsonObject();
      switch (mapping.get(jsonObject.get("name").getAsString())) {
        case TIME:
          GroupByTime groupByTime = new GroupByTime();
          groupByTime.setGroupCount(jsonObject.get("group_count").getAsString());
          JsonObject temp = jsonObject.getAsJsonObject("range_size");
          groupByTime.setRangeSize(temp.get("value").getAsString(), temp.get("unit").getAsString());
          list.add(groupByTime);
          break;
        case VALUE:
          GroupByValue groupByValue = new GroupByValue();
          groupByValue.setRangeSize(jsonObject.get("range_size").getAsString());
          list.add(groupByValue);
          break;
        default:
          break;
      }
    }
    return list;
  }

}
  1. 解析
PrimitiveParser parser = new PrimitiveParser(json);
List<GroupBy> list = parser.parse();
  1. 打印结果
System.out.println("Method 2 ==============================================");
list.forEach(System.out::println);
System.out.println("=======================================================\n\n\n");
  1. 结果
Method 2 ==============================================
name: time
	group_count: 1
	range_size: 1 seconds
name: value
	range_size: 1
=======================================================

相关资源

相关的代码我已上传CSDN,有需要的兄弟们可以直接去下载
https://download.csdn.net/download/zifung_yip/11099832

你可能感兴趣的:(Java)