// Serialization
Gson gson = new Gson();
gson.toJson(1); // ==> 1
gson.toJson("abcd"); // ==> "abcd"
gson.toJson(new Long(10)); // ==> 10
int[] values = { 1 };
gson.toJson(values); // ==> [1]
// Deserialization
int 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);
class BagOfPrimitives {
private int value1 = 1;
private String value2 = "abc";
private transient int value3 = 3;
BagOfPrimitives() {
// no-args constructor
}
}
// Serialization
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj);
// ==> json is {"value1":1,"value2":"abc"}
// Deserialization
BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);
// ==> obj2 is just like obj
注意:
1.推荐类中的属性使用私有属性。
2.序列化和反序列化不需要注解,所有都使用默认的。
3.transient 属性不被序列化和反序列化
4.如何处理空值
5.synthetic属性不被序列化和反序列化
6.内部类中对应外部类的属性将被忽略,不会被序列化和反序列化
7.匿名类和内部类会被排除。经验证匿名类仍然会被序列化,但内部类会被排除
Gson gson = new Gson();
int[] ints = {1, 2, 3, 4, 5};
String[] strings = {"abc", "def", "ghi"};
// Serialization
gson.toJson(ints); // ==> [1,2,3,4,5]
gson.toJson(strings); // ==> ["abc", "def", "ghi"]
// Deserialization
int[] 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);
// Serialization
String json = gson.toJson(ints); // ==> json is [1,2,3,4,5]
// Deserialization
TypeToken<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 variable
Collection<Integer> ints2 = gson.fromJson(json, collectionType);
// ==> ints2 is same as ints
注意:Collection 在反序列化时,需要使用泛型TypeToken,因为它无法指定结果类的具体类型。
Gson gson = new Gson();
Map<String, String> stringMap = new LinkedHashMap<>();
stringMap.put("key", "value");
stringMap.put(null, "null-entry");
// Serialization
String 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);
// Serialization
String json = gson.toJson(intMap); // ==> json is {"2":4,"3":6}
// Deserialization
Gson 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 variable
Map<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 object
String 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,因此需要使用TypeToken
Class。
class Foo<T> {
T value;
}
//错误使用
Gson gson = new Gson();
Foo<Bar> foo = new Foo<Bar>();
gson.toJson(foo); // May not serialize foo.value correctly
gson.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<Bar>>() {}
匿名内部类来获取getType()
,直接使用new () 不好吗?
答:Java5之后规定了新的Class文件格式规范,方法与域的描述符增添了对泛型信息的记录。因此泛型写到Class文件有这样的一个规律:
因此出现这样的情况:
List<String> list1 = new ArrayList<String>();//左侧声明 右侧使用
List list2 = new ArrayList<String>();//左侧声明 右侧使用
实例1 list1
class文件中会保存String这个传入的泛型参数的信息(路径),而实例2list2
就没有包含String。
同理,
new TypeToken<Foo<Bar>>()//若只是用new(),则相当于TypeToken<T> = new TypeToken<Foo<Bar>>() 和实例2一样
new TypeToken<Foo<Bar>>(){} //使用匿名内部类相当于TypeToken<Foo<Bar>> = new TypeToken<Foo<Bar>>() 和实例1一样
这样就不会出现找不到正确的泛型类型的问题。
RowType就是类型擦除后的原始类型。
除了类型擦除这个原因之外,TypeToken使用匿名内部类的原因,是因为TypeToken无参构造函数的作用域是protected。
使用匿名内部类的场景:
像以下复杂类型的集合,无法直接使用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<MyCollectionMemberType>
。
主要是指序列化时的影响。
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
Gson为常用的类内置了一些序列化和反序列化,参考
TypeAdapters
但是提供的内置方法往往不够使用,因此提供了以下的方法自定义序列化和反序列化。
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
提供了检查是否至少实现了一种以上的接口并且注册他们。
实现JsonSerializer
接口,借助JsonElement实现对特定的需求进行序列化,由源码可知最后回调用serialize()方法。
//设置boolean类型为0 或1
public 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);
}
同理,实现JsonDeserializers
接口,借助JsonElement实现。
//将年月日转换成LocalData
public class Employee
{
private Integer id;
private String firstName;
private String lastName;
private String email;
private LocalDate dob;
}
public class EmployeeDeserializer implements JsonDeserializer<Employee>
{
@Override
public 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);
}
}
//注册使用即可
可使用场景:
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 T
return 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对象传递给ReflectiveTypeAdapterFactory
Gson(,,,,,,,){
factories.add(new ReflectiveTypeAdapterFactory(
constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));
}
public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
//根据type获取ObjectConstructor
ObjectConstructor<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();
// 创建对象方式A
final InstanceCreator<T> typeCreator = (InstanceCreator<T>) instanceCreators.get(type);
//客户端没有传InstanceCreator的时候为null
if (typeCreator != null) {
return new ObjectConstructor<T>() {//省略部分代码 };
}
// 创建对象方式B
final 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 unsafe
return 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是ObjectConstructor<T>
T 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和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 {
@Override
public 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;
}
@Override
public 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();
}
}
每个类包括数组都继承自Object
Class是一个类。类对象由Java虚拟机自动构建,用于表示JVM运行时类或接口的信息。Class类的构造函数被设计为私有的,这意味着我们不能通过new的方式来创建Class对象,只有JVM才能创建该类的实例。
是一个接口,自1.5之后,是Java所有类型的通用超级接口。
Raw Type:原始类型,包括类和接口。基本数据类型和不涉及泛型的所有引用类型(类、接口、数组)均是Class类型。
Parameterized types:参数化类型,指泛型,例如List是一个参数化类型。
Array types:带有泛型的数组类型,也就是带有参数化类或者接口所表示的数组对应的类型,例如 List s[]、Map<String,Integer> map[]等对应的类型均是GenericArrayType类型,而List s[]、Map map[]是Class类型。
类型变量(type variables):也叫泛型变量,即泛型中的变量,例如:T、K、V等变量,可以表示任何类。
基本数据类型(primitive types):byte、short、boolean、char、int、long、float、double八大基本数据类型。
通配符类型(WildcardType) :通配符对应的类型,例如 List<? extends Object> 中?对应的类型