Gson详解--入门篇

Gson

目前主流的json解析类库有jackson,fastjson,gson,gson的serialization deserialization解析功能无疑是最强大的,基本上完美支持复杂对象的json化和反json化,其他两个库在转换复杂对象时都容易出现问题。如果在不考虑效率的情况下,我强烈推荐使用gson类库。

首先需要添加依赖

//gradle

dependencies {
    compile 'com.google.code.gson:gson:2.8.2'
}

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

接下来看一些代码例子,gson设计的非常易用,基本上一看就懂。

转换基础数据类型

// 创建gson对象,gson对象是内部无状态的,所以创建一个可以多次使用,可以想象成一个转换器
Gson gson = new Gson();
//转换成json只用直接放入对象就行,gson在内部会提取对象的类型信息
gson.toJson(1);            // ==> 1
gson.toJson("abcd");       // ==> "abcd"
gson.toJson(new Long(10)); // ==> 10
int[] values = { 1 };
gson.toJson(values);       // ==> [1]

// 反json化,此时需要传入类型参数,因为json中是没有保存关于java类型的信息的
int one = gson.fromJson("1", int.class);
Integer one = gson.fromJson("1", Integer.class);
Long one = gson.fromJson("1", Long.class);
String str = gson.fromJson("\"abc\"", String.class);

转换对象类型

当然,gson也支持对对象类型的转换

class BagOfPrimitives {
  private int value1 = 1;
  private String value2 = "abc";
  //使用transient标识的变量不会被json化 
  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"}

不过注意你不能json化一个具有循环引用的对象,会导致死循环(简单来说就是a有一个变量为b,b也有一个变量为a,此时无论json化谁都会导致死循环)

使用gson序列化对象的要点

1.完全可以使用private修饰变量类型,因为gson内部是使用反射来进行json化的,所以private也完全可以读取的到
2.完全没有必要使用任何的annotations 来标注哪个字段需要被包含(有很多其他库是使用annotations 来标记的),gson默认会序列化当前类中的所有字段(包括他的所有父类)
3.如果一个字段被标记为transient,他不会被Json化
4.gson对值为null的字段有很好的支持

转换数组类型

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); 

集合类型

java对集合类型是做了特殊支持的,输出的效果基本和数组一样,除了元素之外不会输出其他的字段例如 size之类的

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

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

        // Deserialization
        //对于泛型类型,因为直接取得的class并不包括泛型类型,所以需要创建type再传入
        Type collectionType = new TypeToken<Collection<Integer>>(){}.getType();
        Collection<Integer> ints2 = gson.fromJson(json, collectionType);

转换泛型类型

因为gson内部是使用getClass来获取类型信息,返回的类型都不包括泛型参数类型,所以直接像之前使用的话,序列化和反序列化都会失败
(其实不只是gson,java的泛型本身就被吐槽很久了,各种毛病)

class Foo<T> {
  T value;
}
Gson gson = new Gson();
Foo<Bar> foo = new Foo<Bar>();
gson.toJson(foo); //不能成功序列化

gson.fromJson(json, foo.getClass()); // 无法反序列化

如果想要成功序列化带有泛型类型的对象,需要使用Type对象

//注意这里的TypeToken带有{},其实是一个匿名类,因为TypeToken的构造器是非Public的,不能直接构造,我也不太清楚为什么要这样设计
Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.toJson(foo, fooType);

gson.fromJson(json, fooType);

转换带有混合类型的集合

有时候你可能会在一个集合中放入不同的类型(虽然我个人强烈不推荐这样写,因为泛型的作用就是为了省掉不必要的cast,你还放入不同类型,这不是自找麻烦吗?)
但是如果你真的这样写了,gson还是可以帮你转换

Collection collection = new ArrayList();
collection.add("hello");
collection.add(5);
collection.add(new Event("GREETINGS", "guest"));

class Event {
  private String name;
  private String source;
  private Event(String name, String source) {
    this.name = name;
    this.source = source;
  }
}

你完全可以像直接一样直接序列化这个集合,没有任何问题。
但是之前也说过,json没有保存关于java对象类型的任何信息(作为一个通用的数据交换格式他这样做是正确的,否则这段json数据就只有gson才能解析了)。
之前我们在反序列化的同时都要手动传入类型参数,但是作为一个混合集合,显然没有一个所谓的’类型参数’,所以直接反序列化是不可能了。
如果你想要反序列化这样的json,有以下几种选择。
1.使用原始的json类库手动解析
2.注册一个collection 的adapter(我们下一篇会讲),自定义解析过程(还是需要手动解析)
所以如果想要反序列化这样的集合,无论怎么样都要手写解析,没什么办法,所以最好还是不要在泛型集合里放入不同的类型

要点总结

gson在序列化对象到json的过程中并没有保存对象的类型信息,所以在反序列化过程中,需要手动传入参数(就是你自己要清楚这个对象原来是什么)
因为我自己也写过简单的json转换类库,我说一下在json中如果保存java类型信息的好处和坏处
首先什么是在json中保存java的类型信息呢,就是例如使用一些额外的字段,将关于该对象本身类型的信息,也加入到json中。
好处:反序列化时不用输入类型参数,直接反序列化
坏处:json体积更大,而且直接序列化json的那个库,才能直接反序列化对应的json,其他的库就不行了,而且限定于java,因为类型信息只是关于java的

关于json的更多高级用法,我们会在下一篇中提及

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值