Gson解析数组多类型元素

why used gson?

Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of.

There are a few open-source projects that can convert Java objects to JSON. However, most of them require that you place Java annotations in your classes; something that you can not do if you do not have access to the source-code. Most also do not fully support the use of Java Generics. Gson considers both of these as very important design goals.

Gson Goals

    Provide simple toJson() and fromJson() methods to convert Java objects to JSON and vice-versa
    Allow pre-existing unmodifiable objects to be converted to and from JSON
    Extensive support of Java Generics
    Allow custom representations for objects
    Support arbitrarily complex objects (with deep inheritance hierarchies and extensive use of generic types) 

json是一种轻量级的数据交互格式,json与xml有相同的特性,易于人编写、阅读和机器的解析,而
gson是谷歌提供的一种json解决方案,其内部对json做了很好的封装,
例如:json不支持对关联查询,而gson则可以支持更深层次关联查询;
同时gson的使用比json更加简单。


本文的出现是为了解决以下需求:使用Gsonjson数组进行解析,但是数组里面元素的类型是多种的。数据如下:

复制代码
{"list":[{
    "type":0,
    "data":{
        "id":1,
        "color":"red"
    }
},{
    "type":1,
    "data":{
        "id":1,
        "name":"case"
    }
}]}
复制代码

可能你会说data中的对应的实体可以包括所有data中的字段就可以了,那么你采用这种方法我只能说太low了,不是不可以这么做,要是遇到很庞大的实体类,那么你会发现里面甚至需要上百个字段。我们这里举例只是为了说明方便,所以给的数据都比较简单,重在思路。

 

如何设计

为了解决上面的问题,那么我想到的是三种处理方法:

方法一:也就是上文所说的那种很low的做法咯,把所有的字段都放在一个实体类中。

这种方法对应初级选手确实感觉还不错,不用思考太多就可以解决解析问题,不过这不是我们程序员应该满足的。(上文已经吐槽过了) 

方法二:对于数组中data数据结构不同,那么字段就不统一命名成data,而是根据实的结构服务器返回不同的字段,如:colorEntityuserEntity。那么对应的实体类应该是这样的形式:

复制代码
public class ListEntity{

  int type;

  User userEntity;

  Color colorEntity;

}
复制代码

缺点很明显。①没有统一的数据字段;②添加新类型,服务器加字段需要检查新加字段名不能和已有的字段名重复(如何已有的类型多,那么服务器工作就需要更细心);③Gson对应的解析实体类会因为list结构丰富而变得很庞大,因为每种类型都需要一个对应的字段。 

当然优点也很明显。简单易懂,遇到问题很容易处理,可读性强。

此方法前提条件就是需要服务器配合,要是你用现成的服务器那么这种方法完全就不用考虑了。 

方法三:根据不同的type返回不同的data值(也就是现在示例中的样子),添加Gson解析器来完成解析(可能很多童鞋对此感到很陌生,其实很简单)。

这种方法就需要对Gson的解析有一定了解。本文也是重点解说如何设计这种解析并且给出demo,下文就是对此方法进行讲解。

 

1Gson对应的实体类

首先我们知道ArrayList里面的元素都是相同的类型,那么如何才能使用不同的类型呢?当然就是集合里面的元素使用一个基类,然后具体的实体类都继承这个基类。示例:

我们有3个类:

 这个类就是刚刚说的基类,所有list字段里面对应实体的基类

public class TypeSuper {

}

list字段里面对应的其中一种类型TypeA

复制代码
public class TypeA extends TypeSuper {

public int id;

public String name;

 

public TypeA(int id, String name) {

super();

this.id = id;

this.name = name;

}

}
复制代码

 

list字段里面对应的其中另一种类型TypeB

复制代码
public class TypeB extends TypeSuper { 

  public int id;

  public String color;

 
  public TypeB(int id, String color) {

    super();

    this.id = id;

    this.color = color;

  }

}
 
复制代码

 

Gson对应的实体类TypeResult

public class TypeResult {

List<TypeSuper> data = new ArrayList<TypeSuper>();

}

 

 

2、Gson反序列化

根据json字符串进行解析,示例代码如下:

Gson解析器TypeResultDeserializer 

复制代码
public class TypeResultDeserializer implements JsonDeserializer<TypeResult> {

    @Override
    public TypeResult deserialize(JsonElement arg0, Type arg1,
            JsonDeserializationContext arg2) throws JsonParseException {
        JsonObject obj = arg0.getAsJsonObject();
        JsonArray asJsonArray = obj.get("list").getAsJsonArray();
        TypeResult result = new TypeResult();
        for (JsonElement jsonElement : asJsonArray) {
            JsonObject jsonOb = jsonElement.getAsJsonObject();
            int type = jsonOb.get("type").getAsInt();
            if (type == 0) {
                JsonObject child = jsonOb.get("data").getAsJsonObject();
                int id = child.get("id").getAsInt();
                String name = child.get("color").getAsString();
                result.data.add(new TypeB(id, name));
            } else if(type == 1) {
                JsonObject child = jsonOb.get("data").getAsJsonObject();
                int id = child.get("id").getAsInt();
                String name = child.get("color").getAsString();
                result.data.add(new TypeA(id, name));
            }
        }
        return result;
    }
}
复制代码

 


3、使用解析器解析Demo

复制代码
public class Test {

    public static void main(String[] args) {
        GsonBuilder gsonb = new GsonBuilder();
        gsonb.registerTypeAdapter(TypeResult.class, new TypeResultDeserializer());
        gsonb.serializeNulls();
        Gson gson = gsonb.create();
        String json = "{\"list\":[{" + "\"type\":0," + "\"data\":{"
                + "\"id\":1," + "\"color\":\"red\"" + "}" + "},{"
                + "\"type\":1," + "\"data\":{" + "\"id\":1,"
                + "\"color\":\"case\"" + "}" + "}]}";
        List<TypeSuper> item = gson.fromJson(json, TypeResult.class).data;
        for (TypeSuper baseItem : item) {
            if (baseItem instanceof TypeA) {
                System.out.println(((TypeA) baseItem).name);
            } else if (baseItem instanceof TypeB) {
                System.out.println(((TypeB) baseItem).color);
            }
        }
    }
}
复制代码

 

看完整个步骤,最核心的就是自定义解析器,根据自己的需求进行解析。以上就完整解说了方式三的具体操作流程。如果读者有更好的方式解析希望可以分享一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值