【Gson】简介 文档 基本使用 示例

时间:2021-09-14 13:54:27

简介

new TypeToken<List<Person>>() {}.getType()
compile 'com.google.code.gson:gson:2.8.1'
A Java serialization/deserialization library to convert Java Objects into JSON and back
将Java对象转换为JSON以及反过来的Java 序列化/反序列化

Gson(又称Google Gson)是Google公司发布的一个开放源代码的Java库,主要用途为 序列化Java对象为JSON字符串,或反序列化JSON字符串成Java对象。而JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成,广泛应用于各种数据的交互中,尤其是服务器与客户端的交互。

使用时需要注意的一些细节

  • 使用 Gson 反序列化时,只有当所有 JSON 串中的 key 和 JavaBean 中的定义的 field 的类型相匹配时才能成功解析,只要有一个 field 的类型不一致,就会造成解析失败。
class Person {
	public String name;
    public int age;
}
System.out.println(gson.fromJson("{'name':'包青天'}", Person.class).name);//包青天。引号既可以是单引号也可以是双引号
System.out.println(gson.fromJson("{\"name\":包青天}", Person.class).name);//包青天。任何类型的value都可以不带引号(包括String)
System.out.println(gson.fromJson("{'NAME':'包青天'}", Person.class).name);//null。严格区分大小写

System.out.println(gson.fromJson("{'age':0xff}", Person.class).age);//NumberFormatException。只能解析十进制数
System.out.println(gson.fromJson("{'age':true}", Person.class).age);//Expected an int but was BOOLEAN
System.out.println(gson.fromJson("{'age':1.23}", Person.class).age);//Expected an int but was 1.23
  • 使用Gson反序列化时,JavaBean中的 field 的访问限制符是public还是private没任何要求,对构造方法也没任何要求
  • 使用Gson反序列化时,在解析JSON数据前需要自己确定待解析的是JSON Object、JSON array、number、字符串……
  • JSON串中的false、true和JavaBean中的整型0、1之间不能相互转换
  • JSON串中用不着的字段可以不在JavaBean中声明,JavaBean中可以声明JSON串中没有的字段
  • JSON串中的引号既可以是单引号也可以是双引号,且任何类型的value都可以不带引号(包括String)
  • JSON串中的key只能是string类型的,而value可以是string、number、false/true、null、Object对象或者array数组
  • JSON数组里的元素不要求是同一类型的,可以是任意json支持的类型

Google-gson 文档

【Gson】简介 文档 基本使用 示例 【Gson】简介 文档 基本使用 示例 【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.

Gson是一个可用于将Java对象转换为JSON表示形式的Java库。它也可以用于将JSON字符串转换为等效的Java对象。 Gson可以和任意Java对象一起使用包括您没有源代码的预先存在的对象


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.

有几个开源项目可以将Java对象转换为JSON。但是,他们大多数都要求您将Java注解放在类中;如果您无法访问源代码,则无法执行此操作。大多数也不完全支持使用Java泛型。 Gson认为这两个都是非常重要的设计目标。


Gson Goals目标
  • Provide simple   toJson()   and   fromJson()   methods to convert Java objects to JSON and vice-versa     提供简单的 toJson() 和 fromJson() 方法将Java对象转换为JSON,反之亦然
  • Allow pre-existing unmodifiable objects to be converted to and from JSON     允许将先前存在的不可修改对象转换为JSON或从JSON转换
  • Extensive support of Java Generics     广泛的支持Java泛型
  • Allow custom representations for objects     允许对象的自定义表示

Gson Download and Maven
  • Gson Download   downloads at Maven Central
  • For Maven check "Dependency Information" tab, on the left side.

Gson Documentation 文档
  • Gson   API : Javadocs for the current Gson release     当前Gson版本的Javadoc
  • Gson   user guide : This guide contains examples on how to use Gson in your code.     本指南包含有关如何在代码中使用Gson的示例。
  • Gson   Roadmap : Details of changes in the recent versions     最近版本更改的详细信息
  • Gson   design document : This document discusses issues we faced while designing Gson. It also include a comparison of Gson with other Java libraries that can be used for Json conversion     本文档讨论了我们在设计Gson时遇到的问题。它还包括将Gson与可用于Json转换的其他Java库进行比较
Please use the   google-gson Google group   to discuss Gson, or to post questions.

Gson-related Content Created by Third Parties    由第三方创建的Gson相关内容

