抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

摘要:本文介绍了如何在Java中使用GSON进行JSON的序列化和反序列化操作。

环境

Windows 10 企业版 LTSC 21H2
Java 1.8

1 简介

GSON是Google提供的一个Java库,用于将Java对象转换为JSON字符串,以及将JSON字符串转换为Java对象。它简单易用,支持复杂的数据类型,包括嵌套对象和集合。

2 基础使用

pom.xml中添加依赖:

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

定义Java类:

Student.java
1
2
3
4
5
6
public class Student {
private String name;
private int age;
private List<String> hobbies;
// 省略其他方法
}

序列化:

java
1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
// 创建Student对象
Student student = new Student();
student.setName("张三");
student.setAge(20);
student.setHobbies(Arrays.asList("阅读", "编程", "运动"));
// 创建Gson实例
Gson gson = new Gson();
// 将对象序列化为JSON字符串
String json = gson.toJson(student);
System.out.println("序列化结果: " + json);
}

反序列化:

java
1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
// 创建JSON字符串
String json = "{\"name\":\"张三\",\"age\":20,\"hobbies\":[\"阅读\",\"编程\",\"运动\"]}";
// 创建Gson实例
Gson gson = new Gson();
// 将JSON字符串反序列化为Student对象
Student student = gson.fromJson(json, Student.class);
System.out.println("反序列化结果: " + student.getName() + ", " + student.getAge() + ", " + student.getHobbies());
}

3 处理泛型

在反序列化泛型对象时,会因为类型擦除的问题,导致反序列化时无法正确识别泛型类型:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) {
Student student = new Student();
student.setName("张三");
List<Student> studentList = new ArrayList<>();
studentList.add(student);
Gson gson = new Gson();
// [{"name":"张三"}]
String jsonString = gson.toJson(studentList);
System.out.println(jsonString);
// 异常信息 ClassCastException: LinkedTreeMap cannot be cast to Student
List<Student> jsonList = gson.fromJson(jsonString, List.class);
System.out.println(jsonList.get(0).getName());
}

可以使用TypeToken解决运行时的泛型类型擦除问题:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) {
Student student = new Student();
student.setName("张三");
List<Student> studentList = new ArrayList<>();
studentList.add(student);
Gson gson = new Gson();
// [{"name":"张三","age":0}]
String jsonString = gson.toJson(studentList);
System.out.println(jsonString);
// 张三
List<Student> jsonList = gson.fromJson(gson.toJson(studentList), new TypeToken<List<Student>>() {}.getType());
System.out.println(jsonList.get(0).getName());
}

4 流式处理

4.1 序列化

使用JsonWriter类实现序列化。

构造方法:

java
1
public JsonWriter(Writer out);

常用方法:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 开始解析对象
public JsonWriter beginObject() throws IOException;
// 结束解析对象
public JsonWriter endObject() throws IOException;
// 开始解析数组
public JsonWriter beginArray() throws IOException;
// 结束解析数组
public JsonWriter endArray() throws IOException;
// 设置属性名
public JsonWriter name(String name) throws IOException;
// 设置布尔属性值
public JsonWriter value(Boolean value) throws IOException;
// 设置数字属性值
public JsonWriter value(Number value) throws IOException;
// 设置null属性值
public JsonWriter nullValue() throws IOException;
// 设置字符串属性值
public JsonWriter value(String value) throws IOException;

自动序列化:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String[] args) {
Student student = new Student();
student.setName("张三");
student.setAge(20);
student.setHobbies(Arrays.asList("阅读", "编程", "运动"));
Type type = new TypeToken<Student>() {}.getType();
Gson gson = new Gson();
try (StringWriter stringWriter = new StringWriter();
JsonWriter jsonWriter = new JsonWriter(stringWriter)) {
gson.toJson(student, type, jsonWriter);
System.out.println("序列化结果: " + stringWriter);
} catch (IOException e) {
e.printStackTrace();
}
}

