Gson源码学习笔记(1)——Gson使用教程(译)

来源:互联网 发布:网络日语速成法 编辑:程序博客网 时间:2024/05/17 02:50

本文是译文,原文地址:https://github.com/google/gson/blob/master/UserGuide.md
概述:

标题

Gson是一个用来将java对象转换为JSON形式的Java库。它也可以被用于将JSON字符串转换为相应的JSON字符串。
Gson可以处理任意的Java对象,包括那些你还没有用代码写出来的已存在的对象。

Gson的目的

  • 提供简便的方式来通过固定的机制像toString和构造方法(工厂方法)来将Java转化为JSON,反之亦然。
  • 允许预先存在的不可改变的方法被转变为JSON,或由JSON转变而来。
  • 允许对象的自定义表现形式。
  • 支持多变的复杂的对象。
  • 产生精炼并且可读的JSON输出。

Gson性能和可扩展性

我们先申明一下运行环境(双核,8GB 内存,64位Ubuntu),在此平台上我们并行运行大量的测试。你可以在这个类PerformanceTest中找到
结果表明,反序列25MB的strings没有任何问题。
对于大的集合而言,序列化140万个对象,反序列化87000个对象的集合也没有任何问题。

Gson用户

Gson原先是由谷歌内部使用的,现在已经被一系列的公司和项目使用了。

使用Gson

主要的类就是Gson。你可以通过调用new Gson()来调用这个类。你也可以通过类GsonBuilder来创造一个Gson实例,并给它设置各种的设置,比如版本控制等等。
Gson实例在调用Json操作时并不保存任何状态。因此。你完全可以重用同一个对象来进行多次的序列化操作和反序列化操作。

应用Maven来使用Gson

可以通过Maven来使用Gson,你可以在Maven中心添加如下依赖应用Gson版本。

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

然后,你的maven对象就支持Gson了。

举个简单的例子

// SerializationGson gson = new Gson();gson.toJson(1);            // ==> 1gson.toJson("abcd");       // ==> "abcd"gson.toJson(new Long(10)); // ==> 10int[] values = { 1 };gson.toJson(values);       // ==> [1]// Deserializationint 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);

对象例子

class BagOfPrimitives {  private int value1 = 1;  private String value2 = "abc";  private transient int value3 = 3;  BagOfPrimitives() {    // no-args constructor  }}// SerializationBagOfPrimitives obj = new BagOfPrimitives();Gson gson = new Gson();String json = gson.toJson(obj);  // ==> json is {"value1":1,"value2":"abc"}

注意,你不能序列化有循环引用的对象,因为这会导致无限循环。

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

对象序列化得一些值得注意的点

  1. 使用私有域是非常好的并且推荐的。
  2. 没必要通过使用注解来声明一个域是被序列化或者被反序列化的。在当前的类中的所有域默认都是被包含在内的(指的是,对象被序列化了,里面的变量也就默认被序列化了)
  3. 如果一个域被标记为transient,(默认情况下)他会被忽视,不会被JSON序列化或者反序列化。
  4. 实现能正确的控制nulls
  5. 当序列化时,一个null的域会被从输出中跳过。
  6. 当反序列化时,在JSON结果中的一个丢失的对象,在转换的对象中,对应的是null。
  7. 如果一个域是synthetic(合成的)的,它会被忽略,而不会包含在JSON序列化或者反序列化中。

嵌套类(包括内部类)

Gson能轻易地序列化static的反序列化类。
不过Gson不能自动地反序列化内部类,因为他们的无参构造方法也需要一个引用来指向在反序列化期间无法访问的包含对象。你可以通过将内部类变为static或者提供一个自定义的instaceCreater来解决这个问题。

public class A {   public String a;   class B {     public String b;     public B() {      // No args constructor for B    }  } }

注意:上述B默认无法被Gson序列化。
Gson不能将{“b”:”abc”}反序列化为B的一个实例,因为B类是一个内部类。如果它被定义为static,那么Gson就可以反序列化这个字符串了。另一个方法是为B写一个自定义的instance creater。

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

上述方法是可行的,但是不被推荐。

数组例子

Gson gson = new Gson();int[] ints = {1, 2, 3, 4, 5};String[] strings = {"abc", "def", "ghi"};// Serializationgson.toJson(ints);     // ==> [1,2,3,4,5]gson.toJson(strings);  // ==> ["abc", "def", "ghi"]// Deserializationint[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class); // ==> ints2 will be same as ints

我们也支持存储任意复杂元素类型的多维数组。

集合例子

Gson gson = new Gson();Collection<Integer> ints = Lists.immutableList(1,2,3,4,5);// SerializationString json = gson.toJson(ints);  // ==> json is [1,2,3,4,5]// DeserializationType collectionType = new TypeToken<Collection<Integer>>(){}.getType();Collection<Integer> ints2 = gson.fromJson(json, collectionType);// ==> ints2 is same as ints

注意我们是如何定义集合的类型的,不幸的是,在java中没有办法绕过他。

集合限制

Gson能够序列化任意对象的集合,但是没办法反序列化它们,因为用户没办法声明结果对象的类型。事实上,在反序列化时,集合必须是一个具体的泛化得类型。这个是有意义的,遵从这样的一个好的java编程习惯能减少很多的问题。

序列化和反序列化泛型

当你调用toJson(obj)时,Gson会调用obj.getClass()来获取序列化区域的信息。类似的,你可以将myClass.class对象通过在fromJson(json, MyClass.class)中传过去。如果对象不是泛型,那么会做的很好,不过,如果是泛型,那么因为java的类型擦除,这个泛型信息会丢失。这里有个例子来阐明这点。

class Foo<T> {  T value;}Gson gson = new Gson();Foo<Bar> foo = new Foo<Bar>();gson.toJson(foo); // May not serialize foo.value correctlygson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar

上述的代码会失败,因为Gson调用了list.getClass来获得它的类信息,但是这个方法返回一个原始类,Foo.class。这意味着Gson没有办法知道这个类型是Foo,而不是Foo。
你可以通过为你的泛型说明正确的序列类型来解决这个问题。你可以通过使用TypeToken类来做到这点。

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

这个方法经常被用于定义一个匿名的内部类,内部类中包含了方法getType(),这个方法能够返回完全参数化得类型。

序列化和反序列化存储不同对象类型的集合

有时,你会处理一些json数组,这些数组存储复合类型。比如:[‘hello’,5,{name:’GREETINGS’,source:’guest’}]
比如:

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

这里的Event被如下定义:

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

你可以不用添加其他的操作就能序列化collection:toJson(collection)可以写出我们想要的输出。
不过,fromJson(json, Collection.class)是不会按我们希望的工作的,因为Gson没有办法知道如何匹配输出的类型。Gson要求你在fromJson中提供一个通用的collection类型。因此,你有3个选项:

