Gson使用教程

Gson是Google開源的一個JSON庫,被普遍應用在Android開發中。java

說明:如下全部的用法都基於Account類!git

public class Account {

	private String uid;
	private String userName;
	private String password;
	private String telNumber;
	
	public Account(String uid, String userName, String telNumber) {
		this.uid = uid;
		this.userName = userName;
		this.telNumber = telNumber;
	}
	
	@Override
	public String toString() {
		return "Account [uid=" + uid + ", userName=" + userName + ", password=" + password + ", telNumber=" + telNumber
				+ "]";
	}
}
複製代碼

基礎用法

集成Gson

dependencies {
  implementation 'com.google.code.gson:gson:2.8.5'
}
複製代碼

建立Gson對象

Gson提供了兩種建立對象的方式:github

  1. 直接使用Gson構造方法建立;json

    Gson gson = new Gson();數組

  2. 使用GsonBuilder建立;服務器

    Gson gson = new GsonBuilder().create();ide

相比直接使用構造方法,GsonBuilder建立的方式更靈活,由於它支持對Gson的配置。ui

將對象轉換爲JSON

Account account = new Account("00001", "Freeman", "13000000000");
System.out.println(gson.toJson(account));
	
ArrayList<Account> accountList = new ArrayList<Account>();
accountList.add(account);
System.out.println(gson.toJson(accountList));
複製代碼

結果:this

{"uid":"00001","userName":"Freeman","telNumber":"13000000000"}
[{"uid":"00001","userName":"Freeman","telNumber":"13000000000"}]
複製代碼

將JSON轉換爲對象

因爲Java中的泛型存在類型擦除的問題,因此使用泛型接收JSON解析結果的時候有點特殊。google

普通對象解析
String json = "{\"uid\":\"00001\",\"userName\":\"Freeman\",\"telNumber\":\"13000000000\"}";
Account receiveAccount = gson.fromJson(json, Account.class);
System.out.println(receiveAccount.toString());
複製代碼

結果:

Account [uid=00001, userName=Freeman, password=null, telNumber=13000000000]
複製代碼
泛型對象解析
String listJson = "[{\"uid\":\"00001\",\"userName\":\"Freeman\",\"telNumber\":\"13000000000\"}]";
List receiveAccountList = gson.fromJson(listJson, new TypeToken<List<Account>>(){}.getType());
System.out.println("receiveAccountList size = " + receiveAccountList.size());
複製代碼

結果:

receiveAccountList size = 1
複製代碼

字段複用

在開發中有時會對Bean對象進行復用,但可能有幾個字段的命名和當前的對象不一致,這樣在解析JSON的時候就不能正確賦值。Gson提供了字段複用功能——@SerializedName,可用一個字段接收不一樣的JSON字段。

// json字符串中手機號的字段爲phone或telNumber時均可正確解析
@SerializedName("phone")
private String telNumber;

// json字符串中用戶名的字段爲userName、user_name、uname或u_name時均可正確解析
@SerializedName(value = "userName", alternate = {"user_name", "uname", "u_name"})
private String userName;
複製代碼

Gson配置

除了以上用法,Gson還提供了豐富的配置選項,包括:空值過濾,字段命名規則,自定義解析器,自定義序列化/反序列化等。

空值問題

Gson默認狀況下會過濾空值字段,但有時在提交數據給後臺時,即使字段爲空,也須要傳給後臺,此時可經過GsonBuilder進行配置。

gson = new GsonBuilder().serializeNulls().create();
Account account = new Account("00001", "Freeman", "13000000000");
System.out.println(gson.toJson(account));
複製代碼

結果:

{"uid":"00001","userName":"Freeman","password":null,"phone":"13000000000"}
複製代碼

從結果能夠看出,password字段被輸出了,而前面直接建立Gson轉換的時候沒有輸出password字段。

字段命名轉換規則

由於不一樣的語言使用不一樣的命名規則,這會出現爲了正確解析JSON字符串,而使用不符合命名規則的字段名。如PHP使用小寫字母下劃線分割的命名方式,而Java使用駱駝命名的方式,這樣Android程序在接收JSON字符串的時候就須要使用小寫字母下劃線分割的命名方式,然而這並不符合Java的命名規範。爲了解決這個問題,Gson提供了豐富的字段命名規則。

// 默認的字段轉換規則,字段名不變
FieldNamingPolicy.IDENTITY()

// 將json中的字段名轉換爲首字母大寫的格式
FieldNamingPolicy.UPPER_CAMEL_CASE()
如:"user_name" -> "UserName"

// 將json中的字段名轉換爲首字母大寫,單詞之間以空格分割的格式
FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES()
如:"user_name" -> "User Name"