手动序列化:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void main(String[] args) {
Student student = new Student();
student.setName("张三");
student.setAge(20);
student.setHobbies(Arrays.asList("阅读", "编程", "运动"));
try (StringWriter stringWriter = new StringWriter();
JsonWriter jsonWriter = new JsonWriter(stringWriter)) {
jsonWriter.beginObject();
jsonWriter.name("name");
jsonWriter.value(student.getName());
jsonWriter.name("age");
jsonWriter.value(student.getAge());
jsonWriter.name("hobbies");
jsonWriter.beginArray();
for (String hobby : student.getHobbies()) {
jsonWriter.value(hobby);
}
jsonWriter.endArray();
jsonWriter.endObject();
System.out.println("序列化结果: " + stringWriter);
} catch (IOException e) {
e.printStackTrace();
}
}

4.2 反序列化

使用JsonReader类实现反序列化。

构造方法:

java
1
public JsonReader(Reader in);

常用方法:

java
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
// 开始解析对象
public void beginObject() throws IOException;
// 结束解析对象
public void endObject() throws IOException;
// 开始解析数组
public void beginArray() throws IOException;
// 结束解析数组
public void endArray() throws IOException;
// 判断是否有下一个元素
public boolean hasNext() throws IOException;
// 获取下一个元素的名称
public String nextName() throws IOException;
// 获取下一个元素的布尔类型的值
public boolean nextBoolean() throws IOException;
// 获取下一个元素的int类型的值
public int nextInt() throws IOException;
// 获取下一个元素的long类型的值
public long nextLong() throws IOException;
// 获取下一个元素的double类型的值
public double nextDouble() throws IOException;
// 获取下一个元素的null类型的值
public void nextNull() throws IOException;
// 获取下一个元素的字符串类型的值
public String nextString() throws IOException;
// 跳过下一个元素
public void skipValue() throws IOException;

自动反序列化:

java
1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
String json = "{\"name\":\"张三\",\"age\":20,\"hobbies\":[\"阅读\",\"编程\",\"运动\"]}";
Type type = new TypeToken<Student>() {}.getType();
Gson gson = new Gson();
try (StringReader stringReader = new StringReader(json);
JsonReader jsonReader = new JsonReader(stringReader)) {
Student student = gson.fromJson(jsonReader, type);
System.out.println("反序列化结果: " + student.getName() + ", " + student.getAge() + ", " + student.getHobbies());
} catch (IOException e) {
e.printStackTrace();
}
}

手动反序列化:

java
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
public static void main(String[] args) {
String json = "{\"name\":\"张三\",\"age\":20,\"hobbies\":[\"阅读\",\"编程\",\"运动\"]}";
try (StringReader stringReader = new StringReader(json);
JsonReader jsonReader = new JsonReader(stringReader)) {
Student student = new Student();
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
switch (name) {
case "name":
student.setName(jsonReader.nextString());
break;
case "age":
student.setAge(jsonReader.nextInt());
break;
case "hobbies":
jsonReader.beginArray();
while (jsonReader.hasNext()) {
if (student.getHobbies() == null) {
student.setHobbies(new ArrayList<>());
}
student.getHobbies().add(jsonReader.nextString());
}
jsonReader.endArray();
break;
default:
jsonReader.skipValue();
break;
}
}
jsonReader.endObject();
System.out.println("反序列化结果: " + student.getName() + ", " + student.getAge() + ", " + student.getHobbies());
} catch (IOException e) {
e.printStackTrace();
}
}

5 修改配置

使用GsonBuilder修改默认配置

构造方法:

java
1
public GsonBuilder();

常用方法:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 设置日期格式
public GsonBuilder setDateFormat(String pattern);
// 设置输出格式,添加缩进和换行
public GsonBuilder setPrettyPrinting();
// 设置字段命名策略,使用预定义的策略
public GsonBuilder setFieldNamingPolicy(FieldNamingPolicy namingConvention);
// 设置字段命名策略,使用自定义的策略
public GsonBuilder setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy);
// 设置排除策略
public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies);
// 设置序列化策略
public GsonBuilder addSerializationExclusionStrategy(ExclusionStrategy strategy);
// 设置反序列化策略
public GsonBuilder addDeserializationExclusionStrategy(ExclusionStrategy strategy);
// 注册类型适配器
public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter);
// 注册类型适配器工厂
public GsonBuilder registerTypeAdapterFactory(TypeAdapterFactory factory);
// 根据版本排除字段
public GsonBuilder setVersion(double version);
// 根据注解排除字段
public GsonBuilder excludeFieldsWithoutExposeAnnotation();
// 根据访问修饰符排除字段
public GsonBuilder excludeFieldsWithModifiers(int... modifiers);

