Gson介绍

Gson

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

首先须要添加依赖git

//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设计的很是易用,基本上一看就懂。github

 

转换基础数据类型

// 建立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也支持对对象类型的转换json

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的字段有很好的支持maven

 

转换数组类型

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

 

集合类型

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

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的泛型自己就被吐槽好久了,各类毛病)gradle

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

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

若是想要成功序列化带有泛型类型的对象,须要使用Type对象ui

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

gson.fromJson(json, fooType);

 

转换带有混合类型的集合

有时候你可能会在一个集合中放入不一样的类型(虽然我我的强烈不推荐这样写,由于泛型的做用就是为了省掉没必要要的cast,你还放入不一样类型,这不是自找麻烦吗?) 
可是若是你真的这样写了,gson仍是能够帮你转换this

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 Serializers: 自定义某种对象类型的序列化行为

Json Deserializers: 自定义某种对象类型的反序列化行为

Instance Creators: 自定义某种对象的建立行为

此时咱们须要配置gsonbuilder,而后用gsonbuilder来建立gson对象,builder模式你们应该很熟悉了 
代码以下

GsonBuilder gsonBuilder= new GsonBuilder();
gson.registerTypeAdapter(MyType.class, new MySerializer());
gson.registerTypeAdapter(MyType.class, new MyDeserializer());
gson.registerTypeAdapter(MyType.class, new MyInstanceCreator());
Gson gson=gsonBuilder.create();

为某类型注册了自定义的序列化和反序列化行为以后,在转换的过程当中一旦遇到该类型的对象,就会调用你注册的行为来序列化。 
这些的类的实现也很容易。

//自定义序列化,须要实现JsonSerializer接口
private class DateTimeSerializer implements JsonSerializer<DateTime> {
  public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
    return new JsonPrimitive(src.toString());
  }
}
//自定义序列化,须要实现DateTimeDeserializer 接口
private class DateTimeDeserializer implements JsonDeserializer<DateTime> {
  public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException {
    return new DateTime(json.getAsJsonPrimitive().getAsString());
  }
}
//自定义对象建立,须要实现InstanceCreator
private class MoneyInstanceCreator implements InstanceCreator<Money> {
  public Money createInstance(Type type) {
    return new Money("1000000", CurrencyCode.USD);
  }
}

在我我的使用gson的过程当中,我发现有些时候是不得不用自定义序列化和反序列化的,由于在使用默认的行为的状况下,对一些复杂对象常常出错,具体缘由我也不知道为何,不少时候都是出现了死循环,可能java一些类中自己就存在双向引用吧,此外还有一些其余的异常,主要缘由都是java一些类自己的继承结构太深了。

 

咱们以序列化Image为例(该类直接序列化会报错) 
这个代码是我实际项目中使用的,将javafx的image对象序列化(固然对于图像对象,最后还要使用压缩流来减小体积)

public class GsonImage implements JsonSerializer<Image>,JsonDeserializer<Image> {

    @Override
    public Image deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {

        Gson gson=new Gson();
        byte[] bs=gson.fromJson(json.getAsString(), byte[].class);
        BufferedImage image = null;
        try {
            //从字节数组建立图片
            image = ImageIO.read(new ByteArrayInputStream(bs));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Image image2=SwingFXUtils.toFXImage(image, null);

        return image2;
    }

    @Override
    public JsonElement serialize(Image image, Type typeOfSrc, JsonSerializationContext context) {



        Gson gson=new Gson();
        ByteArrayOutputStream stream=new ByteArrayOutputStream();
        BufferedImage bufferedImage=SwingFXUtils.fromFXImage(image, null);
        try {
            ImageIO.write(bufferedImage, "PNG", stream);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        byte[] imgBytes=stream.toByteArray();
        //实际上序列化的是字节数组
        String string=gson.toJson(imgBytes);

        return new JsonPrimitive(string);
    }

}

除了三种自定义行为以外,gsonbuilder还提供了一些配置

setPrettyPrinting() //设置输出格式为可读性优先(默认是体积小优先)
serializeNulls() //设置输出null(默认null会被忽略)
excludeFieldsWithModifiers()//设置不被包括在序列化中的修饰符(默认为static //transient,可是你能够覆盖设置)

关于gson就介绍到这里

能够访问gson的github帮助页面来获取更多信息 
https://github.com/google/gson/blob/master/UserGuide.md

相关文章
相关标签/搜索