1.概述

这篇文章主要讲述了Gson的使用.包括从最基础的基本类型的序列化,到对象,数组,集合,再到Gson注解,Gson Builder,再到格式化,自定义序列化与反序列化等内容.
另外文章篇幅较长,建议挑选所需部分查看.所有例子都提供了完整源码,在文章的后面.

2.Gson是什么?(1)JSON

JSON全称为JavaScript Object Notation,一种轻量级的数据交换格式.

类似于XML但比XML更小,更易解析.

(2)Gson

Gson是Google提供的可以使Java对象与JSON互转的类库,可将Java对象转换为JSON,也可将JSON转换成Java对象.

(3)Gson的好处a.容易,高效,强大:Gson是Google管理的标准化库,经过高度优化,同时api简单,比如fromJSON(),toJSON().b.无依赖性:不需要其他库,当然jdk除外.c.结果简单:转换成的json易于阅读.d.支持泛型,支持内部类.e.开源,免费提供.3.配置Gson环境

目前最新的是2.8.6版本.

(1)Gradle

dependencies { implementation 'com.google.code.gson:gson:2.8.6'}(2)Maven

<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.6</version></dependency>(3)jar

点击下载.

4.Gson基础(1)基础类型

int intJSON = 1;long longJSON = 1L;double doubleJSON = 1.0;float floatJSON = 1.0f;byte byteJSON = 1;char charJSON = 'G';short shortJSON = 1;boolean boooleanJSON = true;System.out.println(gson.toJson(intJSON));System.out.println(gson.toJson(longJSON));System.out.println(gson.toJson(doubleJSON));System.out.println(gson.toJson(floatJSON));System.out.println(gson.toJson(byteJSON));System.out.println(gson.toJson(charJSON));System.out.println(gson.toJson(shortJSON));System.out.println(gson.toJson(boooleanJSON));System.out.println("----------------------------------------");System.out.println(gson.fromJson("1",Integer.class));System.out.println(gson.fromJson("1.0",Double.class));System.out.println(gson.fromJson("1",Long.class));System.out.println(gson.fromJson("true",Boolean.class));System.out.println(gson.fromJson("B",Character.class));


就是对应输出,没啥好说的.

(2)嵌套对象

Gson gson = new Gson();System.out.println(gson.toJson(new A()));String str = "{'field':'gggg','field2':33,'field3':'G','field4':'true'}";A a = gson.fromJson(str,A.class);System.out.println(a.getField1());System.out.println(a.getField2());System.out.println(a.getField3());System.out.println(a.getField4());

A类:

class A{ private String field1 = "123"; private int field2 = 1; private char field3 = 'X'; private Boolean field4 = true;}


序列化出来的对象用{}表示.

反序列化时,注意格式,注意名字对应,用单引号引起来,还有char会自动变为String类型,另外对于布尔类型可以加单引号或不加单引号,都可以正常反序列化.

(3)数组a.普通数组

int [] a = new int []{1,2,3};double [] b = new double []{1.0,2.0,3.0};String [] c = new String []{"123","456"};System.out.println(gson.toJson(a));System.out.println(gson.toJson(b));System.out.println(gson.toJson(c));int [] aa = gson.fromJson("[6,7,8]",int [].class);double [] bb = gson.fromJson("[6.0,8.0,9.0]",double [].class);String [] cc = gson.fromJson("['123123','5464']",String [].class);System.out.println(Arrays.toString(aa));System.out.println(Arrays.toString(bb));System.out.println(Arrays.toString(cc));


对普通数组的话,{}变成了[].
还有就是反序列化时,默认会在逗号后面添一个空格.

b.List

List<String> list = new ArrayList<>();list.add("123");list.add("456");System.out.println(gson.toJson(list));List<AAAA> list2 = new ArrayList<>();list2.add(new AAAA());list2.add(new AAAA("45345",8888,false));System.out.println(gson.toJson(list2));System.out.println("---------------------------------");Type type = new TypeToken<List<String>>(){}.getType();String strList = "['234234','45457']";List<String> list3 = gson.fromJson(strList, type);System.out.println(list3);String strList2 = "[" + "{'field1':'9999','field2':666,'field3':'true'}" + "," + "{'field1':'sdlkfkl','field2':-234234,'field3':'false'}" + "]";List<AAAA> list4 = gson.fromJson(strList2, new TypeToken<List<AAAA>>(){}.getType());System.out.println(list4);

