1.Gson的使用

1.1 tojson && fromjson 序列化和反序列化

基本属性 primitives
// SerializationGson gson = new Gson();gson.toJson(1);// ==> 1gson.toJson("abcd"); // ==> "abcd"gson.toJson(new Long(10)); // ==> 10int[] values = { 1 };gson.toJson(values); // ==> [1]// Deserializationint one = gson.fromJson("1", int.class);Integer one = gson.fromJson("1", Integer.class);Long one = gson.fromJson("1", Long.class);Boolean false = gson.fromJson("false", Boolean.class);String str = gson.fromJson("\"abc\"", String.class);String[] anotherStr = gson.fromJson("[\"abc\"]", String[].class);
类-Object
class BagOfPrimitives {private int value1 = 1;private String value2 = "abc";private transient int value3 = 3;BagOfPrimitives() {// no-args constructor}}// SerializationBagOfPrimitives obj = new BagOfPrimitives();Gson gson = new Gson();String json = gson.toJson(obj);// ==> json is {"value1":1,"value2":"abc"}// DeserializationBagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);// ==> obj2 is just like obj

注意:

1.推荐类中的属性使用私有属性。

2.序列化和反序列化不需要注解,所有都使用默认的。

3.transient 属性不被序列化和反序列化

4.如何处理空值

  • 序列化时(tojson),空值会被忽略
  • 反序列化时(fromjson),空值会被反序列化相应的默认值,Object = null,boolean = false ,int = 0;

5.synthetic属性不被序列化和反序列化

6.内部类中对应外部类的属性将被忽略,不会被序列化和反序列化

7.匿名类和内部类会被排除。经验证匿名类仍然会被序列化,但内部类会被排除

Array && Collections
Gson gson = new Gson();int[] ints = {1, 2, 3, 4, 5};String[] strings = {"abc", "def", "ghi"};// Serializationgson.toJson(ints); // ==> [1,2,3,4,5]gson.toJson(strings);// ==> ["abc", "def", "ghi"]// Deserializationint[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class);// ==> ints2 will be same as ints
Gson gson = new Gson();Collection<Integer> ints = Arrays.asList(1,2,3,4,5);// SerializationString json = gson.toJson(ints);// ==> json is [1,2,3,4,5]// DeserializationTypeToken<Collection<Integer>> collectionType = new TypeToken<Collection<Integer>>(){};// Note: For older Gson versions it is necessary to use `collectionType.getType()` as argument below,// this is however not type-safe and care must be taken to specify the correct type for the local variableCollection<Integer> ints2 = gson.fromJson(json, collectionType);// ==> ints2 is same as ints

注意:Collection 在反序列化时,需要使用泛型TypeToken,因为它无法指定结果类的具体类型。

Map
Gson gson = new Gson();Map<String, String> stringMap = new LinkedHashMap<>();stringMap.put("key", "value");stringMap.put(null, "null-entry");// SerializationString json = gson.toJson(stringMap); // ==> json is {"key":"value","null":"null-entry"}Map<Integer, Integer> intMap = new LinkedHashMap<>();intMap.put(2, 4);intMap.put(3, 6);// SerializationString json = gson.toJson(intMap); // ==> json is {"2":4,"3":6}// DeserializationGson gson = new Gson();TypeToken<Map<String, String>> mapType = new TypeToken<Map<String, String>>(){};String json = "{\"key\": \"value\"}";// Note: For older Gson versions it is necessary to use `mapType.getType()` as argument below,// this is however not type-safe and care must be taken to specify the correct type for the local variableMap<String, String> stringMap = gson.fromJson(json, mapType);// ==> stringMap is {key=value}

注意:Gson默认将java.util.Map使用Json对象的形式序列化,本质上是在Map上调用toString()方法。

​ 但对于复杂的Map对象,需要使用这个功能:GsonBuilder().enableComplexMapKeySerialization(),如果使用了这个功能,将会使用TypeAdapter#write()方法代替toString()

class PersonName {String firstName;String lastName;PersonName(String firstName, String lastName) {this.firstName = firstName;this.lastName = lastName;}// ... equals and hashCode}Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create();Map<PersonName, Integer> complexMap = new LinkedHashMap<>();complexMap.put(new PersonName("John", "Doe"), 30);complexMap.put(new PersonName("Jane", "Doe"), 35);// Serialization; complex map is serialized as a JSON array containing key-value pairs (as JSON arrays)String json = gson.toJson(complexMap);// ==> json is [[{"firstName":"John","lastName":"Doe"},30],[{"firstName":"Jane","lastName":"Doe"},35]]////若具备Enable的gson对象序列化常规的Map类型,还是会序列化成常规的Json对象。Map<String, String> stringMap = new LinkedHashMap<>();stringMap.put("key", "value");// Serialization; non-complex map is serialized as a regular JSON objectString json = gson.toJson(stringMap); // json is {"key":"value"}

若使用不具备Enable的gson对象,会导致编码的键格式错误,如下:

Gson gson = new Gson();String json = gson.toJson(complexMap);// ==> {"com.example.androiddemo.gson.PersonName@8e33f51":30,"com.example.androiddemo.gson.PersonName@fb2d3b6":35}
泛型

泛型无法直接使用toJson()||fromJson(),因为获取的class类型是 泛型的class,因此需要使用TypeTokenClass。

class Foo<T> {T value;}//错误使用Gson gson = new Gson();Foo<Bar> foo = new Foo<Bar>();gson.toJson(foo); // May not serialize foo.value correctlygson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar//正确使用Type fooType = new TypeToken<Foo<Bar>>() {}.getType();gson.toJson(foo, fooType);gson.fromJson(json, fooType);

问题:为什么使用new TypeToken<Foo>() {}匿名内部类来获取getType(),直接使用new () 不好吗?

答:Java5之后规定了新的Class文件格式规范,方法与域的描述符增添了对泛型信息的记录。因此泛型写到Class文件有这样的一个规律:

  • 声明一侧的,源码里写了什么运行时就能看到什么。
  • 使用一侧的,源码里写了什么到运行时就没了

因此出现这样的情况:

List<String> list1 = new ArrayList<String>();//左侧声明 右侧使用List list2 = new ArrayList<String>();//左侧声明 右侧使用

实例1 list1class文件中会保存String这个传入的泛型参数的信息(路径),而实例2list2就没有包含String。

同理,

new TypeToken<Foo<Bar>>()//若只是用new(),则相当于TypeToken = new TypeToken<Foo>() 和实例2一样new TypeToken<Foo<Bar>>(){} //使用匿名内部类相当于TypeToken<Foo> = new TypeToken<Foo>() 和实例1一样

这样就不会出现找不到正确的泛型类型的问题。

RowType就是类型擦除后的原始类型。

除了类型擦除这个原因之外,TypeToken使用匿名内部类的原因,是因为TypeToken无参构造函数的作用域是protected。

使用匿名内部类的场景:

  • 只用到类的一个实例
  • 类在定义后马上用到(一般只用一次)
  • 类非常小(SUN推荐是在4行代码以下)
  • 给类命名并不会导致你的代码更容易被理解
复杂类型的集合

像以下复杂类型的集合,无法直接使用TypeToken实现反序列化。

Collection collection = new ArrayList();collection.add("hello");collection.add(5);collection.add(new Event("GREETINGS", "guest"));class Event {private String name;private String source;private Event(String name, String source) {this.name = name;this.source = source;}}String json = gson.toJson(collection); //toJson可以直接使用。

因此,gson提供了以下几种方案:

  • 使用Gson的JsonParser API来实现,即转换成JsonElement来实现。

    JsonArray array = JsonParser.parseString(json).getAsJsonArray();String message = gson.fromJson(array.get(0), String.class);int number = gson.fromJson(array.get(1), int.class);Event event = gson.fromJson(array.get(2), Event.class);
  • Collection.class注册一个Type Adapter,这个gson本身就有。

  • MyCollectionMemberType 注册一个TypeAdapter,并使用 Collection

1.2 GsonBuilder的其他属性

主要是指序列化时的影响。

  • setPrettyPrinting() //设置输出格式为可读性优先(默认是体积小优先),会使Json的格式

  • serializeNulls() //设置输出null(默认null会被忽略)

  • setVersion(1.0) 和注解 @Since可以区分Json解析的版本。