Gson使用时需要注意的混淆问题

  • 问题:在不使用混淆工具进行apk打包时,一切正常;在使用混淆编译的方式进行apk打包后,就不能获取到JavaBean中的值了!
  • 原因:使用Gson的fromJson方法反序列化时,要求 JavaBean 中的字段名必须与 json 串中的 key 完全一致,否则解析失败。而混淆后, JavaBean 的类名及其字段名称全部变成了ABC或a、b、c 等简称了,这与 json 串中的 key 不一致,进而导致解析失败。
  • 解决:在使用混淆编译方式进行apk打包的时候,需要过滤掉所有相关的 JavaBean 。
在proguard.cfg文件中添加下面的代码:
#滤掉某个Java Bean 文件不进行混淆编译
-keep class com.lokinfo.m95xiu.bean.FamilyAssBean {*;}
#滤掉某个包下的所有.class文件不进行混淆编译
-keep class com.lokinfo.m95xiu.bean.** {*;}

GsonBuilder的API简介

  • Gson    create()  Creates a Gson instance based on the current configuration.    根据当前配置创建一个Gson实例。
  • addDeserializationExclusionStrategy(ExclusionStrategy strategy)  Configures Gson to apply the passed in exclusion strategy during deserialization.    配置Gson在反序列化期间应用传递的排除策略。设置反序列化时字段采用策略ExclusionStrategy,如反序列化时不要某字段,当然可以采用@Expore代替。
  • addSerializationExclusionStrategy(ExclusionStrategy strategy)  Configures Gson to apply the passed in exclusion strategy during serialization.   同上
  • disableHtmlEscaping()  By default, Gson escapes HTML characters such as < > etc.    默认情况下,Gson转义HTML字符,如<>等。禁止转义html标签
  • disableInnerClassSerialization()  Configures Gson to exclude inner classes during serialization.    配置Gson在序列化期间排除内部类。
  • enableComplexMapKeySerialization()  Enabling this feature will only change the serialized form if the map key is a complex type (i.e.    启用此功能将仅在映射密钥为复杂类型时更改序列化形式。
  • excludeFieldsWithModifiers(int... modifiers)  Configures Gson to excludes all class fields that have the specified modifiers.    将Gson配置为排除具有指定修饰符的所有类字段。参数值由java.lang.reflect.Modifier提供。
  • excludeFieldsWithoutExposeAnnotation()  Configures Gson to exclude all fields from consideration for serialization or deserialization that do not have the Expose annotation.    将Gson配置为将所有字段排除在不具有“公开”注释的序列化或反序列化中。设置没有@Expore则不序列化和反序列化。
  • generateNonExecutableJson()  Makes the output JSON non-executable in Javascript by prefixing the generated JSON with some special text.    通过使用一些特殊文本将生成的JSON前缀,使JSON中的输出JSON不可执行。在生成的Json串前多了【)]}'】这4个字符,且之后有一个换行
  • registerTypeAdapter(Type type, Object typeAdapter)  Configures Gson for custom serialization or deserialization.    配置Gson以进行自定义序列化或反序列化。为某特定对象设置固定的序列和反序列方式,实现JsonSerializer和JsonDeserializer接口
  • registerTypeAdapterFactory(TypeAdapterFactory factory)  Register a factory for type adapters.    为工厂注册类型适配器。
  • registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter)  Configures Gson for custom serialization or deserialization for an inheritance type hierarchy.    为继承类型层次结构的自定义序列化或反序列化配置Gson。
  • serializeNulls()  Configure Gson to serialize null fields.    配置Gson序列化空字段。
  • serializeSpecialFloatingPointValues()  Section 2.4 of JSON specification disallows special double values (NaN, Infinity, -Infinity).    JSON规范的第2.4节不允许特殊的双重值(NaN,Infinity,-Infinity)。
  • setDateFormat(String pattern)  Configures Gson to serialize Date objects according to the pattern provided.    根据提供的样式,将Gson配置为序列化Date对象。设置日期时间格式,在序列化和反序化时均生效
    • setDateFormat(int style)  Configures Gson to to serialize Date objects according to the style value provided.    同上
    • setDateFormat(int dateStyle, int timeStyle)  Configures Gson to to serialize Date objects according to the style value provided.    同上
  • setExclusionStrategies(ExclusionStrategy... strategies)  Configures Gson to apply a set of exclusion strategies during both serialization and deserialization.    配置Gson在序列化和反序列化期间应用一组排除策略。
  • setFieldNamingPolicy(FieldNamingPolicy namingConvention)  Configures Gson to apply a specific naming policy to an object's field during serialization and deserialization.    配置Gson在序列化和反序列化期间,将特定的命名策略应用于对象的字段。值从枚举FieldNamingPolicy 中获取。
  • setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy)  Configures Gson to apply a specific naming policy strategy to an object's field during serialization and deserialization.    即:设置字段序列和反序列时名称显示,和@Serializer的作用一致。
  • setLenient()  By default, Gson is strict and only accepts JSON as specified by RFC 4627.    默认情况下,Gson是严格的,只接受RFC 4627规定的JSON。
  • setLongSerializationPolicy(LongSerializationPolicy serializationPolicy)  Configures Gson to apply a specific serialization policy for Long and long objects.    配置Gson为长对象应用特定的序列化策略。
  • setPrettyPrinting()  Configures Gson to output Json that fits in a page for pretty printing.    配置Gson来输出适合漂亮打印的页面的Json。
  • setVersion(double ignoreVersionsAfter)  Configures Gson to enable versioning support.    配置Gson以启用版本控制支持。是和@Since 和 @Until 一起使用的。