class AAAA { private String field1 = "123"; private int field2 = 5; private boolean field3 = true;}


序列化没什么问题,直接toJson即可,反序列化时,需要配合java.lang.reflect.Type使用,明确指出所要转换的类型:

Type type = new TypeToken<List<String>>(){}.getType();

TypeToken<T>中T为所需要的类型,再把这个Type对象传递给fromJson即可完成转换.
List序列化出来的用[]表示.

(4)Map

Map<String,Integer> map = new HashMap<>();map.put("123",88);map.put("2349",999);System.out.println(gson.toJson(map));String str = "{'123':23423423,'9999':-234234}";Map<String,Integer> map2 = gson.fromJson(str, new TypeToken<Map<String,Integer>>(){}.getType());System.out.println(map2.get("123").toString());System.out.println(map2.get("9999").toString());


Map同样序列化时直接toJson,反序列化时使用java.lang.reflect.Type.Map序列化出来的用{}表示.

(5)Set

Set<String> set = new HashSet<>();set.add("123123");set.add("2349594");set.add("-234()@#$@#");System.out.println(gson.toJson(set));String str = "['38483','@*#$(@#$)','SD<FGDF>G']";Set<String> set2 = gson.fromJson(str, new TypeToken<Set<String>>(){}.getType());set2.stream().forEach(System.out::println);


set序列化出来的用[]表示.

(6)null

System.out.println(gson.toJson(new AAA()));String str = "{'field2':333,'field3':null}";System.out.println(gson.fromJson(str, AAA.class));

class AAA{ private String field1 = null; private Integer field2 = null; private Double field3 = 3.0; @Override public String toString() { return "field1:"+field1+",field2:"+field2+",field3:"+field3; }}


Gson会忽略空值,在序列化时看不到null对应的键值对,反序列化时,直接对应为空.

(7)混合

一个对象里面包含了List,Map,Set,null.

System.out.println(gson.toJson(new Test()));

class Test{ private List<String> listField = new ArrayList<>(); private Map<String,Double> mapField = new HashMap<>(); private Set<Integer> setField = new HashSet<>(); private List<User> userListFiled = new ArrayList<>(); private Map<String,User> userMapField = new HashMap<>(); private Set<User> userSetField = new HashSet<>(); private Set<String> nullSetField = null; private Map<String,User> nullMapField = null; private List<User> nullListField = null; private Long longField = 23423423423L; private int intField = 234234; private Double doubleField = 234234.23423; private User userField = new User(); { listField.add("234234"); mapField.put("23432",-234.0); setField.add(-23423); userListFiled.add(new User("3459",-23423,new int []{4,5,5})); userListFiled.add(new User()); userMapField.put("()",new User()); userMapField.put("------", new User("345345",3434,new int []{4,44})); userSetField.add(new User()); userSetField.add(new User()); }}class User{ private String name = "noName"; private int age = 0; private int [] nums = new int[]{2,3,4}; public User() { } public User(String name,int age,int [] nums) { this.name = name; this.age = age; this.nums = nums; }}


这个就不反序列化了,可以看到对象,Map用{},List,Set用[].与上面的一致.

5.Gson注解(1)@SerializedName

SerializedName注解有两个参数,分别是value与alternate.SerializedName由注解名字可以知道与序列化成的Json名字有关.

默认情况下,json的键名与对象的字段名一致,@SerializedName可以解决序列化/反序列化时json键名与对象字段名不一致的问题,使其将json可以正确映射到对应的字段.

a.单独使用value

单独使用一个参数时,即@SerializedName("xxx")或@SerializedName(value="xxx"),序列化时,对象字段会变为@SerializedName中的值,反序列化时,若不是@SerializedName()中的值则不会反序列化:

public class SerializedNameValueTest{ public static void main(String[] args) { Gson gson = new Gson(); System.out.println(gson.toJson(new SerializedNameValueTest().new User())); String str = "{'this is a name':'what????','this is an age':13,'email':'33333@222.com'}"; System.out.println(gson.fromJson(str,User.class)); String str2 = "{'name':'askldfklaslk','age':-222,'email':'234234@23423.com'}"; System.out.println(gson.fromJson(str2, User.class)); } class User { @SerializedName("this is a name") private String name = "123"; @SerializedName("this is an age") private int age = 0; private String email = "xxx@xxx.com"; private double[] nums = new double[] { 1.0, 2.0 }; @Override public String toString() { return "name:" + name + ",age:" + age + ",eamil:" + email + ",nums:" + Arrays.toString(nums); } }}


最后一个反序列化不成功,因为'name'不对应@SerializedName()中的'this is a name'.

b.同时使用value与alternate

同时使用两者可以解决上面的问题,即name字段--->json中的'this is a name'--->name字段:

public class SerializedNameValueAndAlternateTest{ public static void main(String[] args) { Gson gson = new Gson(); System.out.println(gson.toJson(new SerializedNameValueAndAlternateTest().new User())); String str = "{'this is a name':'what????','this is an age':13,'email':'33333@222.com'}"; System.out.println(gson.fromJson(str, User.class)); String str2 = "{'name':'askldfklaslk','age':-222,'email':'234234@23423.com'}"; System.out.println(gson.fromJson(str2, User.class)); } class User { @SerializedName(value = "this is a name",alternate = "name") private String name = "123"; @SerializedName(value = "this is an age",alternate = "age") private int age = 0; private String email = "xxx@xxx.com"; private double[] nums = new double[] { 1.0, 2.0 }; @Override public String toString() { return "name:" + name + ",age:" + age + ",eamil:" + email + ",nums:" + Arrays.toString(nums); } }}

alternate就是为反序列化准备的,若找不到value中对应的值,则寻找alternate对应的值,找不到再设为null.

若同时存在value与alternate:

String str3 = "{'name':'altername','this is a name':'value'}";System.out.println(gson.fromJson(str3, User.class));String str4 = "{'this is a name':'value','name':'altername'}";System.out.println(gson.fromJson(str4, User.class));

则以"最晚"出现的值为标准.

(2)@Expose

@Expose可以忽略某个字段,有两个参数:

serializedeserialize

默认情况下都是true,分别表示序列化与反序列化.

System.out.println(gson.toJson(new User()));

class User{ @Expose(serialize = false) private String name = "123"; @Expose(deserialize = false) private int age = 0; @Expose(serialize = false,deserialize = false) private String email = "xxx@xxx.com"; @Expose(serialize = true,deserialize = true) private double [] nums = new double [] {1.0,2.0};}

name不允许序列化,age不允许反序列化,email不允许序列化与反序列化,nums既允许也允许反序列化.(此时效果等于没加@Expose)
输出:

咦?好像没用的样子?
因为Gson对象会默认忽略@Expose,想要@Expose生效需要使用Gson Builder:

GsonBuilder gsonBuilder = new GsonBuilder();gsonBuilder.excludeFieldsWithoutExposeAnnotation();Gson gson = gsonBuilder.create();System.out.println(gson.toJson(new User()));String str = "{'name':'234','age':-3,'email':'23423','nums':[3,4,3]}";System.out.println(gson.fromJson(str, User.class));

class User{ @Expose(serialize = false) private String name = "123"; @Expose(deserialize = false) private int age = 0; @Expose(serialize = false,deserialize = false) private String email = "xxx@xxx.com"; @Expose(serialize = true,deserialize = true) private double [] nums = new double [] {1.0,2.0}; @Override public String toString() { return "name:"+name+",age:"+age+",eamil:"+email+",nums:"+Arrays.toString(nums); }}


不能反序列化age与email,输出的是age与email的默认值.

6.Gson Builder

前面的例子基本上都是通过

Gson gson = new Gson();

来直接实例化一个Gson来使用Gson的,使用Gson Builder可以设置Gson的某些属性,使用其中的create()返回一个Gson.

(1)基础

创建一个简单的Gson,通过create()创建:

GsonBuilder gsonBuilder = new GsonBuilder();Gson gson = gsonBuilder.create();(2)命名规则a.使用系统命名规则

使用

gsonBuilder.setFieldNamingPolicy();

设置json中键的命名规则.6个值可选:

IDENTITY:相同,json中的键名与字段名相同.LOWER_CASE_WITH_DASHES:在原来字段的大写字母前加-,并且把大写变成小写LOWER_CASE_WITH_DOTS:在原来字段的大写字母前加.,并且把大写变成小写LOWER_CASE_WITHUNDERSCORES:在原来字段的大写字母前加,并且把大写变成小写UPPER_CAMEL_CASE:首字母大写UPPER_CAMEL_CASE_WITH_SPACES:在原来字段的大写字母前加空格

public class NamingRulesTest{ public static void main(String[] args) { NamingRulesTest n = new NamingRulesTest(); GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.IDENTITY); System.out.println(gsonBuilder.create().toJson(n.new User())); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES); System.out.println(gsonBuilder.create().toJson(n.new User())); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DOTS); System.out.println(gsonBuilder.create().toJson(n.new User())); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES); System.out.println(gsonBuilder.create().toJson(n.new User())); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE); System.out.println(gsonBuilder.create().toJson(n.new User())); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES); System.out.println(gsonBuilder.create().toJson(n.new User())); } class User { @SuppressWarnings("unused") private String Name_Name_name = "123"; @SuppressWarnings("unused") private int _age_age_Age_age = 645; @SuppressWarnings("unused") private double numsNumsNums = 34.45; }}


注意,若某个字段有了@SerializedName,则这个字段遵循@SerializedName的策略.

b.自定义命名规则

重写FieldNamingStrategy中的translateName(Field field),把自定义的FieldNamingStrategy传递给GsonBuilder的setFieldNamingStrategy().
比如想要前缀加上某人的名字:

public class CustomNamingRulesTest{ public static void main(String[] args) { FieldNamingStrategy myNamingStrategy = new FieldNamingStrategy(){ @Override public String translateName(Field field) { return "kr"+field.getName(); } }; GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setFieldNamingStrategy(myNamingStrategy); Gson gson = gsonBuilder.create(); System.out.println(gson.toJson(new CustomNamingRulesTest().new User())); } class User { @SuppressWarnings("unused") private String name = "123"; @SuppressWarnings("unused") private int num = 5; }}

(3)null

默认情况下,Gson实例不允许序列化null,如果想要序列化null,借助GsonBuilder的serializeNulls()方法:

public class NullTest{ public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.serializeNulls(); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES); System.out.println(gsonBuilder.create().toJson(new NullTest().new User())); } class User { @SuppressWarnings("unused") private String thisIsANullField; @SuppressWarnings("unused") private Integer andThisIsANullFieldToo; }}

(4)排除

前面已经接触到了@Expose这样的排除策略,下面看看更加强大的配合GsonBuilder使用的排除策略.主要有四种:属性名排除,类型排除,修饰符排除,@Expose排除.

a.属性名排除

public class ExclusionNameTest{ public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.serializeNulls(); ExclusionStrategy exclusionName = new ExclusionStrategy(){ @Override public boolean shouldSkipField(FieldAttributes f) { return f.getName().endsWith("e"); } @Override public boolean shouldSkipClass(Class<?> arg0) { return false; } }; gsonBuilder.setExclusionStrategies(exclusionName); System.out.println(gsonBuilder.create().toJson(new ExclusionNameTest().new User())); } class User { private String name; private int num; }}

排除字段名以e结尾的字段.下面是重点:

public boolean shouldSkipField(FieldAttributes f){ return f.getName().endsWith("e");}

重写的shouldSkipField从名字可以看出跳过某些字段,返回true表示跳过,即排除这个字段.上面的例子中若名字以e结尾则跳过,因此输出:

b.类型排除

public class ExclusionTypeTest{ public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.serializeNulls(); ExclusionStrategy exclusionType = new ExclusionStrategy(){ @Override public boolean shouldSkipField(FieldAttributes arg0) { return false; } @Override public boolean shouldSkipClass(Class<?> cls) { return cls == String.class; } }; gsonBuilder.setExclusionStrategies(exclusionType); System.out.println(gsonBuilder.create().toJson(new ExclusionNameTest().new User())); } class User { @SuppressWarnings("unused") private String name; @SuppressWarnings("unused") private int num; }}

重写的shouldSkipClass表示要跳过的类,这里跳过了String,只剩下num.

