加入收藏 | 设为首页 | 会员中心 | 我要投稿 鄂州站长网 (https://www.0711zz.com/)- 数据分析、网络、云渲染、应用安全、大数据!
当前位置: 首页 > 编程开发 > Java > 正文

GSON实现Java对象与JSON格式对象相互转换的完全教程

发布时间:2020-11-17 23:55:09 所属栏目:Java 来源:互联网
导读:Gson是一个Java库,用来实现Json和Java对象之间的相互转换。Gson是一个托管在https://github.com/google/gson的开源项目。

Gson是一个Java库,用来实现Json和Java对象之间的相互转换。Gson是一个托管在https://github.com/google/gson的开源项目。

Gson中主要的类是Gson,也可以使用类GsonBuilder在创建Gson对象的同时设置一些选项。
Gson对象在处理Json时不会保存任何状态,所以使用者能够很轻松的对同一个Gson对象进行多次序列化、反序列化等操作。

示例:基本使用

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

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

//Serialization
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj); 
//==> json is {"value1":1,"value2":"abc"}

示例:对象与Json之间转换

定义BagOfPrimitives类:

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

序列化为Json:

//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

处理对象时的一些细节:

  • 推荐使用私有字段(译者:可以通过反射获取私有字段的名称和值)
  • 没有必要使用标注指明哪些字段该被序列化或者反序列化。在当前类(也包括其父类)中的所有字段都默认会被序列化/反序列化。
  • 如果某字段在声明时使用了关键字transient,默认情况下不会被序列化/反序列化。
  • Gson如下处理null字段:
  • 序列化时候null字段会被跳过
  • 反序列化时,类中有但Json中没有的字段将设值为null。
  • synthetic字段不会被序列化/反序列化。
  • 在外部类(outer classes)中的内部类(inner classes)、匿名类(anonymous classes)和局部类(local classes)中的字段不会被序列化/反序列化。

嵌套类(包括内部类)的处理

Gson可以很轻松地序列化嵌套类,且能够反序列化静态的嵌套类。Gson无法自动地反序列化纯粹的内部类,是因为内部类的无参构造函数需要引用包含它的对象(即外部类的实例)。要反序列化静态类,可以将内部类静态化或者提供一个自定义的实例创造器(instance creator)。下面是一个示例:

public class A {
 public String a;

 class B {

 public String b;

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

上面的类B无法被Gson序列化。由于类B是一个(非静态的)内部类,Gson也无法反序列化{"b":"abc"}到类B的实例中。如果B被声明为static class B,那么Gson就能对这个字符串反序列化了。

另外一个解决方法是为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();
 }
}

这种方法是可行的,但是不推荐。(译者表示没看懂这个实例创建器,不知道该怎么用)

示例:数组

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

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

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

Gson也支持具有复杂数据类型的多维数组。

示例:集合(Collection)

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

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

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

处理集合(Collection)时的限制:

  • 可以序列化任意对象的集合,反序列化就不行了。
  • 反序列化时,集合必须是指定的泛型。

序列化/反序列化泛型

当使用toJson(obj)时,Gson调用obj.getClass()获取字段信息以在序列化中使用。类似的,也可以将对象MyClass.class作为参数传递给fromJson(json,MyClass.class)方法,这可以在在对象不是泛型的时候使用。不过,当对象是一个泛型类型的对象,由于Java中类型擦除(Type Erasure)这一机制,泛型类型信息会丢失。下面的例子将说明这一点:

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

上面的代码将value解释为Bar类型,这是因为Gson调用foo.getClass()获取类的信息,但是这种那个方法返回的是一个原始的类,即Foo.class。这意味着Gson无法知道这是一个Foo<Bar>类型的对象。

要解决这个问题,可以是为你的泛型指定正确的参数化的类型。可以使用TypeToken类做到:

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

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

通过Gson,你不需要做任何特殊的事情就可以序列化集合:toJson(collection)会输出令人满意的结果。

然而,通过fromJson(json,Collection.class)反序列化是不行的,这是因为Gson无法将json中的的内容与类型对应起来。Gson需要你在fromJson中提供一个通用版本的集合类型。你有三个选择:

方案1:使用Gson解析器的API(低级的流解析器或者DOM解析器JsonParser)去解析数组元素,然后使用Gson.fromJson()处理每一个数组元素。这是首选的方案。
方案2:为Collection.class注册一类型适配器将数组中的元素映射到合适的对象。这种方法的缺点是会使你在处理其他的集合类型时候产生不便。
方案3:为MyCollectionMemberType注册一个类型适配器,在fromJson中使用Collection<MyCollectionMemberType>。只有当数组看起来像一个高级的元素或者你能够将字段类型改成Collection<MyCollectionMemberType>,这种方法才比较可行。
内置的序列化/反序列化器

Gson为常用的但是默认表示可能并不合适的类提供了序列化/反序列化器。
下面是这些类的一个列表:

  • java.net.URL,例如会序列化为字符串 http://code.google.com/p/google-gson/
  • java.net.URI,例如会序列化为字符串/p/google-gson/

自定义序列化/反序列化

有时候,Gson的默认实现并不是你想要的,这在处理一些类库时(例如DateTime)时比较常见。

Gson允许你注册自定义的序列化/反序列化器。要这样做的话,你需要实现以下几个部分:

Json序列化器:需要为一个对象自定义序列化
Json反序列化器:需要为一个类型自定义反序列化
类创建器:如果存在无参构造函数或者已经注册了一个反序列化器,就不需要了。

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

registerTypeAdapter会检查类型适配器是否实现了多个接口,并为这些接口注册类型适配器。

写一个序列化器

(编辑:鄂州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读