Gson使用手册

1 篇文章 0 订阅

官网首页:https://google.github.io/gson/

官网文档指南:https://google.github.io/gson/UserGuide.html#overview

引入依赖

<dependencies>
    <!--  Gson: Java to JSON conversion -->
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.10.1</version>
      <scope>compile</scope>
    </dependency>
</dependencies>

使用

基本示例

    @Test
    public void test01(){
        // 序列化
        Gson gson = new Gson();
        System.out.println(gson.toJson(1));;   // ==> 1
        System.out.println(gson.toJson("abcd"));       // ==> "abcd"
        System.out.println(gson.toJson(new Long(10))); // ==> 10
        int[] values = { 1 };
        System.out.println(gson.toJson(values));;      // ==> [1]

        // 反序列化
        int i = gson.fromJson("1", int.class);
        System.out.println("i = " + i);
        Integer intObj = gson.fromJson("1", Integer.class);
        System.out.println("intObj = " + intObj);
        Long longObj = gson.fromJson("1", Long.class);
        System.out.println("longObj = " + longObj);
        Boolean boolObj = gson.fromJson("false", Boolean.class);
        System.out.println("boolObj = " + boolObj);
        String str = gson.fromJson("\"abc\"", String.class);
        System.out.println("str = " + str);
        String[] strArray = gson.fromJson("[\"abc\"]", String[].class);
        System.out.println("strArray = " + Arrays.toString(strArray));
    }

对象示例

1.  默认情况下,当前类(以及所有超类)中的所有字段都会被序列化。

2. 如果字段标记为暂时性,则(默认情况下)将忽略该字段,并且不包含在 JSON 序列化或反序列化中。

1. 创建父类对象

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public class ParentBag {
    private String id;

    private Date date;
}

2. 创建子类对象

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public class BagOfPrimitives extends ParentBag{
    private int value1;
    private String value2;
    // 被 transient 标记的字段不被序列化
    private transient int value3;

    private Boolean value4;
}

3. 使用

    @Test
    public void test02(){
        // 序列化
        BagOfPrimitives obj = new BagOfPrimitives(1, "abc", 3, null);
        obj.id("1001");
        obj.date(new Date());

        Gson gson = new Gson();
        String json = gson.toJson(obj);
        System.out.println("json = " + json);

        // 反序列化
        BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);
        System.out.println("obj2 = " + obj2);
    }

嵌套类(包括内部类)-- 静态

Gson 可以很容易地序列化和反序列化静态嵌套类。

但是,Gson 不能自动反序列化纯内部类,因为它们的 no-args 构造函数还需要对包含的 Object 的引用,而该引用在反序列化时不可用。

1. 创建对象

package org.example.paymentdemo.gson.entity;

