本文的出現是為了解決以下需求:使用Gson對json數組進行解析,但是數組里面元素的類型是多種的。數據如下:
{"list":[{
"type":0,
"data":{
"id":1,
"color":"red"
}
},{
"type":1,
"data":{
"id":1,
"name":"case"
}
}]}
可能你會說data中的對應的實體可以包括所有data中的字段就可以了,那么你采用這種方法我只能說太low了,不是不可以這么做,要是遇到很龐大的實體類,那么你會發現里面甚至需要上百個字段。我們這里舉例只是為了說明方便,所以給的數據都比較簡單,重在思路。
如何設計
為了解決上面的問題,那么我想到的是三種處理方法:
方法一:也就是上文所說的那種很low的做法咯,把所有的字段都放在一個實體類中。
這種方法對應初級選手確實感覺還不錯,不用思考太多就可以解決解析問題,不過這不是我們程序員應該滿足的。(上文已經吐槽過了)
方法二:對於數組中data數據結構不同,那么字段就不統一命名成data,而是根據實的結構服務器返回不同的字段,如:colorEntity,userEntity。那么對應的實體類應該是這樣的形式:
public class ListEntity{ int type; User userEntity; Color colorEntity; }
缺點很明顯。①沒有統一的數據字段;②添加新類型,服務器加字段需要檢查新加字段名不能和已有的字段名重復(如何已有的類型多,那么服務器工作就需要更細心);③Gson對應的解析實體類會因為list結構豐富而變得很龐大,因為每種類型都需要一個對應的字段。
當然優點也很明顯。簡單易懂,遇到問題很容易處理,可讀性強。
此方法前提條件就是需要服務器配合,要是你用現成的服務器那么這種方法完全就不用考慮了。
方法三:根據不同的type返回不同的data值(也就是現在示例中的樣子),添加Gson解析器來完成解析(可能很多童鞋對此感到很陌生,其實很簡單)。
這種方法就需要對Gson的解析有一定了解。本文也是重點解說如何設計這種解析並且給出demo,下文就是對此方法進行講解。
1、Gson對應的實體類
首先我們知道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); } } } }
看完整個步驟,最核心的就是自定義解析器,根據自己的需求進行解析。以上就完整解說了方式三的具體操作流程。如果讀者有更好的方式解析希望可以分享一下。
如果文中有任何疑問或者不妥之處歡迎留言交流。在此也留下QQ群311536202,歡迎交流。
