gson是一个java库,用作java对象和json表达式之间的转换。gson可以处理任何Java对象,包括已经存在的、你没有源代码的对象。gson有很多的优势,比如它强大的功能:1.反序列化25M以上的字符串没有任何问题。2.它可以序列化一个有140万个对象的集合,3.反序列话87000个对象的集合,4.gson1.4 提高了反序列化字节数组的限制,从87KB提高到了11M.此外。
在刚开始学习Gson的时候,我试图在百度上寻找资料。是的,资料很多,但都是零零散散的资料,并不是我想要的系统的学习资料。浏览了下Gson官网,看到有个Gson User Guilde,我觉得从这里切入是不错的选择,虽然我英语很烂,六级都没过,但是我发现阅读英文资料好像更容易读懂一点,貌似编程这东西用英语表示能表示的更加具体和清晰。
1.下载Gson与例程的使用
1.下载gson
下载地址:点击下载gson,下载好以后把jar文件放入libs目录下,然后在android studio中,在jar文件上右键,选择add as library
2.使用源码中的例子
json源码里面有个examples目录,这个目录下有个android的例子。这个例子界面有点丑,如下:
但是使用这个例子可以帮你省去一些时间,在使用这个工程的时候,注意,直接用android studio打开后是无法使用的,但是你可以用android studio 下的 File->New->import Project功能,它会为你生成android studio可以直接运行的项目。如果这个过程出了问题,应该是gradle的某些配置不对,如果你遇到类似的问题,可以参考下我的这两篇文章:
2 使用Gson
为了使用Gson,首先需要获得Gson的一个实例,有两种方法获得它:1. new Gson(),2. GsonBuilder,使用这个类也可以创建一个Gson实例,并且你可以做一些设置,比如版本控制等等。
2.1 new Gson()或者GsonBuilder. create()?
使用new Gson会创建一个默认参数的Gson对象,你基本不需要做什么,家乡下面这样:
Gson gson = new Gson();
如果你想做细致的控制,可以像下面这样:
Gson gson = new GsonBuilder()Gson真的设计的非常简练,使用Gson转换java对象与json表达式貌似主要涉及两个方法,而且很多情况下这个两个方法就能搞定一切,这两个方法就是toJson()和fromJson()。
.registerTypeAdapter(Id.class, new IdTypeAdapter())
.enableComplexMapKeySerialization()
.serializeNulls()
.setDateFormat(DateFormat.LONG)
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
.setPrettyPrinting()
.setVersion(1.0)
.create();
2.2使用new Gson序列化和反序列化原始类型的例子:
<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>
2.3使用new Gson序列化和反序列化一个对象
<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>
关于序列化与反序列化的对象的一些细节:
- 推荐使用私有属性。
- 没有必要使用注释表明某个字段将被用作序列化和反序列化,所有的字段都会被默认的包含进来。
- 如果一个字段被声明为transient,那么它将不会被用作序列化和烦序列化。
- 能正确处理null.
- 序列化的时候null的字段会被跳过。
- 反序列化时,失踪的条目,其对象对应的字段会被设置位null。
- synthetic修饰的字段,在序列化和反序列的过程中会被忽略。
- 内部类中对应与外部类的字段,匿名类,本地类会被忽略。
2.4 嵌套类(nested classes)
Gson可以轻易的序列化静态嵌套类。
Gson也可以反序列化静态嵌套类。Gson不能自动反序列化纯内部类,因为他们的无参构造函数也需要包含对象的引用,而这个引用在反序列化的时候不可用。你可以使用两种方法解决这个问题:
- 声明内部类为static
- 提供一个内部类的实例构建器
比如说一下例子:
public class A {
public String a;
class B {
public String b;
public B() {
// No args constructor for B
}
}
}
在这个例子中,不能使用 {"b":"abc"}反序列化生成B的实例。把class B声明位静态是简单的解决方法,此为,你还可以给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();
}
}
这种方法虽然可行,但并不推荐。
2.5 数组的序列化与反序列化
Gson gson = new Gson();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 ints
2.6 集合的序列化与反序列化
<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>
很可怕的一点:注意这里是怎么定义集合类型的?不幸的是,在java中,我们无法绕过这一点。
2.7 序列化与反序列化泛型
当我们调用toJson(obj),Gson会调用obj.getClass()来获取需要序列化的字段。同样的,我们可以传入MyClass.class对象给fromJson(json,MyClass.class),当对象不是泛型的时候,一切都工作良好,可是,如果对象是泛型,由于java类型擦除机制,泛型的信息会丢失。下面有一个解释这点的例子:
<span style="font-family:SimSun;font-size:14px;">class Foo<T> {上面的代码无法过去Bar类型的值,所以会解析失败。因为Gson会调用list.getClass()获得类信息,但是这个方法返回了一个原始的值,Foo.class,也就是说我们无法知道类的类型是一个Foo<Bar>类型,而不是Foo类型。
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>
你可以解决这个问题,使用指定泛型的正确的参数化类型:
<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方法,从而获得一个完全的参数化类型。
2.8 序列化与反序列化任意类型的集合
有时候需要处理包含多种类型的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>
这个Event的定义是这样的:
<span style="font-family:SimSun;font-size:14px;">class Event {你可以序列化集合使用toJson(connect),这没有任何问题,可以的要期望的结果
private String name;
private String source;
private Event(String name, String source) {
this.name = name;
this.source = source;
}
}</span>
但是,如果是使用fomJson进行反序列化的话就不能进行,因为Gson不知道怎样把输入映射为类型。所以你有三个选择解决这个问题:
-
使用Gson的解析器API(一个低水平的流解析器或者Dom解析器JsonParser)来解析数组元素,然后对数组的每一个元素使用Gson.formJson()来获得Java对象。这是推荐的方式。这里有个例子,只贴出核心代码:
<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>
- 位Collection.class注册一个适配器类,用来观察每一个数组成员,并把他们映射为正确的类型。这种方法的缺点是它会搞砸Gson中其他集合类型的反序列化。
- 位MyCollectionMemberType注册一个适配器类型,并使用对Collection<MyCollectionMemberType>使用fromJson()方法。
Gson User Guilde内容较多,这里就只介绍它的常规使用,其他的内容会在后续的文章中继续探究。