import lombok.*;
import lombok.experimental.Accessors;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public class OutsideObject {

    private String outsideName;
    private InnerObject innerObject;
    private InnerStaticObject innerStaticObject;

    /**
     * 静态内部类
     */
    @Setter
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString(callSuper = true)
    @Accessors(chain = true, fluent = true)
    public static class InnerStaticObject{
        private String innerStaticName;

    }

    /**
     * 非静态内部类:外部无法创建对象
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString(callSuper = true)
    @Accessors(chain = true, fluent = true)
    public class InnerObject{
        private String innerName;
    }
}

2. 使用

    @Test
    public void test03(){

        OutsideObject outsideObject = new OutsideObject();
        outsideObject.outsideName("111");
        // 非静态内部类
        OutsideObject.InnerObject inneredObject = outsideObject.new InnerObject();
        inneredObject.innerName("222");
        outsideObject.innerObject(inneredObject);
        // 静态内部类
        OutsideObject.InnerStaticObject innerStaticObject = new OutsideObject.InnerStaticObject("111");
        outsideObject.innerStaticObject(innerStaticObject);


        // 序列化
        Gson gson = new Gson();
        String json = gson.toJson(outsideObject);
        System.out.println("json = " + json);
        // 反序列化
        OutsideObject outsideObject1 = gson.fromJson(json, OutsideObject.class);
        System.out.println("outsideObject1 = " + outsideObject1);

    }

数组示例

基本类型

多维数组

复杂元素类型

    @Test
    public void test04(){
        Gson gson = new Gson();
        int[] ints = {1, 2, 3, 4, 5};
        String[] strings = {"abc", "def", "ghi"};

        // 序列化
        String json = gson.toJson(ints);// ==> [1,2,3,4,5]
        System.out.println("json = " + json);
        json = gson.toJson(strings);  // ==> ["abc", "def", "ghi"]
        System.out.println("json = " + json);

        // 反序列化
        int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class);
        // ==> ints2 will be same as ints
        System.out.println("ints2 = " + Arrays.toString(ints2));

        // 多维数组
        int[][] intss = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
        json = gson.toJson(intss);
        System.out.println("json = " + json);   // ==> [[1,1],[2,2],[3,3],[4,4],[5,5]]

        int[][] ints1 = gson.fromJson(json, int[][].class);
        System.out.println("ints1 = " + ints1);

        // 任意复杂的元素类型
        ParentBag[] parentBags = {new ParentBag().id("111"), new ParentBag().id("222"), new ParentBag().id("333")};
        json = gson.toJson(parentBags);
        System.out.println("json = " + json);
        ParentBag[] parentBags1 = gson.fromJson(json, ParentBag[].class);
        System.out.println("parentBags1 = " + parentBags1);
    }

集合示例

1. Gson 可以序列化任意对象的集合,但不能从中反序列化,因为无法指定生成对象的类型。

        Gson会自己判断类型,但是可能不是准确的,比如:Integer 反序列为 Double,对象 反序列为 LinkedTreeMap。

2. Gson 使用 TypeToken 类来表示泛型类型 T。反序列化时强制创建此类的子类,即使在运行时也可以检索类型信息。【推荐使用】

    /**
     * 集合示例
     */
    @Test
    public void tset05(){
        Gson gson = new Gson();
        Collection<Integer> ints = Arrays.asList(1,2,3,4,5);

        // 序列化
        String json = gson.toJson(ints);    // ==> [1,2,3,4,5]
        System.out.println("json = " + json);

        // 反序列化
        TypeToken<Collection<Integer>> collectionType = new TypeToken<Collection<Integer>>(){};
        //对于较旧的 Gson 版本,有必要使用“collectionType.getType()”作为下面的参数,但是这不是类型安全的,必须注意为局部变量指定正确的类型
        Collection<Integer> ints2 = gson.fromJson(json, collectionType);    // ==> [1, 2, 3, 4, 5]
        System.out.println("ints2 = " + ints2);


        Collection collection = gson.fromJson(json, Collection.class);
        System.out.println("collection = " + collection);   // ==> [1.0, 2.0, 3.0, 4.0, 5.0]


        ArrayList<ParentBag> list = new ArrayList<>();
        list.add(new ParentBag().id("111"));
        list.add(new ParentBag().id("222"));
        list.add(new ParentBag().id("333"));
        json = gson.toJson(list);    // ==>
        System.out.println("json = " + json);

        Collection collection1 = gson.fromJson(json, Collection.class);
        System.out.println("collection1 = " + collection1);   // ==> [1.0, 2.0, 3.0, 4.0, 5.0]
    }

Map 示例

由于Gson默认使用 toString() 序列化Map键,这可能导致格式错误的编码键,或者可能导致键的序列化和非序列化之间的不匹配。

        例如当 toString() 没有正确实现时。

解决方法:使用 GsonBuilder#enableComplexMapKeySerialization() 来确保为Map键类型注册的 TypeAdapter 用于重复化和序列化。

        Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create();

当key为枚举时,如果Gson无法找到分别具有匹配的 name() 值和 @SerializedName 注释的枚举常量,默认为枚举对象的 toString() 值。

key为基本数据类型

    @Test
    public void test06(){
        Gson gson = new Gson();
        Map<String, String> stringMap = new LinkedHashMap<>();
        stringMap.put("key", "value");
        stringMap.put(null, "null-entry");

        // 序列化
        String json = gson.toJson(stringMap); // ==> {"key":"value","null":"null-entry"}
        System.out.println("json = " + json);
        // 反序列化
        TypeToken<Map<String, String>> mapType = new TypeToken<Map<String, String>>(){};
        Map<String, String> stringMap1 = gson.fromJson(json, mapType);
        System.out.println("stringMap1 = " + stringMap1);


        Map<Integer, Integer> intMap = new LinkedHashMap<>();
        intMap.put(2, 4);
        intMap.put(3, 6);

        // 序列化
        json = gson.toJson(intMap); // ==> {"2":4,"3":6}
        System.out.println("json = " + json);
        // 反序列化
        TypeToken<Map<Integer, Integer>> typeToken = new TypeToken<Map<Integer, Integer>>() {};
        Map<Integer, Integer> integerIntegerMap = gson.fromJson(json, typeToken);
        System.out.println("integerIntegerMap = " + integerIntegerMap);
    }

key为复杂类型

    @Test
    public void test07(){
        Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create();

        // 复杂对象
        Map<ParentBag, ParentBag> bagMap = new HashMap<>();
        bagMap.put(new ParentBag().id("11"), new ParentBag().id("AA"));
        bagMap.put(new ParentBag().id("22"), new ParentBag().id("BB"));
        String json = gson.toJson(bagMap);
        System.out.println("json = " + json);
        
        // 反序列化
        TypeToken<Map<ParentBag, ParentBag>> mapTypeToken = new TypeToken< Map<ParentBag, ParentBag>>() {};
        Map<ParentBag, ParentBag> bagMap1 = gson.fromJson(json, mapTypeToken);
        System.out.println("bagMap1 = " + bagMap1);
    }

 

key为枚举

    @Test
    public void test08(){
        Gson gson = new Gson();

        // 复杂对象
        Map<Season, ParentBag> bagMap = new HashMap<>();
        bagMap.put(Season.SPRING, new ParentBag().id("AA"));
        bagMap.put(Season.SUMMER, new ParentBag().id("BB"));
        String json = gson.toJson(bagMap);
        System.out.println("json = " + json);

        // 反序列化
        TypeToken<Map<Season, ParentBag>> mapTypeToken = new TypeToken< Map<Season, ParentBag>>() {};
        Map<Season, ParentBag> bagMap1 = gson.fromJson(json, mapTypeToken);
        System.out.println("bagMap1 = " + bagMap1);
    }

序列化和非序列化泛型类型

使用 com.google.gson.reflect.TypeToken<T>

错误写法

泛型对象反序列化为LinkedTreeMap对象,通过强转也会报错:

正确写法

    @Test
    public void test10(){
        Gson gson = new Gson();
        Foo<Bar> foo = new Foo<>();
        foo.id("111");
        foo.value(new Bar("222"));
        String json = gson.toJson(foo);
        System.out.println("json = " + json);

        TypeToken<Foo<Bar>> typeToken = new TypeToken<Foo<Bar>>() {};


        Foo<Bar> foo1 = gson.fromJson(json, typeToken);// Fails to deserialize foo.value as Bar
        System.out.println("foo1 = " + foo1);

        Bar value = foo1.value();
        System.out.println("value = " + value);
    }

自定义序列化和反序列化

有时候默认的表示并不是你想要的。在处理库类(DateTime等)时通常会出现这种情况。

步骤:

1. 自定义JSON序列化器,实现com.google.gson.JsonSerializer接口的serialize方法。

2. 自定义 JSON反序列化器,实现com.google.gson.JsonDeserializer接口的deserialize方法。

3. GsonBuilder#registerTypeAdapter方法注册。

Date示例

DateSerializer
import cn.hutool.core.date.DateUtil;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import java.lang.reflect.Type;
import java.util.Date;

public class DateSerializer implements JsonSerializer<Date> {
  @Override
  public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
    return new JsonPrimitive(DateUtil.format(src, "yyyy-MM-dd HH:mm:ss"));
  }
}
DateDeserializer
import cn.hutool.core.date.DateUtil;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;

