GSON
https://github.com/google/gson/blob/master/UserGuide.md
使用
简单类型使用
// Serialization 序列化的用法 基本类型转换成JSON
Gson gson = new Gson();
System.out.println(gson.toJson(2).getClass());//String
gson.toJson(1); // ==> 1
gson.toJson("abcd"); // ==> "abcd"
gson.toJson(new Long(10)); // ==> 10
int[] values = { 1 };
gson.toJson(values); // ==> [1]
System.out.println(gson.toJson(values));
// Deserialization 反序列化,需要传入反序列化目标类型 JSON转换成基本类型
int one = gson.fromJson("1", int.class);
Integer one1 = gson.fromJson("1", Integer.class);
Long one2 = gson.fromJson("1", Long.class);
Boolean false1 = 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; //transient表明这个字段不序列化
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
对于对象的要求:实体类
- 属性使用private修饰
- 所有属性默认都会被序列化和反序列化,包括父类的
- 使用transient关键字修饰的属性,默认不会被序列化和反序列化
- 可以自动处理null值
- 序列化成JSON的时候,如果字段为null,默认不输出这个字段
- 反序列化的时候,如果JSON中缺失的字段,实体中有,那么就会给实体赋值一个默认的,对象是null,数值型是0,boolean是false
- If a field is synthetic, it is ignored and not included in JSON serialization or deserialization.
- Fields corresponding to the outer classes in inner classes, anonymous classes, and local classes are ignored and not included in serialization or deserialization
内部类
内部类可以被序列化的前提是,静态内部类,因为反序列化的时候内部类的无参构造问题,要指定外部对象,但是此时是没有的
这个例子就不行
public class A {
public String a;
class B {
public String b;
public B() {
// No args constructor for B
}
}
}
解决方案有2个:
改成静态内部类
或者
不建议使用:
public class InstanceCreatorForB implements InstanceCreator<A.B> {
private final A a;
public InstanceCreatorForB(A a) {
this.a = a;
}
public A.B createInstance(Type type) {
return a.new B();
}
}
数组
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 = Lists.immutableList(1,2,3,4,5);
// Serialization
String json = gson.toJson(ints); // ==> json is [1,2,3,4,5]
// Deserialization
Type collectionType = new TypeToken<Collection<Integer>>(){}.getType();
Collection<Integer> ints2 = gson.fromJson(json, collectionType);
// ==> ints2 is same as ints
官方吐槽Java的集合类型定义很恶心
在集合使用中的缺陷,可以序列化,但是不能反序列化,因为使用者不知道真正要转换成什么结果集
带泛型的序列化和反序列化
调用toJson(obj)的时候,Gson会调用obj.getClass()来获取要序列化的字段,但是当使用泛型的时候就获取不到了
比如
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
真正的类型应该是Foo,但是这里只能获取到Foo
解决方法
使用TypeToken
Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.toJson(foo, fooType);
gson.fromJson(json, fooType);
这里实现了一个匿名的内部类,使用其中的方法getType()来获取真正的对象类型
复杂类型的集合
这样一个JSON
['hello',5,{name:'GREETINGS',source:'guest'}]
使用集合表示:
Collection collection = new ArrayList();
collection.add("hello");
collection.add(5);
collection.add(new Event("GREETINGS", "guest"));
Event实体类
class Event {
private String name;
private String source;
private Event(String name, String source) {
this.name = name;
this.source = source;
}
}
序列化的时候直接调用toJson(collection)
反序列化的时候如果直接fromJson(json, Collection.class)
是不行的,Gson获取不到集合中的实际数据类型是什么
解决方法:首选方法1
- 使用JsonParser转换成List,然后从里面一个个拿出来进行转换
/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.gson.extras.examples.rawcollections;
import java.util.ArrayList;
import java.util.Collection;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
public class RawCollectionsExample {
static class Event {
private String name;
private String source;
private Event(String name, String source) {
this.name = name;
this.source = source;
}
@Override
public String toString() {
return String.format("(name=%s, source=%s)", name, source);
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void main(String[] args) {
Gson gson = new Gson();
Collection collection = new ArrayList();
collection.add("hello");
collection.add(5);
collection.add(new Event("GREETINGS", "guest"));
String json = gson.toJson(collection);
System.out.println("Using Gson.toJson() on a raw collection: " + json);
//代码
JsonParser parser = new JsonParser();
JsonArray array = parser.parse(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);
System.out.printf("Using Gson.fromJson() to get: %s, %d, %s", message, number, event);
}
}
- 写一个适配器,映射所有的成员到特定的对象实体,不建议使用,这种方法的缺点是它会在Gson中搞乱其他集合类型的反序列化
- 写一个适配器,定义好各个成员的类型,比如MyCollectionMemberType ,然后使用fromJson() 方法的时候传入Collection
内置序列化工具和反序列化工具
例子
java.net.URL
用来匹配"https://github.com/google/gson/"
java.net.URI
用来匹配"/google/gson/"
自定义序列化和反序列化
通常是:
- 定义Json Serializers:需要为对象定义自定义序列化
- 定义Json Deserializers:需要定义一个类型的自定义反序列化
- 定义Instance Creators:如果无参数构造函数可用或注册了反序列化器,则不需要定义
例子:
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());
Serializers
private class DateTimeSerializer implements JsonSerializer<DateTime> {
public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toString());
}
}
针对DateTime类型的序列化,会调用serialize()方法
Deserializers
private class DateTimeDeserializer implements JsonDeserializer<DateTime> {
public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return new DateTime(json.getAsJsonPrimitive().getAsString());
}
}
如果要把一个Json的String转换成DataTime类型的时候就会调用
Instance Creator
private class MoneyInstanceCreator implements InstanceCreator<Money> {
public Money createInstance(Type type) {
return new Money("1000000", CurrencyCode.USD);
}
}
这里类型可以改成泛型,就可以作为工具类了
不用写实际的泛型类型就可以用:
class MyList<T> extends ArrayList<T> {
}
class MyListInstanceCreator implements InstanceCreator<MyList<?>> {
@SuppressWarnings("unchecked")
public MyList<?> createInstance(Type type) {
// No need to use a parameterized list since the actual instance will have the raw type anyway.
return new MyList();
}
}
需要用到实际泛型类型的例子:
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 Id.get((Class)idType, 0L);
}
}
null的处理
默认null转换成JSON的时候是不写的
这样定义就可以了
Gson gson = new GsonBuilder().serializeNulls().create();
public class Foo {
private final String s;
private final int i;
public Foo() {
this(null, 5);
}
public Foo(String s, int i) {
this.s = s;
this.i = i;
}
}
Gson gson = new GsonBuilder().serializeNulls().create();
Foo foo = new Foo();
String json = gson.toJson(foo);
System.out.println(json);
json = gson.toJson(null);
System.out.println(json);
//{"s":null,"i":5}
//null
多版本支持
使用Since注解
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(someObject);
System.out.println(jsonOutput);
System.out.println();
gson = new Gson();
jsonOutput = gson.toJson(someObject);
System.out.println(jsonOutput);
//{"newField":"new","field":"old"}
//{"newerField":"newer","newField":"new","field":"old"}
排除字段
默认被transient修饰的字段是不序列化的,被static修饰的字段也会被排除掉
包含被static修饰的字段
import java.lang.reflect.Modifier;
Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.STATIC)
.create();
或者
Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT, Modifier.VOLATILE)
.create();
@Expose
这个注解,没有被修饰的字段会被排除,不做序列化和反序列化
自定义排除策略
使用Foo注解的会被排除
String类型的会被排除
最后只留下了long类型的1234
@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))
.serializeNulls()
.create();
SampleObjectForTest src = new SampleObjectForTest();
String json = gson.toJson(src);
System.out.println(json);
}
//{"longField":1234}
JSON字段转换
比如
sampleFieldNameInJava
转换成JSON的时候可以选择
sample_field_name_in_java
或者
SampleFieldNameInJava
例子
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);
//{"custom_naming":"first","SomeOtherField":"second"}
其他参考资料
https://www.jianshu.com/p/e740196225a4
https://www.jianshu.com/p/c88260adaf5e
https://www.jianshu.com/p/0e40a52c0063
https://www.jianshu.com/p/3108f1e44155
一些补充
多个别名
可以指定多个别名,把几个不同的名字都映射成同一个,在反序列化的时候有用
当多种情况同时出时,以最后一个出现的值为准
@SerializedName(value = "emailAddress", alternate = {"email", "email_address"})
public String emailAddress;
泛型
Gson gson = new Gson(); String jsonArray = "[\"Android\",\"Java\",\"PHP\"]"; String[] strings = gson.fromJson(jsonArray, String[].class); List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType());
TypeToken
的构造方法是protected
修饰的,所以上面才会写成new TypeToken<List<String>>() {}.getType()
而不是 new TypeToken<List<String>>().getType()
看这个会说的更详细
https://www.jianshu.com/p/d62c2be60617
两个有相同字段的类:
public class UserResult {
public int code;
public String message;
public User data;
}
public class UserListResult {
public int code;
public String message;
public List<User> data;
}
String json = "{..........}";
Gson gson = new Gson();
UserResult userResult = gson.fromJson(json,UserResult.class);
User user = userResult.data;
UserListResult userListResult = gson.fromJson(json,UserListResult.class);
List<User> users = userListResult.data;
其实可以简化成:
public class Result<T> {
public int code;
public String message;
public T data;
}
然后直接使用泛型
Type userType = new TypeToken<Result<User>>(){}.getType();
Result<User> userResult = gson.fromJson(json,userType);
User user = userResult.data;
Type userListType = new TypeToken<Result<List<User>>>(){}.getType();
Result<List<User>> userListResult = gson.fromJson(json,userListType);
List<User> users = userListResult.data;