@Overridepublic boolean shouldSkipClass(Class<?> cls) { return cls == String.class;}

c.修饰符排除

这个不用重写方法了,直接使用GsonBuilder的excludeFieldsWithModifiers(),参数是java.lang.reflect.Modifier:

这个可选的比较多就不一一列举了,只选了一个final的例子:

public class ExclusionModifierTest{ public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.excludeFieldsWithModifiers(Modifier.FINAL); System.out.println(gsonBuilder.create().toJson(new User())); }}class User{ @SuppressWarnings("unused") private final String name = "123"; @SuppressWarnings("unused") private static int num;}

d.@Expose排除

这个准确来说是排除没有被@Expose注解的字段:

public class ExclusionExposeTest{ public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.excludeFieldsWithoutExposeAnnotation(); System.out.println(gsonBuilder.create().toJson(new ExclusionExposeTest().new User())); } class User { @SuppressWarnings("unused") private String name; @SuppressWarnings("unused") private int num; @Expose(serialize = true,deserialize = true) private int age; }}

(5)Lenient

这是有关于反序列化时JSON的容错机制的问题,因为通常来说将一个对象通过Gson转换成json没什么大问题,但是将json转换为对象的时候就...就难说了,因为不知道是否符合标准的json格式,因此Gson提供了一定的容错机制,就是Lenient.

Lenient翻译过来是"宽容的"的意思,可以通过:

GsonBuilder gsonBuilder = new GsonBuilder();gsonBuilder.setLenient();

开启.
Gson内部有一个JsonReader类,默认情况下,JsonReader是严格的且仅接受符合RFC 4627标准的json(RFC 4627标准可以看看这里),设置为lenient后可以"容忍"以下几种错误:

a.以 ) ] } ' \n 开头b.多个顶层值.c.任何类型的顶层值d.数字可能是NaNs或infinitese.以行注释//或#结尾f.以一个换行符结束g.C风格的注释/**/,可能会嵌套h.键/字符串没有引号或者单引号i.数组元素以;分隔j.不必要的数组分隔符,"默认"null为省略值,比如[1,,2],"默认"第二个元素为nullk.键值以=或=>分隔而非使用:l.键值对以;分隔而非使用,

设置setLenient()后,Gson会尽可能解析有错误的json,若实在无能为力,会抛出MalformedJsonException异常.
下面是一个不严格的json的例子:

public class LenientTest{ public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setLenient(); String str = "{'name'='234';'num'=6}"; System.out.println(gsonBuilder.create().fromJson(str,User.class)); } class User { private String name; private int num; @Override public String toString() { return "name:"+name+",num:"+num; } }}


下面是一个异常的例子:

String errorStr = "{'name'=????,,,,,,}";System.out.println(gsonBuilder.create().fromJson(errorStr,User.class));

(6)Floats & Doubles

先看一个例子:

public class FloatTest{ public static void main(String[] args) { Gson gson = new Gson(); System.out.println(gson.toJson(new FloatTest().new User())); } class User { @SuppressWarnings("unused") private float f = Float.POSITIVE_INFINITY; }}

会报错:

它说Infinity在JSON标准是一个非法值.想要重写这个行为需要使用GsonBuilder.serializeSpecialFloatingPointValues().
因为JSON规范不允许NaN,-Infinity,Infinity,因此会报错.下面使用GsonBuilder:

public class FloatTest{ public static void main(String[] args) { // Gson gson = new Gson(); // System.out.println(gson.toJson(new FloatTest().new User())); GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.serializeSpecialFloatingPointValues(); System.out.println(gsonBuilder.create().toJson(new FloatTest().new User())); } class User { @SuppressWarnings("unused") private float f = Float.POSITIVE_INFINITY; }}

直接输出Infinity:

double也类似:

public class DoubleTest{ public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.serializeSpecialFloatingPointValues(); System.out.println(gsonBuilder.create().toJson(new DoubleTest().new User())); } class User { @SuppressWarnings("unused") private double ni = Double.NEGATIVE_INFINITY; @SuppressWarnings("unused") private double pi = Double.POSITIVE_INFINITY; @SuppressWarnings("unused") private double nan = Double.NaN; }}

(7)模型版本化

通过@Since与@Until添加版本控制,控制某个版本在序列化与反序列化时忽略或忽略某个字段.
@Since表示从某个版本开始这个字段不忽略,@Until表示这个版本后将忽略该字段.

需要配合GsonBuilder的setVersion使用,设定版本号.

public class VersionTest{ public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.serializeNulls(); System.out.println(gsonBuilder.setVersion(0.9).create().toJson(new VersionTest().new User())); System.out.println(gsonBuilder.setVersion(1.0).create().toJson(new VersionTest().new User())); System.out.println(gsonBuilder.setVersion(1.4).create().toJson(new VersionTest().new User())); System.out.println(gsonBuilder.setVersion(1.5).create().toJson(new VersionTest().new User())); } class User { @Since(1.0) private String name; @Until(1.4) private int num; }}


