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解析的过程,类型的匹配等都没有说起,感兴趣的能够阅读其源码。

相关文章
相关标签/搜索