  • 使用Gson’s parser的API(流解析器或者Dom解析器)来解析数据元素,然后在每一个数组元素上使用Gson.fromJson()。这是推荐的方法,这里有个例子。
  • 为Collection类注册一个类型适配器,来处理每一个数组成员,将它们和合适的对象匹配起来。这个方法的缺点在于,它会被在Gson中其他collection的反序列化所污染。
  • 为MyCollectionMemberType注册一个类型适配器,然后通过Collection的形式来使用fromJson()。

这个方法只有在数组作为最外围元素或者你可以将控制collection的域类型为变为类型Collection的情况下。

创建Serializers和Deserializers

Gson有已经创建好用于常用类的Serializers和Deserializers。这些类如下所示:
- java.net.URL to match it with strings like “https://github.com/google/gson/”
- java.net.URI to match it with strings like “/google/gson/”
你可以在这个网址找到一些常用类的源码。

自定义Serialization 和 Deserialization

有时候默认的序列化结果不是你想要的,Gson允许你注册你自定义的serializers 和 deserializers。这通常通过以下两部分来实现:
- Json serializers :需要为对象定义一个自定义的serialization
- Json Deserializers:需要为类型定义一个自定义的deserialization。
- Instance Creators:如果有无参构造器的话或者deserializer已经被注册了,那就不需要了。

GsonBuilder gson = new GsonBuilder();gson.registerTypeAdapter(MyType2.class, new MyTypeAdapter());gson.registerTypeAdapter(MyType.class, new MySerializer());gson.registerTypeAdapter(MyType.class, new MyDeserializer());gson.registerTypeAdapter(MyType.class, new MyInstanceCreator());

如果这个type adapter 实现了这些接口中的多个,并注册了它们,registerTypeAdapter会调用检测。

写一个Serializer

这里有一个实例来展示如何为JodaTime DateTime class.编写一个自定义的Serializer的。

private class DateTimeSerializer implements JsonSerializer<DateTime> {  public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {    return new JsonPrimitive(src.toString());  }}

Gson在序列化DateTime时就会调用serialize()方法。

写一个Deserializer

这里有一个实例来展示如何为JodaTime DateTime class.编写一个自定义的Deserializer的。

private class DateTimeDeserializer implements JsonDeserializer<DateTime> {  public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)      throws JsonParseException {    return new DateTime(json.getAsJsonPrimitive().getAsString());  }}

Gson在将JSON字符串反序列化为DateTime对象时,会调用deserialize()

Serializers 和 Deserializers的重点

你可能经常想要为一个原始类型的所有泛型注册一个handler。

  • 例如:假设你对 id representation/translation有一个ID class。
  • ID 类型对所有的泛型有同一个serialization。
    -本质上是输出id值

  • Deserialization是极其相似的,但不完全一样。
    -需要调用new Id(Class, String),它会返回Id实例。

写一个instance creater

当你处理没有定义无参构造器的库类时,instance creator是被需要的。
来个例子:

private class MoneyInstanceCreator implements InstanceCreator<Money> {  public Money createInstance(Type type) {    return new Money("1000000", CurrencyCode.USD);  }}

参数化类型的instanceCreater

有时候你将实例化一个参数化类型。

class MyList<T> extends ArrayList<T> {}class MyListInstanceCreator implements InstanceCreator<MyList<?>> {    @SuppressWarnings("unchecked")  public MyList<?> createInstance(Type type) {    // No need to use a parameterized list since the actual instance will have the raw type anyway.    return new MyList();  }}
public class Id<T> {  private final Class<T> classOfId;  private final long value;  public Id(Class<T> classOfId, long value) {    this.classOfId = classOfId;    this.value = value;  }}class IdInstanceCreator implements InstanceCreator<Id<?>> {  public Id<?> createInstance(Type type) {    Type[] typeParameters = ((ParameterizedType)type).getActualTypeArguments();    Type idType = typeParameters[0]; // Id has only one parameterized type T    return Id.get((Class)idType, 0L);  }}
0 0