Home Gson
Post
Cancel

Gson

[TOC]

一位博主翻译的系列教程,都是官方推荐教程。

Gson用户指南(中文翻译)

Gson教程一(译):Java-JSON的序列化和反序列化

Gson教程二(译):嵌套对象的序列化和反序列化

Gson教程三(译):Arrays和Lists的映射

Gson教程四(译):Maps的映射

Gson教程五(译):Sets的映射

Gson教程六(译):空值的映射

Gson教程七(译):@SerializedName和@Expose

Gson教程八(译):GsonBuilder基础以及命名策略

Gson教程九(译):强制序列化null值

Gson教程十(译):Exclusion Strategies

Gson教程十一(译):轻松使用仁慈的Gson(容错机制)

Gson教程十二(译):Float和Double类型的特殊值

Gson教程十三:模型版本化、日期格式化、漂亮输出

Gson完全教程:基础篇

一、Gson 介绍

Gson 是一个 Java 对象与 Json 格式互转的类库。

  • 提供简单的 toJson()fromJson() 方法用于 Java 对象和 Json 互转
  • 允许已存在的、无法修改的类与 Json 互转
  • 支持泛型
  • 允许自定义对象的Json格式
  • 支持复杂对象(多层继承、泛型)

API Javadoc User guide

Gradle:

1
2
3
dependencies {
  implementation 'com.google.code.gson:gson:2.8.5'
}

Maven:

1
2
3
4
5
<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.8.5</version>
</dependency>

二、基本使用

1. 序列化

  1. 字符串类型 String 转为 “xxx”:”name”: “Norman”
  2. 非字符串类型 int、boolean 等转为 xxx:”age”: 26
  3. 对象转为 {xxx}:”userAddress”: {xxx}
  4. 数组转为 [xxx]:”families”: [xxx]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@AllArgsConstructor
class UserNested {
    String name;
    String email;
    int age;
    boolean isDeveloper;
    UserAddress userAddress;
    String[] families;
}

@AllArgsConstructor
class UserAddress {
    String street;
    String houseNumber;
    String city;
    String country;
}

UserAddress userAddress = new UserAddress(
        "Main Street",
        "42A",
        "Magdeburg",
        "Germany"
);

UserNested userObject = new UserNested(
        "Norman",
        "norman@futurestud.io",
        26,
        true,
        userAddress,
        new String[]{"mother", "father", "son"}
);

Gson gson = new Gson();
String userWithAddressJson = gson.toJson(userObject);
System.out.println(userWithAddressJson);

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
  "name": "Norman",
  "email": "norman@futurestud.io",
  "age": 26,
  "isDeveloper": true,
  "userAddress": {
    "street": "Main Street",
    "houseNumber": "42A",
    "city": "Magdeburg",
    "country": "Germany"
  },
  "families": [
    "mother",
    "father",
    "son"
  ]
}

2. 反序列化

反序列化时需要指定具体类:gson.fromJson(restaurantJson, Restaurant.class)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Data
@AllArgsConstructor
class Restaurant {
    String name;
    Owner owner;
    Cook cook;
    Waiter waiter;
}

@Data
@AllArgsConstructor
class Owner {
    String name;
    UserAddress address;
}

@Data
@AllArgsConstructor
class Cook {
    String name;
    int age;
    int salary;
}

@Data
@AllArgsConstructor
class Waiter {
    String name;
    int age;
    int salary;
}

String restaurantJson = "{ 'name':'Future Studio Steak House', 'owner':{ 'name':'Christian', 'address':{ 'city':'Magdeburg', 'country':'Germany', 'houseNumber':'42', 'street':'Main Street'}},'cook':{ 'age':18, 'name': 'Marcus', 'salary': 1500 }, 'waiter':{ 'age':18, 'name': 'Norman', 'salary': 1000}}";
gson = new Gson();
Restaurant restaurantObject = gson.fromJson(restaurantJson, Restaurant.class);
System.out.println(restaurantObject);

输出

1
Restaurant(name=Future Studio Steak House, owner=Owner(name=Christian, address=UserAddress(street=Main Street, houseNumber=42, city=Magdeburg, country=Germany)), cook=Cook(name=Marcus, age=18, salary=1500), waiter=Waiter(name=Norman, age=18, salary=1000))

3. 空值映射

  • While serializing, a null field is omitted from the output.
  • While deserializing, a missing entry in JSON results in setting the corresponding field in the object to its default value: null for object types, zero for numeric types, and false for booleans.

默认情况下

  • 序列化时,Java对象里的空值被忽略
  • 反序列化时,Json里的缺失项会被赋予默认值:对象为 null,数值类型为 0,布尔类型为 false
1
2
3
4
5
6
7
8
9
10
11
12
13
@Data
@AllArgsConstructor
class UserSimple {
    String name;
    String email;
    int age;
    boolean isDeveloper;
}

UserSimple userObject = new UserSimple(null, "norman@futurestud.io", 26, true);
Gson gson = new Gson();
String userJson = gson.toJson(userObject);
System.out.println(userJson);