    public class VersionedClass {@Since(1.1) private final String newerField;@Since(1.0) private final String newField;private final String field;public VersionedClass() {this.newerField = "newer";this.newField = "new";this.field = "old";}}VersionedClass versionedObject = new VersionedClass();Gson gson = new GsonBuilder().setVersion(1.0).create();String jsonOutput = gson.toJson(versionedObject);System.out.println(jsonOutput);System.out.println();gson = new Gson();jsonOutput = gson.toJson(versionedObject);System.out.println(jsonOutput);//output{"newField":"new","field":"old"}{"newerField":"newer","newField":"new","field":"old"}
  • excludeFieldsWithModifiers()//设置不被包括在序列化中的修饰符(默认为static //transient,但是你可以覆盖设置)

    (Modifier.STATIC, Modifier.TRANSIENT, Modifier.VOLATILE
  • Gson’s @Expose

    该注解的作用,需要使用new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(),只输出添加了@Expose注解的属性。

  • setExclusionStrategies()可以用户自定义排除策略。

    @Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD})public @interface Foo {// Field tag only annotation}public class SampleObjectForTest {@Foo private final int annotatedField;private final String stringField;private final long longField;private final Class<?> clazzField;public SampleObjectForTest() {annotatedField = 5;stringField = "someDefaultValue";longField = 1234;}}public class MyExclusionStrategy implements ExclusionStrategy {private final Class<?> typeToSkip;private MyExclusionStrategy(Class<?> typeToSkip) {this.typeToSkip = typeToSkip;}public boolean shouldSkipClass(Class<?> clazz) {return (clazz == typeToSkip);}public boolean shouldSkipField(FieldAttributes f) {return f.getAnnotation(Foo.class) != null;}}public static void main(String[] args) {Gson gson = new GsonBuilder().setExclusionStrategies(new MyExclusionStrategy(String.class)) //排除String类型和@Foo注解的属性.serializeNulls().create();SampleObjectForTest src = new SampleObjectForTest();String json = gson.toJson(src);System.out.println(json);}//output{"longField":1234}
  • 属性的自定义名称 @SerializedName

    通过注解 @SerializedName ,可以重新命名Json的Key值。

  • 使用FieldNamingPolicy来定义Json的Key值输出形式。

    private class SomeObject {@SerializedName("custom_naming") private final String someField;private final String someOtherField;public SomeObject(String a, String b) {this.someField = a;this.someOtherField = b;}}SomeObject someObject = new SomeObject("first", "second");Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();String jsonRepresentation = gson.toJson(someObject);System.out.println(jsonRepresentation);//output{"custom_naming":"first","SomeOtherField":"second"}
  • Stream

1.3 自定义序列化和反序列化

Gson为常用的类内置了一些序列化和反序列化,参考TypeAdapters

但是提供的内置方法往往不够使用,因此提供了以下的方法自定义序列化和反序列化。

  • JSON Serializers: Need to define custom serialization for an object
  • JSON Deserializers: Needed to define custom deserialization for a type
  • Instance Creators: Not needed if no-args constructor is available or a deserializer is registered(如果无参构造函数可以获取或者反序列化已注册,则不需要),自定义某种对象的创建行为。
GsonBuilder gson = new GsonBuilder();gson.registerTypeAdapter(MyType2.class, new MyTypeAdapter());gson.registerTypeAdapter(MyType.class, new MySerializer());gson.registerTypeAdapter(MyType.class, new MyDeserializer());gson.registerTypeAdapter(MyType.class, new MyInstanceCreator());

registerTypeAdapter提供了检查是否至少实现了一种以上的接口并且注册他们。

JSON Serializers

实现JsonSerializer接口,借助JsonElement实现对特定的需求进行序列化,由源码可知最后回调用serialize()方法。

//设置boolean类型为0 或1public class BooleanSerializer implements JsonSerializer<Boolean> {public JsonElement serialize(Boolean aBoolean, Type type,JsonSerializationContext jsonSerializationContext) {if(aBoolean){ return new JsonPrimitive(1);}return new JsonPrimitive(0);}}public static void main(String[] args) throws Exception {Employee emp = new Employee(1, "Lokesh", "Gupta", "howtodoinjava@gmail.com", true);Gson gson = new GsonBuilder().registerTypeAdapter(Boolean.class, new BooleanSerializer()).setPrettyPrinting().create();String json = gson.toJson(emp);System.out.println(json);}
JSON Deserializers

同理,实现JsonDeserializers接口,借助JsonElement实现。

//将年月日转换成LocalDatapublic class Employee {private Integer id;private String firstName;private String lastName;private String email;private LocalDate dob;}public class EmployeeDeserializer implements JsonDeserializer<Employee> {@Overridepublic Employee deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {JsonObject jsonObject = json.getAsJsonObject();LocalDate localDate = LocalDate.of(jsonObject.get("year").getAsInt(),jsonObject.get("month").getAsInt(),jsonObject.get("day").getAsInt());return new Employee(jsonObject.get("id").getAsInt(), jsonObject.get("firstName").getAsString(), jsonObject.get("lastName").getAsString(), jsonObject.get("email").getAsString(), localDate);}}//注册使用即可
Instance Creators

可使用场景:

1.需要重新定义行为的创建方式。如创建子类

2.创建的实例也是泛型的,通过ParameterizedType获取Type类型

//第二种情况public class Id<T> {private final Class<T> classOfId;private final long value;public Id(Class<T> classOfId, long value) {this.classOfId = classOfId;this.value = value;}}class IdInstanceCreator implements InstanceCreator<Id<?>> {public Id<?> createInstance(Type type) {Type[] typeParameters = ((ParameterizedType)type).getActualTypeArguments();Type idType = typeParameters[0]; // Id has only one parameterized type Treturn new Id((Class)idType, 0L);}}//使用Gson gson=new GsonBuilder().registerTypeAdapter(Id.getClass(),new IdInstanceCreator()).create();String json="";Id<Foo> id=gson.fromJson(json,Id.getClass());

InstanceCreater源码解析

知晓其何时创建实例,学习gson优秀的源码

1.InstanceCreater注册

private final Map<Type, InstanceCreator<?>> instanceCreators= new HashMap<Type, InstanceCreator<?>>();//先放在map中public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {if (typeAdapter instanceof InstanceCreator<?>) {//放入map中instanceCreators.put(type, (InstanceCreator) typeAdapter);}//省略部分代码return this;} public Gson create() {addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, factories);//删除与本文无关的代码return new Gson(...,..., instanceCreators,..., ...,..., ..., ..., ...,..., ..., ...);}//Gson构造函数 private final ConstructorConstructor constructorConstructor; Gson(。。。,final Map<Type, InstanceCreator<?>> instanceCreators, 。。。。。) {this.constructorConstructor = new ConstructorConstructor(instanceCreators);

从中可以看出最后instanceCreators以map的形式放在Gson对象中持有的ConstructorConstructor对象中的map中。

//Gson持有ConstructorConstructor对象。public final class ConstructorConstructor {private final Map<Type, InstanceCreator<?>> instanceCreators;public ConstructorConstructor(Map<Type, InstanceCreator<?>> instanceCreators) {this.instanceCreators = instanceCreators;}

ReflectiveTypeAdapterFactory对象初始化TypeAdapter时,会获取ObjectConstruct。

//Gson初始化时会将ConstructorConstructor对象传递给ReflectiveTypeAdapterFactoryGson(,,,,,,,){factories.add(new ReflectiveTypeAdapterFactory(constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));}public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {//根据type获取ObjectConstructorObjectConstructor<T> constructor = constructorConstructor.get(type);return new Adapter<T>(constructor, getBoundFields(gson, type, raw));}

然后看一下,ObjectConstructor#get方法来实现获取Type对应的实例,为什么要加一个ConstructorConstructor来获取实例。

public <T> ObjectConstructor<T> get(TypeToken<T> typeToken) {final Type type = typeToken.getType();final Class<? super T> rawType = typeToken.getRawType();// 创建对象方式Afinal InstanceCreator<T> typeCreator = (InstanceCreator<T>) instanceCreators.get(type);//客户端没有传InstanceCreator的时候为nullif (typeCreator != null) {return new ObjectConstructor<T>() {//省略部分代码 };}// 创建对象方式Bfinal InstanceCreator<T> rawTypeCreator =(InstanceCreator<T>) instanceCreators.get(rawType); //客户端没有传InstanceCreator的时候为null if (rawTypeCreator != null) {return new ObjectConstructor<T>() {@Override public T construct() {//省略部分代码 }};} // 创建对象方式C//如果没有配置InstanceCreator的实现ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType);if (defaultConstructor != null) {return defaultConstructor;} // 创建对象方式D//如果没有配置InstanceCreator的实现 ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(type, rawType);if (defaultImplementation != null) {return defaultImplementation;}// finally try unsafereturn newUnsafeAllocator(type, rawType);}

此处使用了设计模式——策略模式,有五种策略来实现获取对象实例。

1、根据type通过客户端传入的InstanceCreator
2、根据rawType通过客户端传入的InstanceCreator
3、通过constructor 的newInstance 详见newDefaultConstructor方法
4、判断是否是集合对象,来初始化目标javaBean对象,详见newDefaultImplementationConstructor
5、最后调用newUnsafeAllocator来完成对象的初始,详见newUnsafeAllocator。

2.使用入口:创建对象的实例,在Adapter中(ReflectiveTypeAdapterFactory)来创建实例

 //创建对象的实例:这段至关重要 参考《Gson反射解析机制详解(1)》public T read(JsonReader in) throws IOException {//....//实例化一个对象constructor是ObjectConstructorT instance = constructor.construct();in.beginObject();//遍历json为instance的字段自动赋值while (in.hasNext()) {String name = in.nextName();BoundField field = boundFields.get(name);if (field == null || !field.deserialized) {in.skipValue();} else {field.read(in, instance);}}in.endObject();//返回一个java bean对象return instance;}

从而在Gson的constructor#construct 获取实例。

 T instance = constructor.construct(); 
TypeAdapter实现自定义序列化和反序列化

TypeAdapter和Serializer、Deserializer起到相同的作用,区别在于TypeAdapter使用流来解析数据,而不是使用JsonElement.

GsonBuilder().registerTypeAdapter()可知,TypeAdapter会以工厂模式的方式添加到factories。

public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {Objects.requireNonNull(type);$Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>|| typeAdapter instanceof JsonDeserializer<?>|| typeAdapter instanceof InstanceCreator<?>|| typeAdapter instanceof TypeAdapter<?>);...if (typeAdapter instanceof JsonSerializer<?> || typeAdapter instanceof JsonDeserializer<?>) {TypeToken<?> typeToken = TypeToken.get(type);//Serializer、Deserializer 封装在了TreeTypeAdapter中factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter));}if (typeAdapter instanceof TypeAdapter<?>) {//这里是新建了Factory@SuppressWarnings({"unchecked", "rawtypes"})TypeAdapterFactory factory = TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter);factories.add(factory);}return this;}

主要使用了read()write()方法来实现对Json数据流的处理,以下是一个demo.

public class BookTypeAdapter extends TypeAdapter { @Overridepublic Book read(final JsonReader in) throws IOException {final Book book = new Book(); in.beginObject();while (in.hasNext()) {switch (in.nextName()) {case "isbn":book.setIsbn(in.nextString());break;case "title":book.setTitle(in.nextString());break;case "authors":book.setAuthors(in.nextString().split(";"));break;}}in.endObject(); return book;} @Overridepublic void write(final JsonWriter out, final Book book) throws IOException {out.beginObject();out.name("isbn").value(book.getIsbn());out.name("title").value(book.getTitle());out.name("authors").value(StringUtils.join(book.getAuthors(), ";"));out.endObject();}}

1.4 常用的类

Object

每个类包括数组都继承自Object

Class

Class是一个类。类对象由Java虚拟机自动构建,用于表示JVM运行时类或接口的信息。Class类的构造函数被设计为私有的,这意味着我们不能通过new的方式来创建Class对象,只有JVM才能创建该类的实例。

Type

是一个接口,自1.5之后,是Java所有类型的通用超级接口。

Raw Type:原始类型,包括类和接口。基本数据类型和不涉及泛型的所有引用类型(类、接口、数组)均是Class类型。

Parameterized types:参数化类型,指泛型,例如List是一个参数化类型。

  • getActualTypeArguments()返回Type[],即“”里的参数,比如Map
  • getRawType()返回Tpye,得到“”前面的类型,比如List
  • getOwnerType()返回Type,返回ParameterizedType类型所在的类的Type。如Map.Entry这个参数化类型返回的是Map(因为Map.Entry这个类型所在的类是Map)的类型。

Array types:带有泛型的数组类型,也就是带有参数化类或者接口所表示的数组对应的类型,例如 List s[]、Map map[]等对应的类型均是GenericArrayType类型,而List s[]、Map map[]是Class类型。

类型变量(type variables):也叫泛型变量,即泛型中的变量,例如:T、K、V等变量,可以表示任何类。
基本数据类型(primitive types):byte、short、boolean、char、int、long、float、double八大基本数据类型。
通配符类型(WildcardType) :通配符对应的类型,例如 List 中?对应的类型