@Since的范围包含了左区间端点,@Until的范围不包含右区间端点.

(8)格式化日期

可以使用setDateForamt()来格式化日期输出:

gsonBuilder.setDateFormat(int style);gsonBuilder.setDateFormat(String pattern);gsonBuilder.setDateFormat(int dateStyle,int timeStyle);

第一个函数的参数为DateFormat中的常量值,第二个函数的参数是类似SimpleDateFormat中的String,第三个函数的参数与第一个类似,分开日期与时间设置.
再说以下setPrettyPrinting()这个函数,看名字就知道,美化打印的.会加上空格.

public class FormatTest{ public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setPrettyPrinting(); System.out.println(gsonBuilder.setDateFormat(DateFormat.SHORT, DateFormat.SHORT).create().toJson(new FormatTest().new User())); System.out.println(gsonBuilder.setDateFormat(DateFormat.SHORT,DateFormat.LONG).create().toJson(new FormatTest().new User())); System.out.println(gsonBuilder.setDateFormat(DateFormat.MEDIUM, DateFormat.MEDIUM).create().toJson(new FormatTest().new User())); System.out.println(gsonBuilder.setDateFormat(DateFormat.LONG, DateFormat.MEDIUM).create().toJson(new FormatTest().new User())); System.out.println(gsonBuilder.setDateFormat(DateFormat.FULL, DateFormat.FULL).create().toJson(new FormatTest().new User())); System.out.println(gsonBuilder.setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(new FormatTest().new User())); } class User { @SuppressWarnings("unused") private Date date = new Date(); }}

7.Gson进阶(1)枚举

枚举其实也与普通的字段类似,序列化与反序列化正常操作.

public class EnumTest{ public static void main(String[] args) { Gson gson = new Gson(); System.out.println(gson.toJson(new EnumTest().new User())); String str = "{\"season\":\"SUMMER\",\"name\":\"8888\"}"; System.out.println(gson.fromJson(str,User.class)); } enum Season { SPRING, SUMMER, AUTUMN, WINTER } class User { private Season season = Season.SPRING; private String name = "123"; @Override public String toString() { return "season:"+season.toString()+",name:"+name; } }}


主要配合@SerializedName()使用,例如对于月份,可以使用1,2,3来表示:

public class EnumTest{ public static void main(String[] args) { Gson gson = new Gson(); System.out.println(gson.toJson(new EnumTest().new User())); String str = "{\"season\":\"SUMMER\",\"name\":\"8888\",\"month\":\"2\"}"; System.out.println(gson.fromJson(str,User.class)); } enum Season { SPRING, SUMMER, AUTUMN, WINTER } class User { private Season season = Season.SPRING; private String name = "123"; private Month month = Month.January; @Override public String toString() { return "season:"+season.toString()+",name:"+name+",month:"+month.toString(); } } enum Month { @SerializedName("1") January, @SerializedName("2") February, @SerializedName("3") March, @SerializedName("4") April, @SerializedName("5") May, @SerializedName("6") June, @SerializedName("7") July, @SerializedName("8") August, @SerializedName("9") September, @SerializedName("10") October, @SerializedName("11") November, @SerializedName("12") December }}

(2)泛型

这里主要说一下反序列化泛型.因为序列化泛型...直接toJson()就好了.
想想这样的情景:有一个待解析的Json String,类型为List<T>,因此想有一个这样的方法:

public <T> List<T> fromJSON(String json,Class<T> cls);

好了,怎么写呢,之前用的是TypeToken()实现反序列化:

List<Integer> integerList = new ArrayList<>();integerList.add(3);integerList.add(-999);gson.toJson(integerList, new TypeToken<List<Integer>>() {}.getType());

答案就是使用ParameterizedType:重写里面的getActualTypeArguments(),getOwnerTpye()与getRawType():

public class GenericsTest{ public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setPrettyPrinting(); Gson gson = gsonBuilder.create(); List<Integer> integerList = new ArrayList<>(); integerList.add(3); integerList.add(-999); gson.toJson(integerList, new TypeToken<List<Integer>>() {}.getType()); List<String> stringList = new ArrayList<>(); stringList.add("12321"); stringList.add("(@)#$@#"); String t1 = gson.toJson(integerList); String t2 = gson.toJson(stringList); new GenericsTest().fromJSON(t1, Integer.class).stream().forEach(System.out::println); new GenericsTest().fromJSON(t2, String.class).stream().forEach(System.out::println); } public <T> List<T> fromJSON(String json,Class<T> cls) { return new Gson().fromJson(json,new ParameterizedTypeImpl(cls)); } class ParameterizedTypeImpl implements ParameterizedType { private Class cls; public ParameterizedTypeImpl(Class cls) { this.cls = cls; } @Override public Type[] getActualTypeArguments() { return new Type[]{cls}; } @Override public Type getRawType() { return List.class; } @Override public Type getOwnerType() { return null; } }}

@Overridepublic Type[] getActualTypeArguments(){ return new Type[]{cls};}

返回实际参数类型数组,在这里是String.class与Integer.class.

@Overridepublic Type getRawType(){ return List.class;}

返回声明这个类型的类或接口,在这里是List.class.

@Overridepublic Type getOwnerType(){ return null;}

返回其成员之一的类型,就是说如果完全限定类名为A.B,则返回A,在这里没有A,因此为null.
定义好实现ParameterizedTpye接口的类后,把它传递给fromJson()作为第二参数,构造方法的参数为List<T>中的T.class.

(4)自定义序列化

自定义序列化一般用于自定义简化json.
比如有一个User类:

class User{ private String name = "123"; private String email = "xxx@xxx.com"; private int [] nums = new int [] {1,2,3};}

想要不序列化name,可以使用@Expose(serialize = false),但是想要部分序列化nums,比如只是需要第一个nums[0],上面的@Expose,@SerializedName等注解都用不上,这时需要使用JsonSerializer自定义序列化,重写其中的:

public JsonElement serialize(T t,Type type,JsonSerializationContext context)

可以返回一个JsonObject,这里的JsonObject可以自定义添加属性(即键值对).
需要配合GsonBuilder使用,创建了自己的JsonSerializer<T>后,把它传递给GsonBuilder的registerTypeAdapter():

public class SerializeCustomTest{ public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); JsonSerializer<User> serializer = new JsonSerializer<SerializeCustomTest.User>() { @Override public JsonElement serialize(User u,Type type,JsonSerializationContext context) { JsonObject object = new JsonObject(); object.addProperty("name",u.getName()); object.addProperty("email",u.getEmail()); object.addProperty("nums",u.getNums()[0]); return object; } }; gsonBuilder.registerTypeAdapter(User.class,serializer); System.out.println(gsonBuilder.create().toJson(new SerializeCustomTest().new User())); } class User { private String name = "123"; private String email = "xxx@xxx.com"; private int [] nums = new int [] {1,2,3}; public int [] getNums() { return nums; } public String getName() { return name; } public String getEmail() { return email; } }}

(5)自定义反序列化

自定义反序列化主要就是针对有多余键值对的json,比如User只需要name字段,但是传来的json包含了诸如age这样的键,因此只需挑选所需的进行反序列化.与序列化类似,首先定义自己的JsonDeserializer<T>,重写其中的:

public T deserialize(JsonElement,Type,JsonDeserializationContext);

返回一个自定义的反序列化的对象.最后在GsonBuilder中registerTypeAdapter()即可.