输出

1
2
3
4
5
{
  "email": "norman@futurestud.io",
  "age": 26,
  "isDeveloper": true
}

三、泛型

对于泛型会遇到泛型擦除的问题。譬如,对于 **Result** 和 **Result**,使用基本的fromJson 方法时 Gson 无法判断实际的类型,因为参数都是 **Result.class**。

1
2
3
4
5
public class Result<T> {
    public int code;
    public String message;
    public T data;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
UserAddress userAddress = new UserAddress(
        "Main Street",
        "42A",
        "Magdeburg",
        "Germany"
);
Result<UserAddress> result = new Result<>(200, "success", userAddress);
Gson gson = new Gson();
String resultJson = gson.toJson(result);
System.out.println(resultJson);

// Result.class方式下,T的类型为LinkedTreeMap
result = gson.fromJson(resultJson, Result.class);
System.out.println(result);

// TypeToken方式下,T的类型为UserAddress
result = gson.fromJson(resultJson, new TypeToken<Result<UserAddress>>(){}.getType());
System.out.println(result);

Result.class,data 类型为:LinkedTreeMap。

Result.class

TypeToken,data 类型为:UserAddress。

Result.class

四、其他使用

1. GsonBuilder

new Gson() 只能获取默认配置的 Gson,通过 GsonBuilder 可以实现多种配置。几个常用配置:

  • serializeNulls(),对 null 值进行序列化。

    1
    2
    3
    4
    5
    6
    
    GsonBuilder gsonBuilder = new GsonBuilder();  
    gsonBuilder.serializeNulls();  
    Gson gson = gsonBuilder.create();
      
    UserSimple user = new UserSimple("Norman", null, 26, true);  
    String usersJson = gson.toJson(user);  
    

    输出,email 的 null 也进行了序列化。

    1
    2
    3
    4
    5
    6
    
    {
      "age": 26,
      "email": null,
      "isDeveloper": true,
      "name": "Norman"
    }
    
  • setFieldNamingPolicy(FieldNamingPolicy namingConvention),Java 对象转为 Json 时所有域名的命名规则。

    • FieldNamingPolicy.IDENTITY:保持域名不变
    • FieldNamingPolicy.UPPER_CAMEL_CASE:大驼峰,someFieldName —> SomeFieldName
    • FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES:大驼峰+空格,someFieldName —> Some Field Name
    • FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES:小写+下划线,someFieldName —> some_field_name
    • FieldNamingPolicy.LOWER_CASE_WITH_DASHES:小写+中划线,someFieldName —> some-field-name
    • FieldNamingPolicy.LOWER_CASE_WITH_DOTS:小写+点,someFieldName —> some.field.name
  • setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy),FieldNamingPolicy 无法满足使用要求时,可以自定义域名的命名策略。

    1
    2
    3
    4
    5
    6
    7
    8
    
    UserSimple userObject = new UserSimple(null, "norman@futurestud.io", 26, true);
      
    GsonBuilder gb = new GsonBuilder();
    gb.setFieldNamingStrategy(f -> f.getName().toUpperCase());
    Gson gson = gb.create();
      
    String userJson = gson.toJson(userObject);
    System.out.println(userJson);
    

    输出,所有域名都是大写了。

    1
    2
    3
    4
    5
    
    {
      "EMAIL": "norman@futurestud.io",
      "AGE": 26,
      "ISDEVELOPER": true
    }
    
  • setExclusionStrategies(ExclusionStrategy… strategies),自定义的域排除策略,有两个方法供重写,重写后返回为 true 的域将被排除在外,不进行序列化。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    UserSimple userObject = new UserSimple("Tony", "norman@futurestud.io", 26, true);
    GsonBuilder gb = new GsonBuilder();
    gb.setExclusionStrategies(new ExclusionStrategy() {
        @Override
        public boolean shouldSkipField(FieldAttributes f) {
            return f.getName().startsWith("e");
        }
      
        @Override
        public boolean shouldSkipClass(Class<?> clazz) {
            return clazz == int.class;
        }
    });
      
    Gson gson = gb.create();
    String userJson = gson.toJson(userObject);
    System.out.println(userJson);
      
    gson = new Gson();
    userJson = gson.toJson(userObject);
    System.out.println(userJson);
    

    输出,开头为 e 的域被排除、整数型的域被排除。

    1
    2
    3
    4
    
    {
      "name": "Tony",
      "isDeveloper": true
    }
    

    另外还有两个可以单独配置序列化、反序列化的方法:

    • addSerializationExclusionStrategy(ExclusionStrategy strategy)
    • addDeserializationExclusionStrategy(ExclusionStrategy strategy)
  • setPrettyPrinting(),格式化输出,默认的输出格式都挤在一行,没有换行和缩进。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    // 格式化后的
    {
      "name": "Tony",
      "email": "norman@futurestud.io",
      "age": 26,
      "isDeveloper": true
    }
    // 格式化前的
    {"name":"Tony","email":"norman@futurestud.io","age":26,"isDeveloper":true}
    
  • setVersion(double ignoreVersionsAfter),排除设定版本外的域,结合 @Since@Until 域注解使用,详见后文。

  • excludeFieldsWithoutExposeAnnotation(),排除没有 expose 注解的域,没有 @Expose 注解的域都不会被序列化和反序列化,详见后文。

