最近在研究Retrofit中使用的Gson的时候,发现对Gson的一些深层次的概念和使用比较模糊,因此这里作一个知识点的概括整理。java
Gson(又称Google Gson)是Google公司发布的一个开放源代码的Java库,主要用途为序列化Java对象为JSON字符串,或反序列化JSON字符串成Java对象。而JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成,普遍应用于各类数据的交互中,尤为是服务器与客户端的交互。git
JsonElement
有下面这四种类型:提供一种像toString()和构造方法的很简单的机制,来实现Java 对象和Json之间的互相转换。github
容许已经存在的没法改变的对象,转换成Json,或者Json转换成已存在的对象。typescript
容许自定义对象的表现形式json
支持任意的复杂对象数组
可以生成可压缩和可读的Json的字符串输出。服务器
1 推荐把成员变量都声明称private的app
2 没有必要用注解(@Expose 注解)指明某个字段是否会被序列化或者反序列化,全部包含在当前类(包括父类)中的字段都应该默认被序列化或者反序列化ide
3 若是某个字段被 transient 这个Java关键词修饰,就不会被序列化或者反序列化性能
4 下面的实现方式可以正确的处理null
1)当序列化的时候,若是对象的某个字段为null,是不会输出到Json字符串中的。
2)当反序列化的时候,某个字段在Json字符串中找不到对应的值,就会被赋值为null
5 若是一个字段是 synthetic
的,他会被忽视,也便是不该该被序列化或者反序列化
6 内部类(或者anonymous class(匿名类),或者local class(局部类,能够理解为在方法内部声明的类))的某个字段和外部类的某个字段同样的话,就会被忽视,不会被序列化或者反序列化
该注解能指定该字段在JSON中对应的字段名称
public class Box { @SerializedName("w") private int width; @SerializedName("h") private int height; @SerializedName("d") private int depth; // Methods removed for brevity }
也就是说{"w":10,"h":20,"d":30}
这个JSON 字符串可以被解析到上面的width,height和depth字段中。
该注解可以指定该字段是否可以序列化或者反序列化,默认的是都支持(true)。
public class Account { @Expose(deserialize = false) private String accountNumber; @Expose private String iban; @Expose(serialize = false) private String owner; @Expose(serialize = false, deserialize = false) private String address; private String pin; }
须要注意的经过 builder.excludeFieldsWithoutExposeAnnotation()
方法是该注解生效。
final GsonBuilder builder = new GsonBuilder(); builder.excludeFieldsWithoutExposeAnnotation(); final Gson gson = builder.create();
Since表明“自从”,Until 表明”一直到”。它们都是针对该字段生效的版本。好比说@Since(1.2)
表明从版本1.2以后才生效,@Until(0.9)
表明着在0.9版本以前都是生效的。
public class SoccerPlayer { private String name; @Since(1.2) private int shirtNumber; @Until(0.9) private String country; private String teamName; // Methods removed for brevity }
也就是说咱们利用方法builder.setVersion(1.0)
定义版本1.0,以下:
final GsonBuilder builder = new GsonBuilder(); builder.setVersion(1.0); final Gson gson = builder.create(); final SoccerPlayer account = new SoccerPlayer(); account.setName("Albert Attard"); account.setShirtNumber(10); // Since version 1.2 account.setTeamName("Zejtun Corinthians"); account.setCountry("Malta"); // Until version 0.9 final String json = gson.toJson(account); System.out.printf("Serialised (version 1.0)%n %s%n", json);
因为shirtNumber
和country
做用版本分别是1.2以后,和0.9以前,因此在这里都不会获得序列化,因此输出结果是:
Serialised (version 1.0) {"name":"Albert Attard","teamName":"Zejtun Corinthians"}
英文Serialize和format都对应序列化,这是一个Java对象到JSON字符串的过程。
接着看一个例子,下面分别是java类和以及咱们指望的JSON数据:
public class Book { private String[] authors; private String isbn10; private String isbn13; private String title; //为了代码简洁,这里移除getter和setter方法等 }
{
"title": "Java Puzzlers: Traps, Pitfalls, and Corner Cases", "isbn-10": "032133678X", "isbn-13": "978-0321336781", "authors": [ "Joshua Bloch", "Neal Gafter" ] }
你确定能发现JSON数据中出现了isbn-10
和isbn-13
, 咱们怎么把字段数据isbn10
和isbn13
转化为JSON数据须要的isbn-10
和isbn-13
,Gson固然为咱们提供了对应的解决方案
采用上面提到的@SerializedName
注解。
public class Book { private String[] authors; @SerializedName("isbn-10") private String isbn10; @SerializedName("isbn-13") private String isbn13; private String title; //为了代码简洁,这里移除getter和setter方法等 }
利用JsonSerializer
类
public class BookSerialiser implements JsonSerializer { @Override public JsonElement serialize(final Book book, final Type typeOfSrc, final JsonSerializationContext context) { final JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("title", book.getTitle()); jsonObject.addProperty("isbn-10", book.getIsbn10()); jsonObject.addProperty("isbn-13", book.getIsbn13()); final JsonArray jsonAuthorsArray = new JsonArray(); for (final String author : book.getAuthors()) { final JsonPrimitive jsonAuthor = new JsonPrimitive(author); jsonAuthorsArray.add(jsonAuthor); } jsonObject.add("authors", jsonAuthorsArray); return jsonObject; } }
下面对序列化过程进行大体的分析:
JsonSerializer是一个接口,咱们须要提供本身的实现,来知足本身的序列化要求。
public interface JsonSerializer<T> { /** *Gson 会在解析指定类型T数据的时候触发当前回调方法进行序列化 * * @param T 须要转化为Json数据的类型,对应上面的Book * @return 返回T指定的类对应JsonElement */ public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context); }
final JsonObject jsonObject = new JsonObject();
jsonObject.addProperty... jsonObject.add...
下面是jsonObject中的添加方法:因此最后返回的仍是一个JsonElement 类型,这里对应的是jsonObject。完成了javaBean->JSON数据的转化。
一样须要配置,
// Configure GSON final GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Book.class, new BookSerialiser()); gsonBuilder.setPrettyPrinting(); final Gson gson = gsonBuilder.create(); final Book javaPuzzlers = new Book(); javaPuzzlers.setTitle("Java Puzzlers: Traps, Pitfalls, and Corner Cases"); javaPuzzlers.setIsbn10("032133678X"); javaPuzzlers.setIsbn13("978-0321336781"); javaPuzzlers.setAuthors(new String[] { "Joshua Bloch", "Neal Gafter" }); // Format to JSON final String json = gson.toJson(javaPuzzlers); System.out.println(json);
,这里对应的是gsonBuilder.registerTypeAdapter(Book.class, new BookSerialiser())
方法进行JsonSerializer的配置。在上面例子中,经过调用gsonBuilder.setPrettyPrinting();
方法还告诉了 Gson 对生成的 JSON 对象进行格式化
英文parse和deserialise对应反序列化,这是一个字符串转换成Java对象的过程。
咱们一样采用上面一小节的代码片断,只不过如今咱们须要作的是将:
{
"title": "Java Puzzlers: Traps, Pitfalls, and Corner Cases", "isbn-10": "032133678X", "isbn-13": "978-0321336781", "authors": [ "Joshua Bloch", "Neal Gafter" ] }
转化为对应的Book实体类,
利用@SerializedName
注解
也就是说咱们的实体类Book.java能够这么写:
public class Book { private String[] authors; @SerializedName("isbn-10") private String isbn10; @SerializedName(value = "isbn-13", alternate = {"isbn13","isbn.13"}) private String isbn13; private String title; //为了代码简洁,这里移除getter和setter方法等 }
能够看到这里咱们在
@SerializedName
注解使用了一个value
,alternate
字段,value
也就是默认的字段,对序列化和反序列化都有效,alternate
只有反序列化才有效果。也就是说通常服务器返回给咱们JSON数据的时候可能一样的一个图片,表示"image","img","icon"等,咱们利用@SerializedName
中的alternate
字段就能解决这个问题,所有转化为咱们实体类中的图片字段。
咱们在序列化的时候使用的是JsonSerialize
,这里对应使用JsonDeserializer
咱们将解析到的json数据传递给Book的setter方法便可。
public class BookDeserializer implements JsonDeserializer<Book> { @Override public Book deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context) throws JsonParseException { final JsonObject jsonObject = json.getAsJsonObject(); final JsonElement jsonTitle = jsonObject.get("title"); final String title = jsonTitle.getAsString(); final String isbn10 = jsonObject.get("isbn-10").getAsString(); final String isbn13 = jsonObject.get("isbn-13").getAsString(); final JsonArray jsonAuthorsArray = jsonObject.get("authors").getAsJsonArray(); final String[] authors = new String[jsonAuthorsArray.size()]; for (int i = 0; i < authors.length; i++) { final JsonElement jsonAuthor = jsonAuthorsArray.get(i); authors[i] = jsonAuthor.getAsString(); } final Book book = new Book(); book.setTitle(title); book.setIsbn10(isbn10); book.setIsbn13(isbn13); book.setAuthors(authors); return book; } }
和Gson序列化章节同样,咱们这里接着分析咱们是怎么将JSON数据解析(反序列化)为实体类的:
{}
大括号包围的,也就意味着这是一个Json对象。因此首先咱们经过final JsonObject jsonObject = json.getAsJsonObject();
将咱们的JsonElement转化为JsonObjectjsonObject.get("xxx").getAsString()
的形式获取相应String的值jsonObject.get("xx").getAsJsonArray();
获取相应的json数组,并遍历出其中的相应字段值关于从本地流中读取Json数据可使用 InputStreamReader
完成
// Configure Gson GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Book.class, new BookDeserializer()); Gson gson = gsonBuilder.create(); // The JSON data try(Reader reader = new InputStreamReader(Main.class.getResourceAsStream("/part1/sample.json"), "UTF-8")){ // Parse JSON to Java Book book = gson.fromJson(reader, Book.class); System.out.println(book); }
翻译原文,根据原文作出了较大改动。
1 SIMPLE GSON EXAMPLE
2 GSON DESERIALISER EXAMPLE
3 GSON ANNOTATIONS EXAMPLE
4 GSON SERIALISER EXAMPLE
5 GSON TYPEADAPTER EXAMPLE
6 GSON TYPEADAPTER EXAMPLE SERIALISE LARGE OBJECTS
另附: 你真的会用Gson吗?Gson使用指南(一)系列文章
更多及时技术资讯,欢迎关注个人微博 :Anthony
本篇文章是基于Gson官方使用指导(Gson User Guide)以及Gson解析的优秀外文(来自http://www.javacreed.com/ )作出的一个翻译和概括。
博客原连接:
Gson全解析(上)-Gson基础
Gson全解析(中)-TypeAdapter的使用
Gson全解析(下)-Gson性能分析
from: http://www.jianshu.com/p/fc5c9cdf3aab