gson是一个java库,用作java对象和json表达式之间的转换。gson可以处理任何Java对象,包括已经存在的、你没有源代码的对象。gson有很多的优势,比如它强大的功能:1.反序列化25M以上的字符串没有任何问题。2.它可以序列化一个有140万个对象的集合,3.反序列话87000个对象的集合,4.gson1.4 提高了反序列化字节数组的限制,从87KB提高到了11M.此外。
在刚开始学习Gson的时候,我试图在百度上寻找资料。是的,资料很多,但都是零零散散的资料,并不是我想要的系统的学习资料。浏览了下Gson官网,看到有个Gson User Guilde,我觉得从这里切入是不错的选择,虽然我英语很烂,六级都没过,但是我发现阅读英文资料好像更容易读懂一点,貌似编程这东西用英语表示能表示的更加具体和清晰。
下载地址:点击下载gson,下载好以后把jar文件放入libs目录下,然后在android studio中,在jar文件上右键,选择add as library
json源码里面有个examples目录,这个目录下有个android的例子。这个例子界面有点丑,如下:
但是使用这个例子可以帮你省去一些时间,在使用这个工程的时候,注意,直接用android studio打开后是无法使用的,但是你可以用android studio 下的 File->New->import Project功能,它会为你生成android studio可以直接运行的项目。如果这个过程出了问题,应该是gradle的某些配置不对,如果你遇到类似的问题,可以参考下我的这两篇文章:
理解与配置android studio中的gradle
详细配置android studio中的gradle
为了使用Gson,首先需要获得Gson的一个实例,有两种方法获得它:1. new Gson(),2. GsonBuilder,使用这个类也可以创建一个Gson实例,并且你可以做一些设置,比如版本控制等等。
使用new Gson会创建一个默认参数的Gson对象,你基本不需要做什么,家乡下面这样:
Gson gson = new Gson();
如果你想做细致的控制,可以像下面这样:
Gson gson = new GsonBuilder() .registerTypeAdapter(Id.class, new IdTypeAdapter()) .enableComplexMapKeySerialization() .serializeNulls() .setDateFormat(DateFormat.LONG) .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE) .setPrettyPrinting() .setVersion(1.0) .create();Gson真的设计的非常简练,使用Gson转换java对象与json表达式貌似主要涉及两个方法,而且很多情况下这个两个方法就能搞定一切,这两个方法就是toJson()和fromJson()。
<span style="font-family:SimSun;font-size:14px;"> // 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);</span>
<span style="font-family:SimSun;font-size:14px;"> 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</span>注意:你不能序列化一个循环引用,这将会导致无限循环。
关于序列化与反序列化的对象的一些细节:
Gson可以轻易的序列化静态嵌套类。
Gson也可以反序列化静态嵌套类。Gson不能自动反序列化纯内部类,因为他们的无参构造函数也需要包含对象的引用,而这个引用在反序列化的时候不可用。你可以使用两种方法解决这个问题:
比如说一下例子:
public class A { public String a; class B { public String b; public B() { // No args constructor 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(); } }
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 intsGson也支持多维数组。
<span style="font-family:SimSun;font-size:14px;">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</span>
当我们调用toJson(obj),Gson会调用obj.getClass()来获取需要序列化的字段。同样的,我们可以传入MyClass.class对象给fromJson(json,MyClass.class),当对象不是泛型的时候,一切都工作良好,可是,如果对象是泛型,由于java类型擦除机制,泛型的信息会丢失。下面有一个解释这点的例子:
<span style="font-family:SimSun;font-size:14px;">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</span>上面的代码无法过去Bar类型的值,所以会解析失败。因为Gson会调用list.getClass()获得类信息,但是这个方法返回了一个原始的值,Foo.class,也就是说我们无法知道类的类型是一个Foo<Bar>类型,而不是Foo类型。
你可以解决这个问题,使用指定泛型的正确的参数化类型:
<span style="font-family:SimSun;font-size:14px;">Type fooType = new TypeToken<Foo<Bar>>() {}.getType(); gson.toJson(foo, fooType); gson.fromJson(json, fooType);</span>
这里通过将要过去类型的泛型类型,传递给一个TypeToken的匿名子类的getType方法,从而获得一个完全的参数化类型。
有时候需要处理包含多种类型的json数组,比如:
<span style="font-family:SimSun;font-size:14px;">{name:'GREETINGS',source:'guest'}]</span>与之等价的集合是这样的:
<span style="font-family:SimSun;font-size:14px;">Collection collection = new ArrayList(); collection.add("hello"); collection.add(5); collection.add(new Event("GREETINGS", "guest"));</span>
<span style="font-family:SimSun;font-size:14px;">class Event { private String name; private String source; private Event(String name, String source) { this.name = name; this.source = source; } }</span>你可以序列化集合使用toJson(connect),这没有任何问题,可以的要期望的结果
但是,如果是使用fomJson进行反序列化的话就不能进行,因为Gson不知道怎样把输入映射为类型。所以你有三个选择解决这个问题:
<span style="font-family:SimSun;font-size:14px;"> Gson gson = new Gson(); Collection collection = new ArrayList(); collection.add("hello"); collection.add(5); collection.add(new Event("GREETINGS", "guest")); String json = gson.toJson(collection); System.out.println("Using Gson.toJson() on a raw collection: " + json); JsonParser parser = new JsonParser(); JsonArray array = parser.parse(json).getAsJsonArray(); String message = gson.fromJson(array.get(0), String.class); int number = gson.fromJson(array.get(1), int.class); Event event = gson.fromJson(array.get(2), Event.class); System.out.printf("Using Gson.fromJson() to get: %s, %d, %s", message, number, event);</span>
Gson User Guilde内容较多,这里就只介绍它的常规使用,其他的内容会在后续的文章中继续探究。