import java.lang.reflect.Type;
import java.util.Date;

public class DateDeserializer implements JsonDeserializer<Date> {

    @Override
    public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        return DateUtil.parse(json.getAsJsonPrimitive().getAsString()).toJdkDate();
    }
}
注册使用
    @Test
    public void tset11(){
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.registerTypeAdapter(Date.class, new DateSerializer());
        gsonBuilder.registerTypeAdapter(Date.class, new DateDeserializer());
        Gson gson = gsonBuilder.create();

        // 序列化
        ParentBag parentBag = new ParentBag("111", null);
        String json = gson.toJson(parentBag);
        System.out.println("json = " + json);

        // 反序列化
        ParentBag parentBag1 = gson.fromJson(json, ParentBag.class);
        System.out.println("parentBag1 = " + parentBag1);
    }

JSON输出格式的紧凑打印与漂亮打印

Gson提供的默认JSON输出是一种紧凑的JSON格式。

如果您想使用Pretty Print功能,则必须使用 GsonBuilder 配置您的 Gson 实例。

提供了一个默认的 JsonPrintFormatter ,它具有80个字符的默认行长度,2个字符的缩进和4个字符的右边距。

    @Test
    public void test12(){
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        Bar bar = new Bar("111");
        String json = gson.toJson(bar);
        System.out.println("json = " + json);

        Bar bar1 = gson.fromJson(json, Bar.class);
        System.out.println("bar1 = " + bar1);
    }

Null值处理

Gson中实现的默认行为是忽略 null 对象字段。

    @Test
    public void test13(){
        Gson gson = new GsonBuilder().serializeNulls().create();
        ParentBag parentBag = new ParentBag("111", null);
        String json = gson.toJson(parentBag);
        System.out.println("json = " + json);

        ParentBag parentBag1 = gson.fromJson(json, ParentBag.class);
        System.out.println("parentBag1 = " + parentBag1);
    }

版本控制支持

在Gson中,可以使用@Since注释维护同一对象的多个版本。可以在类,字段以及将来的方法中使用此注释。

