摘要:本文介绍了如何在Java中使用GSON进行JSON的序列化和反序列化操作。
环境
Windows 10 企业版 LTSC 21H2
Java 1.8
1 简介
GSON是Google提供的一个Java库,用于将Java对象转换为JSON字符串,以及将JSON字符串转换为Java对象。它简单易用,支持复杂的数据类型,包括嵌套对象和集合。
2 基础使用
在pom.xml中添加依赖:
pom.xml1 2 3 4 5
| <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.9</version> </dependency>
|
定义Java类:
Student.java1 2 3 4 5 6
| public class Student { private String name; private int age; private List<String> hobbies; }
|
序列化:
java1 2 3 4 5 6 7 8 9 10 11 12
| public static void main(String[] args) { Student student = new Student(); student.setName("张三"); student.setAge(20); student.setHobbies(Arrays.asList("阅读", "编程", "运动")); Gson gson = new Gson(); String json = gson.toJson(student); System.out.println("序列化结果: " + json); }
|
反序列化:
java1 2 3 4 5 6 7 8 9
| public static void main(String[] args) { String json = "{\"name\":\"张三\",\"age\":20,\"hobbies\":[\"阅读\",\"编程\",\"运动\"]}"; Gson gson = new Gson(); Student student = gson.fromJson(json, Student.class); System.out.println("反序列化结果: " + student.getName() + ", " + student.getAge() + ", " + student.getHobbies()); }
|
3 处理泛型
在反序列化泛型对象时,会因为类型擦除的问题,导致反序列化时无法正确识别泛型类型:
java1 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(); String jsonString = gson.toJson(studentList); System.out.println(jsonString); List<Student> jsonList = gson.fromJson(jsonString, List.class); System.out.println(jsonList.get(0).getName()); }
|
可以使用TypeToken解决运行时的泛型类型擦除问题:
java1 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(); 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类实现序列化。
构造方法:
java1
| public JsonWriter(Writer out);
|
常用方法:
java1 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;
public JsonWriter nullValue() throws IOException;
public JsonWriter value(String value) throws IOException;
|
自动序列化:
java1 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(); } }
|
手动序列化:
java1 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类实现反序列化。
构造方法:
java1
| public JsonReader(Reader in);
|
常用方法:
java1 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;
public int nextInt() throws IOException;
public long nextLong() throws IOException;
public double nextDouble() throws IOException;
public void nextNull() throws IOException;
public String nextString() throws IOException;
public void skipValue() throws IOException;
|
自动反序列化:
java1 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(); } }
|
手动反序列化:
java1 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
常用方法:
java1 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键名首字母大写并使用空格分隔。
示例:
java1 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键名:
java1 2 3 4
| public class Student { @SerializedName("student_name") private String name; }
|
反序列化支持多个JSON键名,以最后的值为准:
java1 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()方法使用。
定制序列化和反序列化的规则:
java1 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配置,开启注解:
java1 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类型的版本:
java1 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配置,指定版本:
java1 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配置,指定排除的访问修饰符:
java1 2 3
| Gson gson = new GsonBuilder() .excludeFieldsWithModifiers(Modifier.PUBLIC, Modifier.PROTECTED) .create();
|
6.2.4 自定义策略
使用GsonBuilder的方法根据自定义策略排除字段:
- 使用
setExclusionStrategies()方法设置全局排除策略,可以传入多个排除策略。
- 使用
addSerializationExclusionStrategy()方法添加序列化排除策略,同时使用会覆盖全局排除策略。
- 使用
addDeserializationExclusionStrategy()方法添加反序列化排除策略,同时使用会覆盖全局排除策略。
修改GsonBuilder配置,使用策略:
java1 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; } 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实现序列化和反序列化。
示例:
java1 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 = 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; } }; 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自定义序列化:
java1 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<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; } }; Gson gson = new GsonBuilder() .registerTypeAdapter(Student.class, serializer) .create(); String json = gson.toJson(student); System.out.println("序列化结果: " + json); }
|
7.2.2 反序列化
使用JsonDeserializer自定义反序列化:
java1 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<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; } }; 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.java1 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.java1 2 3 4
| @JsonAdapter(StudentTypeAdapter.class) public class Student { }
|
如果没有其他配置可以省略GsonBulider的配置,直接使用Gson实例:
java1 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 = 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()); }
|
条