预定义的字段命名策略:

  • IDENTITY:Java字段名和JSON键名完全一致,不做任何修改,默认策略。
  • LOWER_CASE_WITH_UNDERSCORES:Java字段名使用驼峰命名,JSON键名小写并使用下划线_分隔。
  • LOWER_CASE_WITH_DASHES:Java字段名使用驼峰命名,JSON键名小写并使用中横线-分隔。
  • LOWER_CASE_WITH_DOTS:Java字段名使用驼峰命名,JSON键名小写并使用点号.分隔。
  • UPPER_CAMEL_CASE:Java字段名使用驼峰命名,JSON键名首字母大写并使用驼峰命名。
  • UPPER_CAMEL_CASE_WITH_SPACES:Java字段名使用驼峰命名,JSON键名首字母大写并使用空格分隔。

示例:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String[] args) {
Student student = new Student();
student.setName("张三");
student.setAge(20);
student.setHobbies(Arrays.asList("阅读", "编程", "运动"));
Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.IDENTITY)
.create();
// 序列化
String jsonString = gson.toJson(student);
System.out.println("序列化结果: " + jsonString);
// 反序列化
Student jsonObject = gson.fromJson(jsonString, Student.class);
System.out.println("反序列化结果: " + jsonObject.getName() + ", " + jsonObject.getAge() + ", " + jsonObject.getHobbies());
}

6 字段处理

6.1 字段映射

使用@SerializedName注解实现字段映射。

指定JSON键名:

java
1
2
3
4
public class Student {
@SerializedName("student_name")
private String name;
}

反序列化支持多个JSON键名,以最后的值为准:

java
1
2
3
4
public class Student {
@SerializedName(value = "student_name", alternate = {"student-name", "student.name"})
private String name;
}

6.2 字段过滤

6.2.1 暴露字段

使用@Expose注解实现字段过滤,需要配合GsonBuilder的excludeFieldsWithoutExposeAnnotation()方法使用。

定制序列化和反序列化的规则:

java
1
2
3
4
5
6
7
8
public class Student {
@Expose(serialize = true, deserialize = true)
private String name;
@Expose(serialize = false, deserialize = true)
private int age;
@Expose(serialize = true, deserialize = false)
private List<String> hobbies;
}

修改GsonBuilder配置,开启注解:

java
1
2
3
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();

说明:

  • 使用了@Expose注解,且serialize和deserialize都为true,则序列化和反序列化都处理该字段。
  • 使用了@Expose注解,且serialize为true,deserialize为false,则序列化处理该字段,反序列化忽略该字段。
  • 使用了@Expose注解,且serialize为false,deserialize为true,则反序列化处理该字段,序列化忽略该字段。
  • 未使用@Expose注解,则序列化和反序列化都忽略该字段。

当取值为true时,可以省略配置。

6.2.2 版本控制

使用@Since注解和@Until注解实现版本控制,需要配合GsonBuilder的setVersion()方法使用。

设置版本,传入double类型的版本:

java
1
2
3
4
5
6
7
8
public class Student {
@Since(1.0)
private String name;
@Since(2.0)
private int age;
@Until(2.0)
private List<String> hobbies;
}

修改GsonBuilder配置,指定版本:

java
1
2
3
Gson gson = new GsonBuilder()
.setVersion(1.0)
.create();

说明:

  • 如果配置的版本大于等于@Since注解的版本,则序列化和反序列化都处理该字段,否则忽略该字段。
  • 如果配置的版本小于@Until注解的版本,则序列化和反序列化都处理该字段,否则忽略该字段。

6.2.3 访问修饰符