JsonElement 继承体系

JsonElement 类是一个抽象类,代表着json串的某一个元素。这个元素可以是一个Json(JsonObject)、可以是一个数组(JsonArray)、可以是一个Java的基本类型(JsonPrimitive)、当然也可以为null(JsonNull)。JsonObject、JsonArray、JsonPrimitive、JsonNull都是JsonElement这个抽象类的子类。

JsonElement提供了一系列的方法来判断当前的JsonElement是否是上述子类的一种:比如 isJsonObject() 用来判断当前的json元素是否是一个数组类型,它的实现很简单:
public boolean isJsonObject() {  
    return this instanceof JsonObject;  
}
同样的,既然有isJsonObject()等这样的判断,该类也提供了把当前 JsonElement 作为上述子类的一种返回的方法:
public JsonObject getAsJsonObject() {  
  if (isJsonObject()) {  
    return (JsonObject) this;  
  }  
  throw new IllegalStateException("Not a JSON Object: " + this);  
}

JsonObject 可以看成是 key/value 的 结构,用 LinkedTreeMap<String, JsonElement> 来保存。其中  key 必须是一个字符串,而 value 可以是任意的一种 JsonElement。
private final LinkedTreeMap<String, JsonElement> members = new LinkedTreeMap();
JsonArray: Json的数组包含的其实也是一个个 Json 串,用一个 List<JsonElement> 来保存 json 数组中的每个 JsonElement 元素。
public final class JsonArray extends JsonElement implements Iterable<JsonElement> //集合类都实现了此接口,所以JsonArray具有集合的功能
private final List<JsonElement> elements;
JsonNull: 该类没什么可说的,为不可变类,当然在json中所有的JsonNullObject 调用 equals 方法判断的话都是相等的。
public static final JsonNull INSTANCE = new JsonNull(); //单例

JsonPrimitive 类

A class representing a Json primitive value. A primitive value is either a String, a Java primitive, or a Java primitive wrapper type.
JsonPrimitive  类是对 Java 的基本类型及其对应的对象类进行了封装:
private static final Class<?>[] PRIMITIVE_TYPES = { Integer.TYPE, Long.TYPE, Short.TYPE, Float.TYPE, Double.TYPE, Byte.TYPE, Boolean.TYPE, Character.TYPE, Integer.class, Long.class, Short.class, Float.class, Double.class, Byte.class, Boolean.class, Character.class };
该类定义了一个 value 字段用于存储要封装的基本类型及其对应的对象:
private Object value; 
可通过  is**()  方法 判断具体是那种类型:
public boolean isString() {
    return value instanceof String;
}
可通过  setValue(**) 方法为 value 赋值:
void setValue(Object primitive) {
   if (primitive instanceof Character) {//对于Character类型的json元素需要特殊处理
      // convert characters to strings since in JSON, characters are represented as a single character string  
      char c = ((Character) primitive).charValue();
      this.value = String.valueOf(c);
   } else {
       //对于传入的其他json类型通过checkArgumeng进行过滤,如果不是是Number或者String和PRIMITIVE_TYPES里的一种的话,就会抛出异常。
      $Gson$Preconditions.checkArgument(primitive instanceof Number || isPrimitiveOrString(primitive));
      this.value = primitive;
   }
}
可通过  getAs**() 方法将value转换为指定的类型并返回 value 的值:
public String getAsString() {
   if (isNumber())
      return getAsNumber().toString();
   if (isBoolean()) {
      return getAsBooleanWrapper().toString();
   }
   return (String) value;
}

Gson、FastJsonJackson性能对比

