1. 将 JSON 映射为简单 Java 对象

我们先从最基础的开始:将一个简单的 JSON 字符串转换为一个 Java 对象,比如 Foo 类:

public class Foo {
    public int intValue;
    public String stringValue;

    // + 标准的 equals 和 hashCode 实现
}

对应的反序列化操作如下:

@Test
public void whenDeserializingToSimpleObject_thenCorrect() {
    String json = "{\"intValue\":1,\"stringValue\":\"one\"}";

    Foo targetObject = new Gson().fromJson(json, Foo.class);

    assertEquals(targetObject.intValue, 1);
    assertEquals(targetObject.stringValue, "one");
}

小结:Gson 默认使用字段名匹配来映射 JSON 和 Java 对象,非常直观。


2. 反序列化泛型对象

如果我们的类是泛型的,比如:

public class GenericFoo<T> {
    public T theValue;
}

这时候就不能直接用 .class 来指定类型了,需要借助 TypeToken

@Test
public void whenDeserializingToGenericObject_thenCorrect() {
    Type typeToken = new TypeToken<GenericFoo<Integer>>() { }.getType();
    String json = "{\"theValue\":1}";

    GenericFoo<Integer> targetObject = new Gson().fromJson(json, typeToken);

    assertEquals(targetObject.theValue, new Integer(1));
}

⚠️ 踩坑提醒:泛型擦除导致 Gson 无法自动推断类型,必须显式提供 Type


3. 处理包含未知字段的 JSON 数据

如果 JSON 中有我们 Java 类中没有定义的字段,Gson 会怎么处理?

@Test
public void givenJsonHasExtraValues_whenDeserializing_thenCorrect() {
    String json = 
      "{\"intValue\":1,\"stringValue\":\"one\",\"extraString\":\"two\",\"extraFloat\":2.2}";
    Foo targetObject = new Gson().fromJson(json, Foo.class);

    assertEquals(targetObject.intValue, 1);
    assertEquals(targetObject.stringValue, "one");
}

结论:Gson 会自动忽略未知字段,不会报错。这在处理第三方 API 返回的数据时非常有用。


4. 字段名不一致的 JSON 映射

有时候 JSON 的字段名和 Java 类中的字段名不一致,比如:

@Test
public void givenJsonHasNonMatchingFields_whenDeserializingWithCustomDeserializer_thenCorrect() {
    String json = "{\"valueInt\":7,\"valueString\":\"seven\"}";

    GsonBuilder gsonBldr = new GsonBuilder();
    gsonBldr.registerTypeAdapter(Foo.class, new FooDeserializerFromJsonWithDifferentFields());
    Foo targetObject = gsonBldr.create().fromJson(json, Foo.class);

    assertEquals(targetObject.intValue, 7);
    assertEquals(targetObject.stringValue, "seven");
}

这时我们需要自定义一个反序列化器:

public class FooDeserializerFromJsonWithDifferentFields implements JsonDeserializer<Foo> {

    @Override
    public Foo deserialize
      (JsonElement jElement, Type typeOfT, JsonDeserializationContext context) 
      throws JsonParseException {
        JsonObject jObject = jElement.getAsJsonObject();
        int intValue = jObject.get("valueInt").getAsInt();
        String stringValue = jObject.get("valueString").getAsString();
        return new Foo(intValue, stringValue);
    }
}

⚠️ 提示:这种方式适合处理字段名不一致但结构清晰的场景。


5. 将 JSON 数组转换为 Java 数组

JSON 数组也可以轻松转换为 Java 数组:

@Test
public void givenJsonArrayOfFoos_whenDeserializingToArray_thenCorrect() {
    String json = "[{\"intValue\":1,\"stringValue\":\"one\"}," +
      "{\"intValue\":2,\"stringValue\":\"two\"}]";
    Foo[] targetArray = new GsonBuilder().create().fromJson(json, Foo[].class);

    assertThat(Lists.newArrayList(targetArray), hasItem(new Foo(1, "one")));
    assertThat(Lists.newArrayList(targetArray), hasItem(new Foo(2, "two")));
    assertThat(Lists.newArrayList(targetArray), not(hasItem(new Foo(1, "two"))));
}

技巧:使用 Foo[].class 指定目标类型即可。


6. 将 JSON 数组转换为 Java 集合

如果你更喜欢用集合而不是数组,Gson 也支持:

@Test
public void givenJsonArrayOfFoos_whenDeserializingCollection_thenCorrect() {
    String json = 
      "[{\"intValue\":1,\"stringValue\":\"one\"},{\"intValue\":2,\"stringValue\":\"two\"}]";
    Type targetClassType = new TypeToken<ArrayList<Foo>>() { }.getType();

    Collection<Foo> targetCollection = new Gson().fromJson(json, targetClassType);
    assertThat(targetCollection, instanceOf(ArrayList.class));
}

⚠️ 注意:这里必须通过 TypeToken 获取泛型类型。


7. 嵌套对象的反序列化

如果对象中包含嵌套对象,比如:

public class FooWithInner {
    public int intValue;
    public String stringValue;
    public InnerFoo innerFoo;

    public class InnerFoo {
        public String name;
    }
}

反序列化代码如下:

@Test
public void whenDeserializingToNestedObjects_thenCorrect() {
    String json = "{\"intValue\":1,\"stringValue\":\"one\",\"innerFoo\":{\"name\":\"inner\"}}";

    FooWithInner targetObject = new Gson().fromJson(json, FooWithInner.class);

    assertEquals(targetObject.intValue, 1);
    assertEquals(targetObject.stringValue, "one");
    assertEquals(targetObject.innerFoo.name, "inner");
}

结论:Gson 支持自动递归解析嵌套对象,无需额外配置。


8. 使用自定义构造器进行反序列化

默认情况下,Gson 会使用无参构造器创建对象。但如果你希望使用带参构造器,可以使用 InstanceCreator

public class FooInstanceCreator implements InstanceCreator<Foo> {

    @Override
    public Foo createInstance(Type type) {
        return new Foo("sample");
    }
}

注册并使用:

@Test
public void whenDeserializingUsingInstanceCreator_thenCorrect() {
    String json = "{\"intValue\":1}";

    GsonBuilder gsonBldr = new GsonBuilder();
    gsonBldr.registerTypeAdapter(Foo.class, new FooInstanceCreator());
    Foo targetObject = gsonBldr.create().fromJson(json, Foo.class);

    assertEquals(targetObject.intValue, 1);
    assertEquals(targetObject.stringValue, "sample");
}

构造器如下:

public Foo(String stringValue) {
    this.stringValue = stringValue;
}

⚠️ 适用场景:当你需要初始化某些字段为默认值,或依赖注入时很有用。


9. 总结

本文通过多个常见场景,展示了如何使用 Gson 高效地将 JSON 映射为 Java 对象。包括:

  • 简单对象
  • 泛型对象
  • 字段不一致处理
  • 数组与集合转换
  • 嵌套对象
  • 自定义构造器

📌 示例代码仓库GitHub 项目地址(基于 Eclipse,可直接导入运行)



原始标题:Gson Deserialization Cookbook