Java基础-序列化/反序列化-gson基础知识

以下内容来之官网翻译,地址

1.Gson依赖

1.1.Gradle/Android

dependencies {
    implementation 'com.google.code.gson:gson:2.9.0'
}

1.2.maven

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

1.2.Gson简单实用

1.2.1.基础类型

// Serialization
Gson gson = new Gson();
gson.toJson(1);            // ==> 1
gson.toJson("abcd");       // ==> "abcd"
gson.toJson(new Long(10)); // ==> 10
int[] values = { 1 };
gson.toJson(values);       // ==> [1]

// Deserialization
int one = gson.fromJson("1", int.class);
Integer one = gson.fromJson("1", Integer.class);
Long one = gson.fromJson("1", Long.class);
Boolean false = gson.fromJson("false", Boolean.class);
String str = gson.fromJson("\"abc\"", String.class);
String[] anotherStr = gson.fromJson("[\"abc\"]", String[].class);

1.2.2.对象

class BagOfPrimitives {
  private int value1 = 1;
  private String value2 = "abc";
  private transient int value3 = 3;
  BagOfPrimitives() {
    // no-args constructor
  }
}

// Serialization
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj);  

// ==> json is {"value1":1,"value2":"abc"}

// Deserialization
BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);
// ==> obj2 is just like obj

Notes 如果对象内存在循环引用,序列化时将导致死循环。

例如:


@Data
public class RecursionObject {

    private String name;

    private RecursionReferObject refer;
}


@Data
public class RecursionReferObject {

    private String name;

    private RecursionObject refer;
}



public class GsonRecursionTest {


    public static void main(String[] args) {
        RecursionObject parent = new RecursionObject();
        parent.setName("1");

        RecursionReferObject son = new RecursionReferObject();
        son.setName("2");

        parent.setRefer(son);
        son.setRefer(parent);
        
        Gson gson = new GsonBuilder().create();
        String json=gson.toJson(parent);
        System.out.println(json);
        RecursionObject recursionObject=gson.fromJson(json,RecursionObject.class);
        System.out.println(recursionObject);
    }
}