使用GsonBuilder的excludeFieldsWithModifiers()方法根据访问修饰符排除字段。

需要传入int类型的访问修饰符,取值由java.lang.reflect包下的Modifier类提供,常用取值:

  • Modifier.PUBLIC
  • Modifier.PRIVATE
  • Modifier.PROTECTED
  • Modifier.STATIC
  • Modifier.FINAL
  • Modifier.SYNCHRONIZED

修改GsonBuilder配置,指定排除的访问修饰符:

java
1
2
3
Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.PUBLIC, Modifier.PROTECTED)
.create();

6.2.4 自定义策略

使用GsonBuilder的方法根据自定义策略排除字段:

  • 使用setExclusionStrategies()方法设置全局排除策略,可以传入多个排除策略。
  • 使用addSerializationExclusionStrategy()方法添加序列化排除策略,同时使用会覆盖全局排除策略。
  • 使用addDeserializationExclusionStrategy()方法添加反序列化排除策略,同时使用会覆盖全局排除策略。

修改GsonBuilder配置,使用策略:

java
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
Gson gson = new GsonBuilder()
.setExclusionStrategies(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes field) {
// 通过字段名排除
if (field.getName().equals("hobbies")) {
return true;
}
// 通过@Expose注解排除
if (field.getAnnotation(Expose.class) != null) {
return true;
}
// 通过定义的类型排除
if (field.getDeclaredClass().equals(String.class)) {
return true;
}
// 通过所属的类型排除
if (field.getDeclaringClass().equals(Student.class)) {
return true;
}
// 通过访问修饰符排除
if (Modifier.isPrivate(field.getDeclaringClass().getModifiers())) {
return true;
}
return false;
}

@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
})
.create();

7 自定义处理

7.1 双向处理

使用TypeAdapter实现序列化和反序列化。

示例:

java
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public static void main(String[] args) {
Student student = new Student();
student.setName("张三");
student.setAge(20);
student.setHobbies(Arrays.asList("阅读", "编程", "运动"));
// 创建自定义的TypeAdapter实例
TypeAdapter typeAdapter = new TypeAdapter<Student>() {
@Override
public void write(JsonWriter jsonWriter, Student student) throws IOException {
jsonWriter.beginObject();
jsonWriter.name("name");
jsonWriter.value(student.getName());
jsonWriter.name("age");
jsonWriter.value(student.getAge());
jsonWriter.name("hobbies");
jsonWriter.beginArray();
for (String hobby : student.getHobbies()) {
jsonWriter.value(hobby);
}
jsonWriter.endArray();
jsonWriter.endObject();
}

@Override
public Student read(JsonReader jsonReader) throws IOException {
Student student = new Student();
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
switch (name) {
case "name":
student.setName(jsonReader.nextString());
break;
case "age":
student.setAge(jsonReader.nextInt());
break;
case "hobbies":
jsonReader.beginArray();
while (jsonReader.hasNext()) {
if (student.getHobbies() == null) {
student.setHobbies(new ArrayList<>());
}
student.getHobbies().add(jsonReader.nextString());
}
jsonReader.endArray();
break;
default:
jsonReader.skipValue();
break;
}
}
jsonReader.endObject();
return student;
}
};
// 修改GsonBuilder配置,注册自定义的TypeAdapter实例
Gson gson = new GsonBuilder()
.registerTypeAdapter(Student.class, typeAdapter)
.create();
// 序列化
String jsonString = gson.toJson(student);
System.out.println("序列化结果: " + jsonString);
// 反序列化
Student jsonObject = gson.fromJson(jsonString, Student.class);
System.out.println("反序列化结果: " + jsonObject.getName() + ", " + jsonObject.getAge() + ", " + jsonObject.getHobbies());
}

7.2 单向处理

7.2.1 序列化