public class DeserializedCustomTest{ public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); JsonDeserializer<User> deserializer = new JsonDeserializer<DeserializedCustomTest.User>() { @Override public User deserialize(JsonElement json,Type type,JsonDeserializationContext context) { JsonObject object = json.getAsJsonObject(); User user = new DeserializedCustomTest().new User(object.get("name").getAsString()); return user; } }; gsonBuilder.registerTypeAdapter(User.class, deserializer); String str = "{\"aaa\":\"bbbb\",\"name\":\"this is a name\",\"age\":\"444\"}"; System.out.println(gsonBuilder.create().fromJson(str,User.class)); } class User { private String name; private int age; public User(String name) { this.name = name; } @Override public String toString() { return "name:"+name+",age:"+age; } }}

(6)默认实例

可以设置反序列化时的默认值,通过构造方法实现.比如json中没有所需要的字段的值,默认情况下为null,如果想要不为null,可以设定默认值,对于对象可以设定构造方法.

通过实现InstanceCreator<T>来实现,重写其中的createInstance方法,再配合GsonBuilder的registerTypeAdapter().

public class InstanceCustomTest{ public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter( AA.class, new InstanceCustomTest().new AAInstance( new InstanceCustomTest().new BB("123","456") ) ); String str = "{\"name\":\"123123\"}"; System.out.println(gsonBuilder.create().fromJson(str, AA.class)); } class AAInstance implements InstanceCreator<AA> { private BB bb; public AAInstance(BB bb) { this.bb = bb; } @Override public AA createInstance(Type type) { return new AA(bb); } } class AA { private String name = "AA"; private BB bb; public AA(BB bb) { this.bb = bb; } @Override public String toString() { return "name:"+name+",bb:"+bb.toString(); } } class BB { private String field1; private String field2; public BB(String field1,String field2) { this.field1 = field1; this.field2 = field2; } @Override public String toString() { return "field1:"+field1+",field2:"+field2; } }}

json没有为BB类设定值,采用默认值.

(7)@JsonAdapter

这个是自定义序列化/反序列化的注解,可以简化JsonSerializer与JsonDeserializer.另外不用配合GsonBuilder使用,直接使用new Gson().toJson()/fromJson()即可,比直接使用JsonSerializer与JsonDeserializer要简单.
首先使一个类实现JsonSerializer<T>接口,接着把这个类作为要注解的字段的@JsonAdapter的参数:

class Serializer implements JsonSerializer<User>class ContainUser{ private String userId = "x"; @JsonAdapter(Serializer.class) private User user = new User();}

public class JsonAdapterSerializeTest{ public static void main(String[] args) { Gson gson = new Gson(); System.out.println(gson.toJson(new JsonAdapterSerializeTest().new ContainUser())); } class Serializer implements JsonSerializer<User> { @Override public JsonElement serialize(User u,Type type,JsonSerializationContext context) { JsonObject object = new JsonObject(); object.addProperty("name",u.getName()); object.addProperty("email",u.getEmail()); object.addProperty("nums",u.getNums()[0]); return object; } } class ContainUser { private String userId = "x"; @JsonAdapter(Serializer.class) private User user = new User(); } class User { private String name = "123"; private String email = "xxx@xxx.com"; private int [] nums = new int [] {1,2,3}; public int [] getNums() { return nums; } public String getName() { return name; } public String getEmail() { return email; } }}


反序列化也类似.

public class JsonAdapterDeserializeTest{ public static void main(String[] args) { Gson gson = new Gson(); String str = "{\"aaaa\":\"bbbb\",\"name\":\"this is a name\",\"age\":\"444\"}"; System.out.println(gson.fromJson(str,User.class)); } class Deserialize implements JsonDeserializer<User> { @Override public User deserialize(JsonElement json,Type type,JsonDeserializationContext context) { JsonObject object = json.getAsJsonObject(); User user = new JsonAdapterDeserializeTest().new User(object.get("name").getAsString()); return user; } } @JsonAdapter(Deserialize.class) class User { private String name = "123"; public User() { } public User(String name) { this.name = name; } @Override public String toString() { return "name:"+name; } }}


实现JsonDeserializer<T>,重写deserialize(),在所需的类上添加注解.

注意@JsonAdapter注解只能添加在类上.

8.源码

所有例子的完整源码.
github.
码云.
Gson官方github.

9.参考链接

1.Gson Tutorial Series by Future Studio

2.gson完全教程

3.gson教程

4.gson用户指南

5.Gson User guide

6.gson