/***
Exception in thread "main" java.lang.StackOverflowError
    at com.google.gson.stream.JsonWriter.string(JsonWriter.java:566)
    at com.google.gson.stream.JsonWriter.writeDeferredName(JsonWriter.java:402)
    at com.google.gson.stream.JsonWriter.value(JsonWriter.java:417)
    at com.google.gson.internal.bind.TypeAdapters$16.write(TypeAdapters.java:406)
    at com.google.gson.internal.bind.TypeAdapters$16.write(TypeAdapters.java:390)
/**

说明:

  • 推荐对象字段使用基础类型
  • 不需要添加给字段添加注解来表示该字段需要序列化,因为当前类(所有父类)中的所有字段默认都会被序列化
  • 如果一个字段被标记为transient,默认它在序列化/反序列化时会被忽略
  • null的处理
    • 当序列化时,一个null字段会被省略
    • 当反序列化时,如果一个字段找不到,则对应的对象字段会被设置为以下默认值:对象类型为null,数值类型为0,boolean类型为false
  • 被synthetic 标记的字段,也会在序列化/反序列化过程中被忽略
  • 内部类、匿名类、本地类所对应的外部类字段,在序列化/反序列化过程中也将会忽略(这块没太理解)

1.2.3.内部类(没看太懂)

Gson can serialize static nested classes quite easily.

Gson can also deserialize static nested classes. However, Gson can not automatically deserialize the pure inner classes since their no-args constructor also need a reference to the containing Object which is not available at the time of deserialization. You can address this problem by either making the inner class static or by providing a custom InstanceCreator for it. Here is an example:

public class A { 
  public String a; 

  class B { 

    public String b; 

    public B() {
      // No args constructor for B
    }
  } 
}

NOTE: The above class B can not (by default) be serialized with Gson.

Gson can not deserialize {"b":"abc"} into an instance of B since the class B is an inner class. If it was defined as static class B then Gson would have been able to deserialize the string. Another solution is to write a custom instance creator for B.

public class InstanceCreatorForB implements InstanceCreator<A.B> {
  private final A a;
  public InstanceCreatorForB(A a)  {
    this.a = a;
  }
  public A.B createInstance(Type type) {
    return a.new B();
  }
}

The above is possible, but not recommended.

1.2.4.Array

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

// Serialization
gson.toJson(ints);     // ==> [1,2,3,4,5]
gson.toJson(strings);  // ==> ["abc", "def", "ghi"]

// Deserialization
int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class); 
// ==> ints2 will be same as ints

支持多维。

1.2.5.集合

Gson gson = new Gson();
Collection<Integer> ints = Lists.immutableList(1,2,3,4,5);

// Serialization
String json = gson.toJson(ints);  // ==> json is [1,2,3,4,5]

// Deserialization
Type collectionType = new TypeToken<Collection<Integer>>(){}.getType();
Collection<Integer> ints2 = gson.fromJson(json, collectionType);
// ==> ints2 is same as ints

限制:gson可以序列化任意对象的集合,但是反序列化时需要指定集合元素的类型。

1.2.泛型

1.2.1.TypeToken的使用

1.2.1.1.对象类型的泛型
class Foo<T> {
  T value;
}
Gson gson = new Gson();
Foo<Bar> foo = new Foo<Bar>();
gson.toJson(foo); // May not serialize foo.value correctly

gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar

Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.toJson(foo, fooType);
gson.fromJson(json, fooType);

通过TypeToken来定义泛型类型。

1.2.1.2.集合类型的泛型

@Data
public class Bar {

    private String name;
}

public class GsonListTest {

    public static void main(String[] args) {
        Gson gson = new GsonBuilder().create();

        List<Bar> bars = new ArrayList<>();

        Bar bar = new Bar();
        bar.setName("bar 1");

        bars.add(bar);
        String json = gson.toJson(bars);
        System.out.println(json);
        Type type = new TypeToken<List<Bar>>(){}.getType();
        List<Bar> dbars = gson.fromJson(json,type);
        System.out.println(dbars);

    }
}

/**
[{"name":"bar 1"}]
[Bar(name=bar 1)]
***/

1.2.2.自定义ParameterizedType

在实际项目中,如果使用大量使用TypeToken,定义起来会比较麻烦,查看TypeToken的底层源码,发现它也是通过ParameterizedType来实现的。(不懂ParameterizedType的可以先百度一下)


public class MyParameterizedType implements ParameterizedType {

    private Type[] args;

    private Class rawType;

    public MyParameterizedType( Class rawType,Type[] args) {
        this.args = args;
        this.rawType = rawType;
    }

    @Override
    public Type[] getActualTypeArguments() {
        return args;
    }

    @Override
    public Type getRawType() {
        return rawType;
    }

    @Override
    public Type getOwnerType() {
        return null;
    }
}


//测试复杂泛型类型

public class ParameterizedTypeTest {

    public static void main(String[] args) {
        Gson gson = new GsonBuilder().create();
        Result<List<Bar>> result = new Result<>();
        List<Bar> bars = new ArrayList<>();
        Bar bar = new Bar();
        bar.setName("bar 1");
        bars.add(bar);
        result.setData(bars);
      
        Type inner = new MyParameterizedType(List.class, new Class[]{Bar.class});
        MyParameterizedType type = new MyParameterizedType(Result.class,new Type[]{inner});
      
        String json = gson.toJson(result);
        System.out.println(json);
        Result<List<Bar>> result1=gson.fromJson(json,type);
        System.out.println(result1);

    }
}

1.3.null值处理

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



public class Foo {
  private final String s;
  private final int i;

  public Foo() {
    this(null, 5);
  }

  public Foo(String s, int i) {
    this.s = s;
    this.i = i;
  }
}

Gson gson = new GsonBuilder().serializeNulls().create();
Foo foo = new Foo();
String json = gson.toJson(foo);
System.out.println(json);

json = gson.toJson(null);
System.out.println(json);

{"s":null,"i":5}
null

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容