参考      参考2   
【JSON序列化  Object => JSON】
类库 样本数量 执行次数 最长时间(毫秒) 最短时间(毫秒) 平均时间(毫秒)
FastJson
100000 10 2291.22 1416.70 1454.93
Jackson 100000 10 1980.92 841.91 880.82
Gson 100000 10 2383.02 1469.08 1520.38

【JSON反序列化 JSON => Object】

类库 样本数量 执行次数 最长时间(毫秒) 最短时间(毫秒) 平均时间(毫秒)
FastJson
100000 10 7942.31 6340.55 6526.41
Jackson 100000 10 7957.22 6623.85 6815.41
Gson 100000 10 8235.15 7006.06 7364.75

【总结】

把Java对象JSON序列化,Jackson速度最快,在测试中比Gson快接近50%,FastJson和Gson速度接近。 
把JSON反序列化成Java对象,FastJson、Jackson速度接近,Gson速度稍慢,不过差距很小。


示例代码

序列化与反序列化

public class Test {
	public static Gson gson = new GsonBuilder().create();

	public static void main(String[] args) {
		objToJson();//普通对象
		arrayToJson();//数组
		listToJson();//集合
	}

	/**普通对象*/
	public static void objToJson() {
		String jsonString = gson.toJson(new Person("包青天", "广州"));
		System.out.println("【JSON序列化  Object => JSON】" + jsonString);
		Person person = gson.fromJson(jsonString, Person.class);//也可以用【new TypeToken<Person>() {}.getType()】
		System.out.println("【JSON反序列化 JSON => Object】" + person);
	}

	/**数组*/
	public static void arrayToJson() {
		String jsonString = gson.toJson(new String[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" });
		System.out.println("\n【JSON序列化  Array => JSON】" + jsonString);
		String[] array = gson.fromJson(jsonString, String[].class);//也可以用【new TypeToken<String[]>() {}.getType()】
		System.out.println("【JSON反序列化 JSON => Array】" + Arrays.toString(array));
		//二维数组
		String jsonString2 = gson.toJson(new int[][] { { 1, 2, 3 }, { 3, 4, 5 }, { 4, 5, 6 } });
		System.out.println("\n【JSON序列化  Array => JSON】" + jsonString2);
		int[][] array2 = gson.fromJson(jsonString2, int[][].class);
		System.out.println("【JSON反序列化 JSON => Array】" + Arrays.toString(array2));
	}

	/**集合*/
	public static void listToJson() {
		//List
		List<Person> persons = new ArrayList<Person>();
		persons.add(new Person("包青天", "北京"));
		persons.add(new Person("白乾涛", "上海"));
		persons.add(new Person("bqt", "广州"));

		String jsonString = gson.toJson(persons);
		System.out.println("\n【JSON序列化  List => JSON】" + jsonString);
		List<Person> persons2 = gson.fromJson(jsonString, new TypeToken<List<Person>>() {
		}.getType());//支持带泛型
		System.out.println("【JSON反序列化 JSON => List】" + persons2.toString());

		//Map
		Map<String, Integer> names = new HashMap<String, Integer>();
		names.put("包青天", 1);
		names.put("白乾涛", 2);
		names.put("bqt", 3);

		String jsonString2 = gson.toJson(names);
		System.out.println("\n【JSON序列化  Map => JSON】" + jsonString2);
		Map<String, Integer> names2 = gson.fromJson(jsonString2, new TypeToken<Map<String, Integer>>() {
		}.getType());
		System.out.println("【JSON反序列化 JSON => Map】" + names2.toString());
	}
}


直接解析Json串

String json = "{'flag':true,'data':{'name':'张三','age':18,'address':'广州'}}";
JsonElement element = new JsonParser().parse(json);// 获得根节点元素
JsonObject root = element.getAsJsonObject();//必须事先知道根节点是 JsonObject还是JsonArray ,框架本身没法帮你决定
JsonPrimitive flagElement = root.getAsJsonPrimitive("flag");//取得根节点下的某个节点的值
boolean flag = flagElement.getAsBoolean();
System.out.println("\n【解析Json串】" + flag);

JsonObject dataJson = root.getAsJsonObject("data");//逐层向内解析
Person person = gson.fromJson(dataJson, Person.class);
System.out.println("【JSON反序列化】" + person);

Bean

class Person {
	public String name;//对字段的访问限制符public还是private没任何限制,但字段名必须和Json串中的完全一致
	public String address;

	public Person(String name, String address) {//对构造方法也没任何限制
		this.name = name;
		this.address = address;
	}

	@Override
	public String toString() {
		return "name=" + name + " & " + "address=" + address;
	}
}

2017-9-12