2. 序列化对象数组

我们先从最基础的场景开始:将一个对象数组序列化为 JSON 字符串。

@Test
public void givenArrayOfObjects_whenSerializing_thenCorrect() {
    SourceClass[] sourceArray = {new SourceClass(1, "one"), new SourceClass(2, "two")};
    String jsonString = new Gson().toJson(sourceArray);

    String expectedResult = 
      "[{"intValue":1,"stringValue":"one"},{"intValue":2,"stringValue":"two"}]";
    assertEquals(expectedResult, jsonString);
}

✅ 简单粗暴,Gson 直接搞定,无需额外配置。

3. 序列化集合类型

和数组类似,Gson 也能直接处理 Java 集合:

@Test
public void givenCollection_whenSerializing_thenCorrect() {
    Collection<SourceClass> sourceCollection = 
      Lists.newArrayList(new SourceClass(1, "one"), new SourceClass(2, "two"));
    String jsonCollection = new Gson().toJson(sourceCollection);

    String expectedResult = 
      "[{"intValue":1,"stringValue":"one"},{"intValue":2,"stringValue":"two"}]";
    assertEquals(expectedResult, jsonCollection);
}

⚠️ 注意:这里用的是 Lists.newArrayList(),属于 Guava 提供的便捷工具。

4. 自定义字段名序列化

有时我们希望输出的 JSON 字段名和 Java 对象属性名不一致,比如把 intValue 输出为 otherIntValue

这时候就需要自定义序列化器了:

@Test
public void givenUsingCustomSerializer_whenChangingNameOfFieldOnSerializing_thenCorrect() {
    SourceClass sourceObject = new SourceClass(7, "seven");
    GsonBuilder gsonBuildr = new GsonBuilder();
    gsonBuildr.registerTypeAdapter(SourceClass.class, new DifferentNameSerializer());
    String jsonString = gsonBuildr.create().toJson(sourceObject);

    String expectedResult = "{"otherIntValue":7,"otherStringValue":"seven"}";
    assertEquals(expectedResult, jsonString);
}

对应的自定义序列化器如下:

public class DifferentNameSerializer implements JsonSerializer<SourceClass> {
    @Override
    public JsonElement serialize
      (SourceClass src, Type typeOfSrc, JsonSerializationContext context) {
        String otherIntValueName = "otherIntValue";
        String otherStringValueName = "otherStringValue";

        JsonObject jObject = new JsonObject();
        jObject.addProperty(otherIntValueName, src.getIntValue());
        jObject.addProperty(otherStringValueName, src.getStringValue());

        return jObject;
    }
}

💡 踩坑提示:记得注册 TypeAdapter,否则自定义逻辑不会生效。

5. 忽略特定字段序列化

有些字段不想暴露给前端?可以使用自定义序列化器来忽略它们:

@Test
public void givenIgnoringAField_whenSerializingWithCustomSerializer_thenFieldIgnored() {
    SourceClass sourceObject = new SourceClass(7, "seven");
    GsonBuilder gsonBuildr = new GsonBuilder();
    gsonBuildr.registerTypeAdapter(SourceClass.class, new IgnoringFieldsSerializer());
    String jsonString = gsonBuildr.create().toJson(sourceObject);

    String expectedResult = "{"intValue":7}";
    assertEquals(expectedResult, jsonString);
}

自定义序列化器实现:

public class IgnoringFieldsSerializer implements JsonSerializer<SourceClass> {
    @Override
    public JsonElement serialize
      (SourceClass src, Type typeOfSrc, JsonSerializationContext context) {
        String intValue = "intValue";
        JsonObject jObject = new JsonObject();
        jObject.addProperty(intValue, src.getIntValue());

        return jObject;
    }
}

⚠️ 如果你能修改源码,推荐使用 @Exposetransient 关键字来控制字段是否序列化,会更简洁。

6. 条件性序列化字段

这是比较高级的用法:只有满足特定条件的字段才会被序列化。例如只序列化正整数的 intValue

@Test
public void givenUsingCustomDeserializer_whenFieldNotMatchesCriteria_thenIgnored() {
    SourceClass sourceObject = new SourceClass(-1, "minus 1");
    GsonBuilder gsonBuildr = new GsonBuilder();
    gsonBuildr.registerTypeAdapter(SourceClass.class, 
      new IgnoringFieldsNotMatchingCriteriaSerializer());
    Gson gson = gsonBuildr.create();
    Type sourceObjectType = new TypeToken<SourceClass>() {}.getType();
    String jsonString = gson.toJson(sourceObject, sourceObjectType);
    
    String expectedResult = "{"stringValue":"minus 1"}";
    assertEquals(expectedResult, jsonString);
}

对应的自定义序列化器如下:

public class IgnoringFieldsNotMatchingCriteriaSerializer 
  implements JsonSerializer<SourceClass> {
    @Override
    public JsonElement serialize
      (SourceClass src, Type typeOfSrc, JsonSerializationContext context) {
        JsonObject jObject = new JsonObject();

        // Criteria: intValue >= 0
        if (src.getIntValue() >= 0) {
            String intValue = "intValue";
            jObject.addProperty(intValue, src.getIntValue());
        }

        String stringValue = "stringValue";
        jObject.addProperty(stringValue, src.getStringValue());

        return jObject;
    }
}

🎯 这种方式非常灵活,适合处理一些敏感字段或业务规则控制的输出逻辑。


📌 总结一下,以上就是 Gson 中常见的几种序列化场景。虽然 Gson 默认已经很好用了,但在一些特殊需求下(比如字段重命名、条件输出),自定义 JsonSerializer 还是非常实用的。掌握这些技巧,日常开发中基本可以应对大部分 JSON 序列化的问题了。


原始标题:Gson Serialization Cookbook

« 上一篇: Baeldung周报36
» 下一篇: Java周报 37