2. 域注解

  • @Since,指定该域在某一版本及之后才存在。Java 对象转 Json 以 setVersion(double ignoreVersionsAfter) 中设定的版本为界,如 setVersion(0.99) 设定了版本为 0.99,那么所有 @Since 大于 0.99 的域都不会转 Json。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    @Data
    @AllArgsConstructor
    class UserSimple {
        String name;
        String email;
        int age;
        @Since(1.0)
        boolean isDeveloper;
    }
      
    UserSimple userObject = new UserSimple("Tony", "norman@futurestud.io", 26, true);
      
    GsonBuilder gb = new GsonBuilder();
    gb.setPrettyPrinting();
    gb.setVersion(0.99);
    Gson gson = gb.create();
      
    String userJson = gson.toJson(userObject);
    System.out.println(userJson);
    

    输出,版本 1.0 > 版本 0.99,所以 isDeveloper 被排除。

    1
    2
    3
    4
    5
    
    {
      "name": "Tony",
      "email": "norman@futurestud.io",
      "age": 26
    }
    
  • @Until,指定该域一直存在到某一版本。如 setVersion(1.01) 设定了版本为 1.01,那么所有 @Until 小于 1.01 的域都不会转 Json。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    @Data
    @AllArgsConstructor
    class UserSimple {
        String name;
        String email;
        int age;
        @Until(1.0)
        boolean isDeveloper;
    }
      
    UserSimple userObject = new UserSimple("Tony", "norman@futurestud.io", 26, true);
      
    GsonBuilder gb = new GsonBuilder();
    gb.setPrettyPrinting();
    gb.setVersion(1.01);
    Gson gson = gb.create();
      
    String userJson = gson.toJson(userObject);
    System.out.println(userJson);
    

    输出,版本 1.0 < 版本 1.01,所以 isDeveloper 被排除。

    1
    2
    3
    4
    5
    
    {
      "name": "Tony",
      "email": "norman@futurestud.io",
      "age": 26
    }
    
  • @Expose,配置 excludeFieldsWithoutExposeAnnotation() 后,没有 @Expose 注解的域将不会转为 Json。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    @Data
    @AllArgsConstructor
    class UserSimple {
        @Expose
        String name;
        @Expose
        String email;
        @Expose
        int age;
        boolean isDeveloper;
    }
      
    UserSimple userObject = new UserSimple("Tony", "norman@futurestud.io", 26, true);
      
    GsonBuilder gb = new GsonBuilder();
    gb.setPrettyPrinting();
    gb.excludeFieldsWithoutExposeAnnotation();
    Gson gson = gb.create();
      
    String userJson = gson.toJson(userObject);
    System.out.println(userJson);
    

    输出,没有 @Expose 注解的 isDeveloper 被排除了。

    1
    2
    3
    4
    5
    
    {
      "name": "Tony",
      "email": "norman@futurestud.io",
      "age": 26
    }
    
  • transientstatic,这两个关键字修饰的域默认不转 Json。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    @Data
    @AllArgsConstructor
    class UserSimple {
        String name;
        String email;
        static int age;
        transient boolean isDeveloper;
    }
      
    UserSimple userObject = new UserSimple("Tony", "norman@futurestud.io",  true);
      
    GsonBuilder gb = new GsonBuilder();
    gb.setPrettyPrinting();
    Gson gson = gb.create();
      
    String userJson = gson.toJson(userObject);
    

    输出,static 修饰的 age 和 transient 修饰的 isDeveloper 都被排除。

    1
    2
    3
    4
    
    {
      "name": "Tony",
      "email": "norman@futurestud.io"
    }
    
  • @SerializedName,自定序列化和反序列化时 Json 中对应的域名。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    @Data
    @AllArgsConstructor
    class UserSimple {
        @SerializedName("MyName")
        String name;
        String email;
        @SerializedName("YourAge")
        int age;
        boolean isDeveloper;
    }
      
    UserSimple userObject = new UserSimple("Tony", "norman@futurestud.io", 26, true);
      
    GsonBuilder gb = new GsonBuilder();
    gb.setPrettyPrinting();
    Gson gson = gb.create();
      
    String userJson = gson.toJson(userObject);
    System.out.println(userJson);
    

    输出,name 对应 MyName,age 对应 YourAge。

    1
    2
    3
    4
    5
    6
    
    {
      "MyName": "Tony",
      "email": "norman@futurestud.io",
      "YourAge": 26,
      "isDeveloper": true
    }
    
This post is licensed under CC BY 4.0 by the author.