官网首页:https://google.github.io/gson/
官网文档指南:https://google.github.io/gson/UserGuide.html#overview
引入依赖
<dependencies>
<!-- Gson: Java to JSON conversion -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
使用
基本示例
@Test
public void test01(){
// 序列化
Gson gson = new Gson();
System.out.println(gson.toJson(1));; // ==> 1
System.out.println(gson.toJson("abcd")); // ==> "abcd"
System.out.println(gson.toJson(new Long(10))); // ==> 10
int[] values = { 1 };
System.out.println(gson.toJson(values));; // ==> [1]
// 反序列化
int i = gson.fromJson("1", int.class);
System.out.println("i = " + i);
Integer intObj = gson.fromJson("1", Integer.class);
System.out.println("intObj = " + intObj);
Long longObj = gson.fromJson("1", Long.class);
System.out.println("longObj = " + longObj);
Boolean boolObj = gson.fromJson("false", Boolean.class);
System.out.println("boolObj = " + boolObj);
String str = gson.fromJson("\"abc\"", String.class);
System.out.println("str = " + str);
String[] strArray = gson.fromJson("[\"abc\"]", String[].class);
System.out.println("strArray = " + Arrays.toString(strArray));
}
对象示例
1. 默认情况下,当前类(以及所有超类)中的所有字段都会被序列化。
2. 如果字段标记为暂时性,则(默认情况下)将忽略该字段,并且不包含在 JSON 序列化或反序列化中。
1. 创建父类对象
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public class ParentBag {
private String id;
private Date date;
}
2. 创建子类对象
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public class BagOfPrimitives extends ParentBag{
private int value1;
private String value2;
// 被 transient 标记的字段不被序列化
private transient int value3;
private Boolean value4;
}
3. 使用
@Test
public void test02(){
// 序列化
BagOfPrimitives obj = new BagOfPrimitives(1, "abc", 3, null);
obj.id("1001");
obj.date(new Date());
Gson gson = new Gson();
String json = gson.toJson(obj);
System.out.println("json = " + json);
// 反序列化
BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);
System.out.println("obj2 = " + obj2);
}
嵌套类(包括内部类)-- 静态
Gson 可以很容易地序列化和反序列化静态嵌套类。
但是,Gson 不能自动反序列化纯内部类,因为它们的 no-args 构造函数还需要对包含的 Object 的引用,而该引用在反序列化时不可用。
1. 创建对象
package org.example.paymentdemo.gson.entity;
import lombok.*;
import lombok.experimental.Accessors;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public class OutsideObject {
private String outsideName;
private InnerObject innerObject;
private InnerStaticObject innerStaticObject;
/**
* 静态内部类
*/
@Setter
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public static class InnerStaticObject{
private String innerStaticName;
}
/**
* 非静态内部类:外部无法创建对象
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public class InnerObject{
private String innerName;
}
}
2. 使用
@Test
public void test03(){
OutsideObject outsideObject = new OutsideObject();
outsideObject.outsideName("111");
// 非静态内部类
OutsideObject.InnerObject inneredObject = outsideObject.new InnerObject();
inneredObject.innerName("222");
outsideObject.innerObject(inneredObject);
// 静态内部类
OutsideObject.InnerStaticObject innerStaticObject = new OutsideObject.InnerStaticObject("111");
outsideObject.innerStaticObject(innerStaticObject);
// 序列化
Gson gson = new Gson();
String json = gson.toJson(outsideObject);
System.out.println("json = " + json);
// 反序列化
OutsideObject outsideObject1 = gson.fromJson(json, OutsideObject.class);
System.out.println("outsideObject1 = " + outsideObject1);
}
数组示例
基本类型
多维数组
复杂元素类型
@Test
public void test04(){
Gson gson = new Gson();
int[] ints = {1, 2, 3, 4, 5};
String[] strings = {"abc", "def", "ghi"};
// 序列化
String json = gson.toJson(ints);// ==> [1,2,3,4,5]
System.out.println("json = " + json);
json = gson.toJson(strings); // ==> ["abc", "def", "ghi"]
System.out.println("json = " + json);
// 反序列化
int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class);
// ==> ints2 will be same as ints
System.out.println("ints2 = " + Arrays.toString(ints2));
// 多维数组
int[][] intss = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
json = gson.toJson(intss);
System.out.println("json = " + json); // ==> [[1,1],[2,2],[3,3],[4,4],[5,5]]
int[][] ints1 = gson.fromJson(json, int[][].class);
System.out.println("ints1 = " + ints1);
// 任意复杂的元素类型
ParentBag[] parentBags = {new ParentBag().id("111"), new ParentBag().id("222"), new ParentBag().id("333")};
json = gson.toJson(parentBags);
System.out.println("json = " + json);
ParentBag[] parentBags1 = gson.fromJson(json, ParentBag[].class);
System.out.println("parentBags1 = " + parentBags1);
}
集合示例
1. Gson 可以序列化任意对象的集合,但不能从中反序列化,因为无法指定生成对象的类型。
Gson会自己判断类型,但是可能不是准确的,比如:Integer 反序列为 Double,对象 反序列为 LinkedTreeMap。
2. Gson 使用 TypeToken 类来表示泛型类型 T。反序列化时强制创建此类的子类,即使在运行时也可以检索类型信息。【推荐使用】
/**
* 集合示例
*/
@Test
public void tset05(){
Gson gson = new Gson();
Collection<Integer> ints = Arrays.asList(1,2,3,4,5);
// 序列化
String json = gson.toJson(ints); // ==> [1,2,3,4,5]
System.out.println("json = " + json);
// 反序列化
TypeToken<Collection<Integer>> collectionType = new TypeToken<Collection<Integer>>(){};
//对于较旧的 Gson 版本,有必要使用“collectionType.getType()”作为下面的参数,但是这不是类型安全的,必须注意为局部变量指定正确的类型
Collection<Integer> ints2 = gson.fromJson(json, collectionType); // ==> [1, 2, 3, 4, 5]
System.out.println("ints2 = " + ints2);
Collection collection = gson.fromJson(json, Collection.class);
System.out.println("collection = " + collection); // ==> [1.0, 2.0, 3.0, 4.0, 5.0]
ArrayList<ParentBag> list = new ArrayList<>();
list.add(new ParentBag().id("111"));
list.add(new ParentBag().id("222"));
list.add(new ParentBag().id("333"));
json = gson.toJson(list); // ==>
System.out.println("json = " + json);
Collection collection1 = gson.fromJson(json, Collection.class);
System.out.println("collection1 = " + collection1); // ==> [1.0, 2.0, 3.0, 4.0, 5.0]
}
Map 示例
由于Gson默认使用
toString()
序列化Map键,这可能导致格式错误的编码键,或者可能导致键的序列化和非序列化之间的不匹配。例如当
toString()
没有正确实现时。解决方法:使用 GsonBuilder#enableComplexMapKeySerialization() 来确保为Map键类型注册的
TypeAdapter
用于重复化和序列化。Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create();
当key为枚举时,如果Gson无法找到分别具有匹配的
name()
值和@SerializedName
注释的枚举常量,默认为枚举对象的toString()
值。
key为基本数据类型
@Test
public void test06(){
Gson gson = new Gson();
Map<String, String> stringMap = new LinkedHashMap<>();
stringMap.put("key", "value");
stringMap.put(null, "null-entry");
// 序列化
String json = gson.toJson(stringMap); // ==> {"key":"value","null":"null-entry"}
System.out.println("json = " + json);
// 反序列化
TypeToken<Map<String, String>> mapType = new TypeToken<Map<String, String>>(){};
Map<String, String> stringMap1 = gson.fromJson(json, mapType);
System.out.println("stringMap1 = " + stringMap1);
Map<Integer, Integer> intMap = new LinkedHashMap<>();
intMap.put(2, 4);
intMap.put(3, 6);
// 序列化
json = gson.toJson(intMap); // ==> {"2":4,"3":6}
System.out.println("json = " + json);
// 反序列化
TypeToken<Map<Integer, Integer>> typeToken = new TypeToken<Map<Integer, Integer>>() {};
Map<Integer, Integer> integerIntegerMap = gson.fromJson(json, typeToken);
System.out.println("integerIntegerMap = " + integerIntegerMap);
}
key为复杂类型
@Test
public void test07(){
Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create();
// 复杂对象
Map<ParentBag, ParentBag> bagMap = new HashMap<>();
bagMap.put(new ParentBag().id("11"), new ParentBag().id("AA"));
bagMap.put(new ParentBag().id("22"), new ParentBag().id("BB"));
String json = gson.toJson(bagMap);
System.out.println("json = " + json);
// 反序列化
TypeToken<Map<ParentBag, ParentBag>> mapTypeToken = new TypeToken< Map<ParentBag, ParentBag>>() {};
Map<ParentBag, ParentBag> bagMap1 = gson.fromJson(json, mapTypeToken);
System.out.println("bagMap1 = " + bagMap1);
}
key为枚举
@Test
public void test08(){
Gson gson = new Gson();
// 复杂对象
Map<Season, ParentBag> bagMap = new HashMap<>();
bagMap.put(Season.SPRING, new ParentBag().id("AA"));
bagMap.put(Season.SUMMER, new ParentBag().id("BB"));
String json = gson.toJson(bagMap);
System.out.println("json = " + json);
// 反序列化
TypeToken<Map<Season, ParentBag>> mapTypeToken = new TypeToken< Map<Season, ParentBag>>() {};
Map<Season, ParentBag> bagMap1 = gson.fromJson(json, mapTypeToken);
System.out.println("bagMap1 = " + bagMap1);
}
序列化和非序列化泛型类型
使用 com.google.gson.reflect.TypeToken<T>
错误写法
泛型对象反序列化为LinkedTreeMap对象,通过强转也会报错:
正确写法
@Test
public void test10(){
Gson gson = new Gson();
Foo<Bar> foo = new Foo<>();
foo.id("111");
foo.value(new Bar("222"));
String json = gson.toJson(foo);
System.out.println("json = " + json);
TypeToken<Foo<Bar>> typeToken = new TypeToken<Foo<Bar>>() {};
Foo<Bar> foo1 = gson.fromJson(json, typeToken);// Fails to deserialize foo.value as Bar
System.out.println("foo1 = " + foo1);
Bar value = foo1.value();
System.out.println("value = " + value);
}
自定义序列化和反序列化
有时候默认的表示并不是你想要的。在处理库类(DateTime等)时通常会出现这种情况。
步骤:
1. 自定义JSON序列化器,实现com.google.gson.JsonSerializer接口的serialize方法。
2. 自定义 JSON反序列化器,实现com.google.gson.JsonDeserializer接口的deserialize方法。
3. GsonBuilder#registerTypeAdapter方法注册。
Date示例
DateSerializer
import cn.hutool.core.date.DateUtil;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import java.util.Date;
public class DateSerializer implements JsonSerializer<Date> {
@Override
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(DateUtil.format(src, "yyyy-MM-dd HH:mm:ss"));
}
}
DateDeserializer
import cn.hutool.core.date.DateUtil;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.util.Date;
public class DateDeserializer implements JsonDeserializer<Date> {
@Override
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return DateUtil.parse(json.getAsJsonPrimitive().getAsString()).toJdkDate();
}
}
注册使用
@Test
public void tset11(){
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Date.class, new DateSerializer());
gsonBuilder.registerTypeAdapter(Date.class, new DateDeserializer());
Gson gson = gsonBuilder.create();
// 序列化
ParentBag parentBag = new ParentBag("111", null);
String json = gson.toJson(parentBag);
System.out.println("json = " + json);
// 反序列化
ParentBag parentBag1 = gson.fromJson(json, ParentBag.class);
System.out.println("parentBag1 = " + parentBag1);
}
JSON输出格式的紧凑打印与漂亮打印
Gson提供的默认JSON输出是一种紧凑的JSON格式。
如果您想使用Pretty Print功能,则必须使用 GsonBuilder 配置您的 Gson 实例。
提供了一个默认的 JsonPrintFormatter ,它具有80个字符的默认行长度,2个字符的缩进和4个字符的右边距。
@Test
public void test12(){
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Bar bar = new Bar("111");
String json = gson.toJson(bar);
System.out.println("json = " + json);
Bar bar1 = gson.fromJson(json, Bar.class);
System.out.println("bar1 = " + bar1);
}
Null值处理
Gson中实现的默认行为是忽略 null 对象字段。
@Test
public void test13(){
Gson gson = new GsonBuilder().serializeNulls().create();
ParentBag parentBag = new ParentBag("111", null);
String json = gson.toJson(parentBag);
System.out.println("json = " + json);
ParentBag parentBag1 = gson.fromJson(json, ParentBag.class);
System.out.println("parentBag1 = " + parentBag1);
}
版本控制支持
在Gson中,可以使用@Since注释维护同一对象的多个版本。可以在类,字段以及将来的方法中使用此注释。
当我们为Gson实例配置版本号“ 1.1”时,所有标记有版本大于1.1的类字段都将被忽略。例如,如果我们将Gson配置为版本号“ 1.2”,则所有版本号更高的字段(例如1.3、1.4…)都将被忽略。
使用GsonBuilder.setVersion()方法创建Gson实例。
1. 创建实体类
import com.google.gson.annotations.Since;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public class VersionedClass {
@Since(1.1)
private String newerField;
@Since(1.0)
private String newField;
private String field;
}
2. 使用
@Test
public void test14(){
VersionedClass versionedObject = new VersionedClass("newField", "newField", "field");
Gson gson = new GsonBuilder().setVersion(1.0).create();
String jsonOutput = gson.toJson(versionedObject);
System.out.println(jsonOutput);
gson = new Gson();
jsonOutput = gson.toJson(versionedObject);
System.out.println(jsonOutput);
}
排除字段
Java修饰符排除
默认情况下,字段标记为 transient ,或者 被标记为 static ,那么默认情况下它将被排除。
1. 新建实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public class ExcludeFieldClass {
private String value1;
private static String value2 = "value2";
private transient String value3;
}
2. 使用
@Test
public void test15() {
Gson gson = new Gson();
ExcludeFieldClass excludeFieldClass = new ExcludeFieldClass("value1", "value3");
String json = gson.toJson(excludeFieldClass);
System.out.println("json = " + json);
}
GsonBuilder#excludeFieldsWithModifiers方法
@Test
public void test16() {
// 都不排除
Gson gson = new GsonBuilder().excludeFieldsWithModifiers().create();
// 排除静态和瞬态
// Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT).create();
ExcludeFieldClass excludeFieldClass = new ExcludeFieldClass("value1", "value3");
String json = gson.toJson(excludeFieldClass);
System.out.println("json = " + json);
}
Gson 的 @Expose 注解
注解参数:
serialize –如果为true,则在序列化时会在JSON中写出带有此注解的字段。
deserialize –如果为true,则从JSON反序列化带有此注解的字段。实体类每个字段都得加注解,不加注解默认不参与序列化与反序列化。
必须使用 new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create() 来创建Gson实例。
1. 实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public class ExcludeFieldClass {
private String value1;
private static String value2 = "value2";
private transient String value3;
@Expose(serialize = false)
private String value4;
@Expose(deserialize = false)
private String value5;
@Expose(serialize = false, deserialize = false)
private String value6;
}
2. 使用:
@Test
public void test17() {
// 排除没有公开注释的字段
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
// 排除静态和瞬态
ExcludeFieldClass excludeFieldClass = new ExcludeFieldClass("value1", "value3", "value4", "value5", "value6");
String json = gson.toJson(excludeFieldClass);
System.out.println("json = " + json);
}
自定义的排除策略
步骤:
1. 实现 com.google.gson.ExclusionStrategy 接口
2. GsonBuilder#setExclusionStrategies注册
1. 定义排除注解:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Foo {
// Field tag only annotation
}
2. 自定义排除策略,实现 ExclusionStrategy 接口
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
public class MyExclusionStrategy implements ExclusionStrategy {
private final Class<?> typeToSkip;
public MyExclusionStrategy(Class<?> typeToSkip) {
this.typeToSkip = typeToSkip;
}
@Override
public boolean shouldSkipField(FieldAttributes f) {
return f.getAnnotation(Foo.class) != null;
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return (clazz == typeToSkip);
}
}
3. 注册并使用
@Test
public void test18() {
Gson gson = new GsonBuilder()
.setExclusionStrategies(new MyExclusionStrategy(String.class))
.serializeNulls()
.create();
SampleObjectForTest src = new SampleObjectForTest(5, "someDefaultValue", 1234L);
String json = gson.toJson(src);
System.out.println(json);
}
更改Java对象和JSON的字段名映射
@SerializedName注解
注解参数:
value:序列化或反序列化时字段的所需名称
alternate:反序列化时字段的备用名称
1. 新建实体类
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public class SomeObject {
@SerializedName(value = "custom_naming", alternate = "custom_naming_two")
private String someField;
private String someOtherField;
}
2. 使用
@Test
public void test19(){
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);
String json = "{\"custom_naming_two\":\"first_bak\",\"SomeOtherField\":\"second\"}";
SomeObject someObject1 = gson.fromJson(json, SomeObject.class);
System.out.println("someObject1 = " + someObject1);
}