// 將json中的字段名轉換爲小寫字母,單詞之間如下劃線分割的格式
FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES()
如:"UserName" -> "user_name"

// 將json中的字段名轉換爲小寫字母,單詞之間以分隔線分割的格式
FieldNamingPolicy.LOWER_CASE_WITH_DASHES()
如:"UserName" -> "user-name"
複製代碼

因此對於服務器是PHP的狀況,Android端可以使用FieldNamingPolicy.UPPER_CAMEL_CASE轉換規則。

Gson gson = new GsonBuilder()
	.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
	.create();
複製代碼

固然,若是上面幾種命名轉換規則不知足需求,也可自定義命名轉換規則,只須要實現FieldNamingStrategy接口,並完善translateName方法便可。須要注意的是,命名轉換規則會同時被應用於序列化和反發序列化,因此在將對象轉換爲JSON(序列化)傳給後臺時須要注意。

字段過濾

默認狀況下,Gson將對象轉換爲JSON時,會將全部非null字段進行轉換,但有時爲了業務需求,一般會添加一些狀態字段,如表示item選中狀態的isSelected,這些字段一般不但願被轉換。Gson提供了多種過濾方式,這裏說說兩種最經常使用的。

  1. 經過修飾符過濾

    Gson gson = new GsonBuilder() // 過濾transient或static修飾的字段, .excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.STATIC) .create();

  2. 自定義過濾規則

經過實現setExclusionStrategies接口來定義過濾規則:

ExclusionStrategy strategy = new ExclusionStrategy() {

	@Override
	public boolean shouldSkipClass(Class<?> arg0) {
		// 過濾指定的類
		return false;
	}

	@Override
	public boolean shouldSkipField(FieldAttributes arg0) {
		// 過濾指定的字段
		return false;
	}
	
};

Gson gson = new GsonBuilder()
	// 過濾規則同時適用於序列化/反序列化
	.setExclusionStrategies(strategy)
	// 過濾規則只適用於序列化
	.addSerializationExclusionStrategy(strategy)
	// 過濾規則只適用於反序列化
	.addDeserializationExclusionStrategy(strategy)
	.create();
複製代碼

字段容錯性

字段容錯性主要表如今字段的類型不匹配,好比接收的字段是整型,返回的倒是字符串或者null, 這種狀況狀況直接使用String接收整型倒能夠解決,但對於接收類型是數組,返回的確是對象的狀況,卻不能直接使用類型兼容來處理。

雖然這些狀況都是由於後臺數據格式的問題,但對用戶最直觀的感覺是APP閃退了。因此咱們須要對JSON的解析過程作必定的兼容處理,以防出現異常數據時致使APP閃退。

開發中常常遇到的類型兼容問題彙總:

  1. 使用Number類型接收,返回了String或空值(Gson已處理此類問題);
  2. 使用數組接收,返回了對象類型;

Gson提供了多種序列化/反序列化方式,因爲這裏咱們只作JSON解析(即反序列化)的兼容處理,因此直接實現JsonDeserializer接口便可。

// 爲數組類型自定義反序列化適配器
JsonDeserializer<List<?>> listDeserial = new JsonDeserializer<List<?>>() {
	@Override
	public List<?> deserialize(JsonElement arg0, java.lang.reflect.Type arg1,
			JsonDeserializationContext arg2) throws JsonParseException {
		if (arg0.isJsonArray()) {
			JsonArray jsonArray = arg0.getAsJsonArray();
			if (jsonArray.size() == 0) {
				return Collections.EMPTY_LIST;
			}
			List<?> resultList = new ArrayList<>();
			for (JsonElement element : jsonArray) {
				resultList.add(arg2.deserialize(element, arg1));
			}
			return resultList;
		} else {
			return Collections.EMPTY_LIST;
		}
	}
};

Gson gson = new GsonBuilder()
    // 註冊自定義的反序列化適配器
	.registerTypeHierarchyAdapter(List.class, listDeserial)
	.create();
複製代碼

Gson經常使用配置總結

gson = new GsonBuilder()
    // 不過濾空值
    .serializeNulls()
    // 設置字段命名轉換規則
    .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
    // 設置字段序列化/反序列化過濾規則
    .excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.STATIC)
    // 自定義類型解析器,提升Gson容錯性
    .registerTypeHierarchyAdapter(List.class, listDeserial)
    .create();
複製代碼

總結

以上只是使用Gson過程當中的一些總結,其中涉及的的不少細節,如JSON解析的過程,類型的匹配等都沒有說起,感興趣的能夠閱讀其源碼。

相關文章
相關標籤/搜索