当我们为Gson实例配置版本号“ 1.1”时,所有标记有版本大于1.1的类字段都将被忽略。例如,如果我们将Gson配置为版本号“ 1.2”,则所有版本号更高的字段(例如1.3、1.4…)都将被忽略。

使用GsonBuilder.setVersion()方法创建Gson实例。

1. 创建实体类

import com.google.gson.annotations.Since;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public class VersionedClass {
    @Since(1.1)
    private String newerField;
    @Since(1.0)
    private String newField;
    private String field;
}

2. 使用

    @Test
    public void test14(){
        VersionedClass versionedObject = new VersionedClass("newField", "newField", "field");
        Gson gson = new GsonBuilder().setVersion(1.0).create();
        String jsonOutput = gson.toJson(versionedObject);
        System.out.println(jsonOutput);

        gson = new Gson();
        jsonOutput = gson.toJson(versionedObject);
        System.out.println(jsonOutput);
    }

排除字段

 Java修饰符排除

默认情况下,字段标记为 transient ,或者 被标记为 static ,那么默认情况下它将被排除。

1. 新建实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public class ExcludeFieldClass {

    private String value1;
    private static String value2 = "value2";
    private transient String value3;
}

2. 使用

    @Test
    public void test15() {
        Gson gson = new Gson();
        ExcludeFieldClass excludeFieldClass = new ExcludeFieldClass("value1", "value3");
        String json = gson.toJson(excludeFieldClass);
        System.out.println("json = " + json);
    }

GsonBuilder#excludeFieldsWithModifiers方法

    @Test
    public void test16() {
        // 都不排除
        Gson gson = new GsonBuilder().excludeFieldsWithModifiers().create();
        // 排除静态和瞬态
//        Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT).create();
        ExcludeFieldClass excludeFieldClass = new ExcludeFieldClass("value1", "value3");
        String json = gson.toJson(excludeFieldClass);
        System.out.println("json = " + json);
    }

 Gson 的 @Expose 注解

注解参数:

        serialize –如果为true,则在序列化时会在JSON中写出带有此注解的字段。
        deserialize –如果为true,则从JSON反序列化带有此注解的字段。

实体类每个字段都得加注解,不加注解默认不参与序列化与反序列化。

必须使用 new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create() 来创建Gson实例。

1. 实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public class ExcludeFieldClass {

    private String value1;
    private static String value2 = "value2";
    private transient String value3;


    @Expose(serialize = false)
    private String value4;
    @Expose(deserialize = false)
    private String value5;
    @Expose(serialize = false, deserialize = false)
    private String value6;
}

2. 使用:

    @Test
    public void test17() {
        // 排除没有公开注释的字段
        Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
        // 排除静态和瞬态
        ExcludeFieldClass excludeFieldClass = new ExcludeFieldClass("value1", "value3", "value4", "value5", "value6");
        String json = gson.toJson(excludeFieldClass);
        System.out.println("json = " + json);
    }

自定义的排除策略

步骤:

1. 实现 com.google.gson.ExclusionStrategy 接口

2. GsonBuilder#setExclusionStrategies注册

1. 定义排除注解:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Foo {
  // Field tag only annotation
}

2. 自定义排除策略,实现 ExclusionStrategy 接口

import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;

public class MyExclusionStrategy implements ExclusionStrategy {

    private final Class<?> typeToSkip;

    public MyExclusionStrategy(Class<?> typeToSkip) {
        this.typeToSkip = typeToSkip;
    }

    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getAnnotation(Foo.class) != null;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return (clazz == typeToSkip);
    }
}

3. 注册并使用

    @Test
    public void test18() {
        Gson gson = new GsonBuilder()
                .setExclusionStrategies(new MyExclusionStrategy(String.class))
                .serializeNulls()
                .create();
        SampleObjectForTest src = new SampleObjectForTest(5, "someDefaultValue", 1234L);
        String json = gson.toJson(src);
        System.out.println(json);
    }

更改Java对象和JSON的字段名映射

@SerializedName注解

注解参数:

       value:序列化或反序列化时字段的所需名称

       alternate:反序列化时字段的备用名称

1. 新建实体类

import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true, fluent = true)
public class SomeObject {
    @SerializedName(value = "custom_naming", alternate = "custom_naming_two")
    private String someField;
    private String someOtherField;
}

2. 使用

    @Test
    public void test19(){
        SomeObject someObject = new SomeObject("first", "second");
        Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
        String jsonRepresentation = gson.toJson(someObject);
        System.out.println(jsonRepresentation);

        String json = "{\"custom_naming_two\":\"first_bak\",\"SomeOtherField\":\"second\"}";
        SomeObject someObject1 = gson.fromJson(json, SomeObject.class);
        System.out.println("someObject1 = " + someObject1);
    }

  • 36
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值