使用JsonSerializer自定义序列化:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void main(String[] args) {
Student student = new Student();
student.setName("张三");
student.setAge(20);
student.setHobbies(Arrays.asList("阅读", "编程", "运动"));
// 创建自定义的JsonSerializer实例
JsonSerializer<Student> serializer = new JsonSerializer<Student>() {
@Override
public JsonElement serialize(Student src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("name", src.getName());
jsonObject.addProperty("age", src.getAge());
jsonObject.add("hobbies", context.serialize(src.getHobbies()));
return jsonObject;
}
};
// 修改GsonBuilder配置,注册自定义的JsonSerializer实例
Gson gson = new GsonBuilder()
.registerTypeAdapter(Student.class, serializer)
.create();
// 序列化
String json = gson.toJson(student);
System.out.println("序列化结果: " + json);
}

7.2.2 反序列化

使用JsonDeserializer自定义反序列化:

java
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
public static void main(String[] args) {
String json = "{\"name\":\"张三\",\"age\":20,\"hobbies\":[\"阅读\",\"编程\",\"运动\"]}";
// 创建自定义的JsonDeserializer实例
JsonDeserializer<Student> deserializer = new JsonDeserializer<Student>() {
@Override
public Student deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
Student student = new Student();
student.setName(jsonObject.get("name").getAsString());
student.setAge(jsonObject.get("age").getAsInt());
JsonArray hobbiesArray = jsonObject.get("hobbies").getAsJsonArray();
List<String> hobbiesList = new ArrayList<>();
for (int i = 0; i < hobbiesArray.size(); i++) {
hobbiesList.add(hobbiesArray.get(i).getAsString());
}
student.setHobbies(hobbiesList);
return student;
}
};
// 修改GsonBuilder配置,注册自定义的JsonDeserializer实例
Gson gson = new GsonBuilder()
.registerTypeAdapter(Student.class, deserializer)
.create();
// 反序列化
Student student = gson.fromJson(json, Student.class);
System.out.println("反序列化结果: " + student.getName() + ", " + student.getAge() + ", " + student.getHobbies());
}

7.3 使用注解

使用@JsonAdapter注解后,可以省略修改GsonBuilder配置的逻辑,不需要通过匿名类实现接口。

创建StudentTypeAdapter类继承TypeAdapter抽象类:

StudentTypeAdapter.java
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
38
39
40
41
42
43
44
45
46
47
48
49
public class StudentTypeAdapter extends TypeAdapter<Student> {
@Override
public void write(JsonWriter jsonWriter, Student student) throws IOException {
jsonWriter.beginObject();
jsonWriter.name("name");
jsonWriter.value(student.getName());
jsonWriter.name("age");
jsonWriter.value(student.getAge());
jsonWriter.name("hobbies");
jsonWriter.beginArray();
for (String hobby : student.getHobbies()) {
jsonWriter.value(hobby);
}
jsonWriter.endArray();
jsonWriter.endObject();
}

@Override
public Student read(JsonReader jsonReader) throws IOException {
Student student = new Student();
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
switch (name) {
case "name":
student.setName(jsonReader.nextString());
break;
case "age":
student.setAge(jsonReader.nextInt());
break;
case "hobbies":
jsonReader.beginArray();
while (jsonReader.hasNext()) {
if (student.getHobbies() == null) {
student.setHobbies(new ArrayList<>());
}
student.getHobbies().add(jsonReader.nextString());
}
jsonReader.endArray();
break;
default:
jsonReader.skipValue();
break;
}
}
jsonReader.endObject();
return student;
}
}

在Student类上使用@JsonAdapter注解,指定StudentTypeAdapter类:

Student.java
1
2
3
4
@JsonAdapter(StudentTypeAdapter.class)
public class Student {
// 省略代码
}

如果没有其他配置可以省略GsonBulider的配置,直接使用Gson实例:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) {
Student student = new Student();
student.setName("张三");
student.setAge(20);
student.setHobbies(Arrays.asList("阅读", "编程", "运动"));
// 直接使用Gson示例
Gson gson = new Gson();
// 序列化
String jsonString = gson.toJson(student);
System.out.println("序列化结果: " + jsonString);
// 反序列化
Student jsonObject = gson.fromJson(jsonString, Student.class);
System.out.println("反序列化结果: " + jsonObject.getName() + ", " + jsonObject.getAge() + ", " + jsonObject.getHobbies());
}

评论