【前言】最近項(xiàng)目中對數(shù)據(jù)的解析都使用了Gson,艸蛋的是每次都要手寫JavaBean對象很麻煩入愧。抱著能否簡化的心態(tài)閱讀了Gson的部分源碼贬堵。發(fā)現(xiàn)很多以前沒有注意到的知識點(diǎn)划纽。
寫在前面的話
Gson是一個(gè)Java庫拗窃,可用于將Java對象轉(zhuǎn)換為JSON表示瞎领。它也可以用來將JSON字符串轉(zhuǎn)換為等效的Java對象。 Gson可以使用任意Java對象随夸,包括您沒有源代碼的預(yù)先存在的對象九默。
如何生成Json
JsonObject jsonObject = new JsonObject();
JsonObject jsonArray = new JsonObject();
//addProperty():產(chǎn)生JsonObject
jsonObject.addProperty("testString","7c");
jsonObject.addProperty("testInt",7);
jsonObject.addProperty("testBoolean",true);
jsonObject.addProperty("testCharater","7c");
jsonArray.addProperty("testStringArray","7c");
jsonArray.addProperty("testIntArray",7);
jsonArray.addProperty("testBooleanArray",true);
jsonObject.add("JsonElement",jsonArray);
System.out.println(jsonObject.toString());
//Json結(jié)構(gòu)
{
"JsonElement": {
"testBooleanArray": true,
"testIntArray": 7,
"testStringArray": "7c"
},
"testBoolean": true,
"testCharater": "7c",
"testInt": 7,
"testString": "7c"
}
手動解析Json
try {
JSONObject originJson = new JSONObject(json);
ManualresolutionBean manualresolutionBean = new ManualresolutionBean();
boolean success = originJson.optBoolean("success");
int failCode = originJson.optInt("failCode");
JSONArray data = originJson.optJSONArray("data");
List<ManualresolutionBean.JsonList> jsonLists = new ArrayList();
manualresolutionBean.setFailCode(failCode);
manualresolutionBean.setSuccess(success);
for (int i = 0 ; i < data.length() ; i ++){
JSONObject jsonObject1 = data.getJSONObject(i);
JsonList jsonList = new JsonList();
String check = jsonObject1.optString("check");
String id = jsonObject1.optString("id");
int isPoor = jsonObject1.optInt("isPoor");
String level = jsonObject1.optString("level");
String model = jsonObject1.optString("model");
String name = jsonObject1.optString("name");
String pid = jsonObject1.optString("pid");
String sort = jsonObject1.optString("sort");
String supportPoor = jsonObject1.optString("supportPoor");
jsonList.setCheck(check);
jsonList.setId(id);
jsonList.setIsPoor(isPoor);
jsonList.setLevel(level);
jsonList.setModel(model);
jsonList.setName(name);
jsonList.setPid(pid);
jsonList.setSort(sort);
jsonList.setSupportPoor(supportPoor);
jsonLists.add(jsonList);
}
manualresolutionBean.setList(jsonLists);
} catch (JSONException e) {
e.printStackTrace();
}
}
【注意】
1.藍(lán)色標(biāo)記部分手動解析的時(shí)候充當(dāng)JSONObject;【】充當(dāng)JSONArray宾毒。
2.如果你放在main函數(shù)中執(zhí)行會報(bào) java.lang.RuntimeException: Stub!驼修。這是因?yàn)槟阍贘ava中使用Android包出錯。
通過構(gòu)造器來創(chuàng)建Gson
new Gson()是我們?nèi)粘i_發(fā)中經(jīng)常用來解析數(shù)據(jù)的方式诈铛。熟悉的人員請繞過這部分乙各。
String jsonArray = "[\"U\",\"A\",\"R\",\"T\"]";
Gson gson = new Gson();
//json與數(shù)組的轉(zhuǎn)換
//json轉(zhuǎn)換為數(shù)組
String[] strings = gson.fromJson(jsonArray, String[].class);
for (String string : strings){
System.out.println(string);
}
//數(shù)組轉(zhuǎn)換為json
String s = gson.toJson(strings);
System.out.println(s);
System.out.println("=================================");
//json轉(zhuǎn)換為List
//new TypeToken<List<String>>(){}.getType()這里為什么需要一個(gè){},查看TypeToken源碼可以發(fā)現(xiàn)
//這樣一段話TypeToken<List<String>> list = new TypeToken<List<String>>() {};
List<String> list = gson.fromJson(jsonArray, new TypeToken<List<String>>() {
}.getType());
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String next = iterator.next();
System.out.println(next);
}
//List轉(zhuǎn)換為json
String listJson = gson.toJson(list,new TypeToken<List<String>>() {
}.getType());
System.out.println(listJson);
Gson用法進(jìn)階
屬性重命名
- 場景:服務(wù)端返回的字段名癌瘾,與我們本地的字段名有出入觅丰。
- 原理及用法:@SerializedName 指示此成員的注釋應(yīng)該以提供的名稱值作為其字段名稱序列化為JSON饵溅。
@SerializedName("name") String a;
@SerializedName(value="name1", alternate={"name2", "name3"}) String b;
@SerializedName(value ="name",alternate = {"userName","Name","Kobe"})
public String name;
String json = "{\"name\": \"Uart\"}";
String json1 = "{\"userName\": \"Uart\"}";
String json2 = "{\"Name\": \"Uart\"}";
String json3 = "{\"Kobe\": \"Uart\"}";
Gson gson = new Gson();
User user = gson.fromJson(json,new TypeToken<User>(){}.getType());
User user1 = gson.fromJson(json1,new TypeToken<User>(){}.getType());
User user2 = gson.fromJson(json2,new TypeToken<User>(){}.getType());
User user3 = gson.fromJson(json3,new TypeToken<User>(){}.getType());
user.toString();
user1.toString();
user2.toString();
user3.toString();
字段過濾
基于@Expose注解
- 原理:指示此成員的注釋應(yīng)公開給JSON序列化或反序列化妨退。
- 注意 :此注釋要生效必須調(diào)用GsonBuilder的excludeFieldsWithoutExposeAnnotation()方法。
- 用法:
@Expose private String firstName;
@Expose(serialize = false) private String lastName;
@Expose (serialize = false, deserialize = false) private String emailAddress;
private String password;
@Expose(serialize = true, deserialize = true) //序列化和反序列化都生效
private String a;
@Expose(serialize = false, deserialize = true) //序列化時(shí)不生效蜕企,反序列化時(shí)生效
private String b;
@Expose(serialize = true, deserialize = false) //序列化時(shí)生效咬荷,反序列化時(shí)不生效
private String c;
@Expose(serialize = false, deserialize = false) //序列化和反序列化都不生效,和不寫注解一樣
private String d;
private String e;
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
FilterBean filterBean = new FilterBean("A", "B", "C", "D", "E");
//序列化
System.out.println(gson.toJson(filterBean));
//反序列化
String json = "{\"a\":\"A\",\"b\":\"B\",\"c\":\"C\",\"d\":\"D\",\"e\":\"E\"}";
FilterBean filterBean1 = gson.fromJson(json, FilterBean.class);
System.out.println(filterBean1.toString());
//輸出結(jié)果
{"a":"A","c":"C"}
FilterBean{a='A', b='B', c='null', d='null', e='null'}
基于版本
- 原理:@Since自成員或類型出現(xiàn)以來表示版本號的注釋轻掩。
@Until表示直到成員或類型應(yīng)該存在的版本號的注釋幸乒。
此注釋對于管理Web服務(wù)的Json類的版本控制非常有用。 - 注意:此注釋要生效必須調(diào)用GsonBuilder的setVersion(double)方法唇牧。
- 用法:
@Since(1.0) private String emailAddress罕扎;
@Until(1.1) private String emailAddress;
@Since(1.3)
private String a;
@Until(1.9)
private String b;
@Since(1.5)
private String c;
@Until(1.2)
private String d;
private String e;
Gson gson = new GsonBuilder().setVersion(1.3).create();
FilterBean filterBean = new FilterBean("A", "B", "C", "D", "E");
//序列化
System.out.println(gson.toJson(filterBean));
//反序列化
String json = "{\"a\":\"A\",\"b\":\"B\",\"c\":\"C\",\"d\":\"D\",\"e\":\"E\"}";
FilterBean filterBean1 = gson.fromJson(json, FilterBean.class);
System.out.println(filterBean1.toString());
//輸出結(jié)果
{"a":"A","b":"B","e":"E"}
FilterBean{a='A', b='B', c='null', d='null', e='E'}
基于訪問修飾符
- 原理:excludeFieldsWithModifiers()方法丐重,配置Gson以排除所有具有指定修飾符的類字段腔召。默認(rèn),Gson將排除所有標(biāo)記為瞬態(tài)(transient)或靜態(tài)(static)的字段扮惦。此方法將覆蓋該行為臀蛛。
public String publicField = "public";
protected String protectedField = "protected";
private String privateField = "private";
String defaultField = "default";
final String finalField = "final";
static String staticField = "static";
Gson gson2 = new GsonBuilder().excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.PUBLIC).create();
ModifierBean modifierBean = new ModifierBean();
System.out.println(gson2.toJson(modifierBean));
//輸出結(jié)果
{"protectedField":"protected","defaultField":"default","finalField":"final","staticField":"static"}
基于策略
- 原理:GsonBuilder 類包含 setExclusionStrategies(ExclusionStrategy... strategies)方法用于傳入不定長參數(shù)的策略方法,用于直接排除指定字段名或者指定字段類型。
private String stringField;
private int intField;
private double doubleField;
public StrategiesBean(String stringField, int intField, double doubleField) {
this.stringField = stringField;
this.intField = intField;
this.doubleField = doubleField;
}
Gson gson3 = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes f) {
//排除指定字段名
return f.getName().equals("stringField");
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
//排除指定字段類型
return clazz.getName().equals(double.class.getName()); }}).create();
StrategiesBean strategies = new StrategiesBean("stringField", 111, 11.22);
System.out.println();
System.out.println(gson3.toJson(strategies));
String json2 = "{\"stringField\":\"stringField\",\"intField\":111,\"doubleField\":11.22}";
strategies = gson3.fromJson(json2, StrategiesBean.class);
System.out.println();
System.out.println(strategies);
//輸出結(jié)果
{"intField":111}
Strategies{stringField='null', intField=111, doubleField=0.0}
感興趣的小伙伴可以研究一下setFieldNamingStrategy()浊仆、addDeserializationExclusionStrategy()客峭、addSerializationExclusionStrategy()這三種方法
自定義配置
輸出null
對于 Gson 而言,在序列化時(shí)如果某個(gè)屬性值為 null 的話抡柿,那么在序列化時(shí)該字段不會參與進(jìn)來舔琅,如果想要顯示輸出該字段的話,可以通過 GsonBuilder 進(jìn)行配置洲劣。
Gson gson3 = new GsonBuilder()
.serializeNulls()
.create();
StrategiesBean strategies = new StrategiesBean(null, 111, 11.22);
System.out.println();
System.out.println(gson3.toJson(strategies));
//輸出結(jié)果
{"stringField":null,"intField":111,"doubleField":11.22}
格式化輸出Json
Gson gson3 = new GsonBuilder()
.serializeNulls()
.setPrettyPrinting()//格式化輸出
.create();
StrategiesBean strategies = new StrategiesBean(null, 111, 11.22);
System.out.println();
System.out.println(gson3.toJson(strategies));
//輸出結(jié)果
{
"stringField": null,
"intField": 111,
"doubleField": 11.22
}
TypeAdapter
- 作用:將Java對象與JSON進(jìn)行轉(zhuǎn)換搏明。默認(rèn)情況下,Gson使用其內(nèi)置類型將應(yīng)用程序類轉(zhuǎn)換為JSON適配器闪檬。如果Gson的默認(rèn)JSON轉(zhuǎn)換不適合某種類型星著,擴(kuò)展此類以定制轉(zhuǎn)換。
序列化交換位置
@Override
public void write(JsonWriter out, UartBean value) throws IOException {
//序列化過程
if(value == null) {
out.nullValue();
return;
}
String name = value.getName();
int age = value.getAge();
value.setName(age + "");
value.setAge(Integer.valueOf(name));
out.value(value.getName());
out.value(value.getAge());
}
@Override
public UartBean read(JsonReader in) throws IOException {
//反序列化過程
if(in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
in.beginObject();
UartBean uartBean = new UartBean();
while(in.hasNext()) {
switch (in.nextName()) {
case "name" :
uartBean.setName(in.nextString());
break;
case "age":
uartBean.setAge(in.nextInt());
break;
}
}
in.endObject();
return uartBean;
}
Gson gson4 = new GsonBuilder().registerTypeAdapter(UartBean.class, new UartAdapter()).create();
UartBean uartBean = new UartBean("10", 20);
System.out.println(gson4.toJson(uartBean));
String json4 = "{\"name\":\"10\",\"age\":24}";
UartBean bean = gson4.fromJson(json4, UartBean.class);
System.out.println();
System.out.println(bean);
//輸出結(jié)果
"20" 10
UartBean{name='10', age=24}
JsonSerializer 和 JsonDeserializer是TypeAdapter提供的專門針對序列化和反序列化的接口粗悯。感興趣的朋友可以自行了解一下虚循。
更新
"156": "42F7B18E9C12ACFDC1B9",
"156": "3247F56244FDE",
針對上述json字符串如何解析?
stationNameInfoList = new ArrayList<EquivalentStationNameInfo>();
Iterator<String> keys = object.keys();
while (keys.hasNext()) {
EquivalentStationNameInfo equivalentStationNameInfo = new EquivalentStationNameInfo();
String next = keys.next();
equivalentStationNameInfo.setStationName(next);
equivalentStationNameInfo.setStationId(object.optString(next));
for (EquivalentHourInfo info : equivalentHourInfoList) {
if (info.getStationName().equals(next)) {
stationNameInfoList.add(equivalentStationNameInfo);
}
}
}