原文: https://howtodoinjava.com/gson/custom-serialization-deserialization/

Gson 在默认序列化和反序列化方面提供了非常出色的功能。 不过,我们可能会遇到默认和内置自定义选项无法解决我们问题的情况。

在这种情况下,我们可以使用两个接口JsonSerializerJsonDeserializer使用自定义序列化和反序列化。

1.自定义序列化

1.1 JsonSerializer接口

JsonSerializer接口看起来像这样:

  1. public interface JsonSerializer<T>
  2. {
  3. public JsonElement serialize(T value, Type type,
  4. JsonSerializationContext jsonSerializationContext) {
  5. }
  6. }

为 Json 创建自定义序列化器之后,我们还需要通过GsonBuilder.registerTypeAdapter(Type, Object)注册该序列化器。

Gson 在遇到指定类型的字段时,会在序列化过程中调用其回调方法serialize()

1.2 Gson JsonSerializer示例

假设我们进入一种情况,我们必须将 Java 对象序列化为 json,以便将所有布尔值都写入1 or 0,而不是打印true or false

让我们为该要求编写自定义序列化程序。

  1. import com.google.gson.JsonElement;
  2. import com.google.gson.JsonPrimitive;
  3. import com.google.gson.JsonSerializationContext;
  4. import com.google.gson.JsonSerializer;
  5. public class BooleanSerializer implements JsonSerializer<Boolean> {
  6. public JsonElement serialize(Boolean aBoolean, Type type,
  7. JsonSerializationContext jsonSerializationContext)
  8. {
  9. if(aBoolean){
  10. return new JsonPrimitive(1);
  11. }
  12. return new JsonPrimitive(0);
  13. }
  14. }

让我们编写一个程序,使用registerTypeAdapter()注册JsonSerializer实例,然后使用它将 Java 对象序列化为 json。

  1. import com.google.gson.Gson;
  2. import com.google.gson.GsonBuilder;
  3. public class Main
  4. {
  5. public static void main(String[] args) throws Exception
  6. {
  7. Employee emp = new Employee(1, "Lokesh", "Gupta", "howtodoinjava@gmail.com", true);
  8. Gson gson = new GsonBuilder()
  9. .registerTypeAdapter(Boolean.class, new BooleanSerializer())
  10. .setPrettyPrinting()
  11. .create();
  12. String json = gson.toJson(emp);
  13. System.out.println(json);
  14. }
  15. }

注意程序输出,键“active”的值被序列化为 1。

  1. {
  2. "id": 1,
  3. "firstName": "Lokesh",
  4. "lastName": "Gupta",
  5. "email": "howtodoinjava@gmail.com",
  6. "active": 1
  7. }

2.自定义反序列化

2.1 JsonDeserializer接口

自定义反序列化器必须实现JsonDeserializer接口。 JsonDeserializer接口如下所示:

  1. public interface JsonDeserializer<T>
  2. {
  3. public Boolean deserialize(JsonElement jsonElement,
  4. Type type, JsonDeserializationContext jsonDeserializationContext)
  5. throws JsonParseException;
  6. }

为 Json 创建自定义反序列化器之后,我们还需要通过GsonBuilder.registerTypeAdapter(Type, Object)注册此反序列化器。

Gson 在遇到指定类型的字段时,会在序列化过程中调用其回调方法deserialize()

2.2 Gson JsonDeserializer示例

假设某些服务将日期字段分别分为天,月和年等部分分别返回给我们。 在 JSON 字符串中,它们可能有意义,但在 Java 中,它们只有作为单个java.time.LocalDate对象的一部分时才有意义。

  1. {
  2. "id": 1,
  3. "firstName": "Lokesh",
  4. "lastName": "Gupta",
  5. "email": "howtodoinjava@gmail.com",
  6. "day": 11,
  7. "month": 8,
  8. "year": 2019
  9. }

我们要自定义反序列化并将最后三个字段组合为LocalDate对象。

我们的Employee看起来像这样。 包括必要的获取器和设置器以及构造器。

  1. public class Employee
  2. {
  3. private Integer id;
  4. private String firstName;
  5. private String lastName;
  6. private String email;
  7. private LocalDate dob;
  8. }

自定义反序列化器类如下所示:

  1. import com.google.gson.JsonDeserializationContext;
  2. import com.google.gson.JsonDeserializer;
  3. import com.google.gson.JsonElement;
  4. import com.google.gson.JsonObject;
  5. import com.google.gson.JsonParseException;
  6. public class EmployeeDeserializer implements JsonDeserializer<Employee>
  7. {
  8. @Override
  9. public Employee deserialize(JsonElement json, Type typeOfT,
  10. JsonDeserializationContext context) throws JsonParseException
  11. {
  12. JsonObject jsonObject = json.getAsJsonObject();
  13. LocalDate localDate = LocalDate.of(
  14. jsonObject.get("year").getAsInt(),
  15. jsonObject.get("month").getAsInt(),
  16. jsonObject.get("day").getAsInt()
  17. );
  18. return new Employee(
  19. jsonObject.get("id").getAsInt(),
  20. jsonObject.get("firstName").getAsString(),
  21. jsonObject.get("lastName").getAsString(),
  22. jsonObject.get("email").getAsString(),
  23. localDate);
  24. }
  25. }

让我们注册反序列化器,然后将给定的 JSON 解析为 java 对象。

  1. public class Main
  2. {
  3. public static void main(String[] args) throws Exception
  4. {
  5. String json = "{'id': 1001,"
  6. + "'firstName': 'Lokesh',"
  7. + "'lastName': 'Gupta',"
  8. + "'email': 'howtodoinjava@gmail.com', "
  9. + "'day': 11, "
  10. + "'month': 8, "
  11. + "'year': 2019}";
  12. Gson gson = new GsonBuilder()
  13. .registerTypeAdapter(Employee.class, new EmployeeDeserializer())
  14. .create();
  15. Employee employee = gson.fromJson(json, Employee.class);
  16. System.out.println(employee);
  17. }
  18. }

注意程序输出如何将 3 个单独的字段组合成单个LocalDate对象。

  1. Employee [id=1001,
  2. firstName=Lokesh,
  3. lastName=Gupta,
  4. email=howtodoinjava@gmail.com,
  5. dob=2019-08-11]

根据提供的 json 输入的保证,我们可能想用has()来检查JsonObject中是否存在模型属性。 否则,如果我们正在访问属性,然后尝试获取该属性的值,则可能会遇到NullPointerException

向我提供有关 Java 中使用 Gson 的自定义序列化和反序列化的问题。

学习愉快!