JSON 是一種文本形式的數據交換格式,它比XML更輕量、比二進制容易閱讀和編寫,調式也更加方便;解析和生成的方式不少,Java中最經常使用的類庫有:JSON-Java、Gson、Jackson、FastJson等html
1、Gson的基本用法json
Gson提供了fromJson() 和toJson() 兩個直接用於解析和生成的方法,前者實現反序列化,後者實現了序列化;同時每一個方法都提供了重載方法api
(1)基本數據類型的解析數組
Gson gson = new Gson(); int i = gson.fromJson("100", int.class); //100 double d = gson.fromJson("\"99.99\"", double.class); //99.99 boolean b = gson.fromJson("true", boolean.class); // true String str = gson.fromJson("String", String.class); // String
(2)基本數據類型的生成 ui
Gson gson = new Gson(); String jsonNumber = gson.toJson(100); // 100 String jsonBoolean = gson.toJson(false); // false String jsonString = gson.toJson("String"); //"String"
(3)POJO類的生成與解析google
public class User { //省略其它 public String name; public int age; public String emailAddress; }
生成JSON: url
Gson gson = new Gson(); User user = new User("張三",24); String jsonObject = gson.toJson(user); // {"name":"張三kidou","age":24}
解析JSON: spa
Gson gson = new Gson(); String jsonString = "{\"name\":\"張三\",\"age\":24}"; User user = gson.fromJson(jsonString, User.class);
2、屬性重命名 @SerializedName 註解的使用.net
從上面POJO的生成與解析能夠看出json的字段和值是的名稱和類型是一一對應的,但也有必定容錯機制(如第一個例子第3行將字符串的99.99轉成double型),但有時候也會出現一些不和諧的狀況,如:設計
指望的json格式:{"name":"張三","age":24,"emailAddress":"zhangsan@ceshi.com"}
實際:{"name":"張三","age":24,"email_address":"zhangsan@ceshi.com"}
Gson在序列化和反序列化時須要使用反射,通常各種庫都將註解放到annotations包下,打開源碼在com.google.gson包下有一個annotations,裏面有一個SerializedName的註解類。對於json中email_address這個屬性對應POJO的屬性則變成:
@SerializedName("email_address") public String emailAddress;
爲POJO字段提供備選屬性名:SerializedName註解提供了兩個屬性,上面用到了其中一個,別外還有一個屬性alternate,接收一個String數組
注:alternate須要2.4版本
@SerializedName(value = "emailAddress", alternate = {"email", "email_address"}) public String emailAddress; //當三個屬性(email_address、email、emailAddress)都中出現任意一個時都可以獲得正確的結果 //當多種狀況同時出時,以最後一個出現的值爲準。 Gson gson = new Gson(); String json = "{\"name\":\"張三kidou\",\"age\":24,\"emailAddress\":\"zhangsan@ceshi.com\",\"email\":\"zhangsan_2@ceshi.com\",\"email_address\":\"zhangsan_3@ceshi.com\"}"; User user = gson.fromJson(json, User.class); System.out.println(user.emailAddress); // zhangsan_3@example.com
3、Gson中使用泛型
例如:JSON字符串數組:["Android","Java","PHP"]
當要經過Gson解析這個json時,通常有兩種方式:使用數組,使用List;而List對於增刪都是比較方便的,因此實際使用是仍是List比較多
數組比較簡單:
Gson gson = new Gson(); String jsonArray = "[\"Android\",\"Java\",\"PHP\"]"; String[] strings = gson.fromJson(jsonArray, String[].class);
對於List將上面的代碼中的 String[].class 直接改成 List<String>.class 是不行的,對於Java來講List<String> 和List<User> 這倆個的字節碼文件只一個那就是List.class,這是Java泛型使用時要注意的問題 泛型擦除
爲了解決的上面的問題,Gson提供了TypeToken來實現對泛型的支持,因此將以上的數據解析爲List<String>時須要這樣寫
Gson gson = new Gson(); String jsonArray = "[\"Android\",\"Java\",\"PHP\"]"; String[] strings = gson.fromJson(jsonArray, String[].class); List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType()); //TypeToken的構造方法是protected修飾的,因此上面纔會寫成new TypeToken<List<String>>() {}.getType() 而不是 new TypeToken<List<String>>().getType()
泛型解析對接口POJO的設計影響
泛型的引入能夠減小無關的代碼:
{"code":"0","message":"success","data":{}}
{"code":"0","message":"success","data":[]}
咱們真正須要的data所包含的數據,而code只使用一次,message則幾乎不用,若是Gson不支持泛型或不知道Gson支持泛型的同窗必定會這麼定義POJO
public class UserResponse { public int code; public String message; public User data; }
當其它接口的時候又從新定義一個XXResponse將data的類型改爲XX,很明顯code,和message被重複定義了屢次,經過泛型能夠將code和message字段抽取到一個Result的類中,這樣只須要編寫data字段所對應的POJO便可:
public class Result<T> { public int code; public String message; public T data; } //對於data字段是User時則能夠寫爲 Result<User> ,當是個列表的時候爲 Result<List<User>>
4、Gson的流式反序列化
(1)自動方式
Gson提供了fromJson()和toJson() 兩個直接用於解析和生成的方法,前者實現反序列化,後者實現了序列化。同時每一個方法都提供了重載方法
Gson.toJson(Object);
Gson.fromJson(Reader,Class);
Gson.fromJson(String,Class);
Gson.fromJson(Reader,Type);
Gson.fromJson(String,Type);
(2)手動方式:手動的方式就是使用stream包下的JsonReader類來手動實現反序列化,和Android中使用pull解析XML是比較相似的
String json = "{\"name\":\"張三\",\"age\":\"24\"}"; User user = new User(); JsonReader reader = new JsonReader(new StringReader(json)); reader.beginObject(); while (reader.hasNext()) { String s = reader.nextName(); switch (s) { case "name": user.name = reader.nextString(); break; case "age": user.age = reader.nextInt(); //自動轉換 break; case "email": user.email = reader.nextString(); break; } } reader.endObject(); // throws IOException System.out.println(user.name); //張三 System.out.println(user.age); // 24 System.out.println(user.email); //zhangsan@ceshi.com
自動方式最終都是經過JsonReader來實現的,若是第一個參數是String類型,那麼Gson會建立一個StringReader轉換成流操做
5、Gson的流式序列化
(1)自動方式
Gson.toJson方法列表
//PrintStream(System.out) 、StringBuilder、StringBuffer和*Writer都實現了Appendable接口。
Gson gson = new Gson(); User user = new User("張三",24,"zhangsan@ceshi.com"); gson.toJson(user,System.out);
(2)手動方式
JsonWriter writer = new JsonWriter(new OutputStreamWriter(System.out)); writer.beginObject() // throws IOException .name("name").value("張三") .name("age").value(24) .name("email").nullValue() //演示null .endObject(); // throws IOException writer.flush(); // throws IOException //{"name":"張三","age":24,"email":null} //除了beginObject、endObject還有beginArray和endArray,二者能夠相互嵌套,注意配對便可。beginArray後不能夠調用name方法,一樣beginObject後在調用value以前必需要調用name方法。
6、 使用GsonBuilder導出null值、格式化輸出、日期時間
通常狀況下Gson類提供的 API已經能知足大部分的使用場景,但有時須要更多特殊、強大的功能時,這時候就引入一個新的類 GsonBuilder。
GsonBuilder從名上也能知道是用於構建Gson實例的一個類,要想改變Gson默認的設置必須使用該類配置Gson
GsonBuilder用法:
//各類配置 //生成配置好的Gson Gson gson = new GsonBuilder().create();
(1)Gson在默認狀況下是不動導出值null的鍵的,如:
public class User { public String name; public int age; //省略 public String email; } Gson gson = new Gson(); User user = new User(張三",24); System.out.println(gson.toJson(user)); //{"name":"張三","age":24} //email字段是沒有在json中出現的,當在調試時須要導出完整的json串時或API接中要求沒有值必須用Null時,就會比較有用。
使用方法:
Gson gson = new GsonBuilder().serializeNulls() .create(); User user = new User("張三", 24); System.out.println(gson.toJson(user)); //{"name":"張三","age":24,"email":null}
格式化輸出、日期時間及其它:
Gson gson = new GsonBuilder() //序列化null .serializeNulls() // 設置日期時間格式,另有2個重載方法 // 在序列化和反序化時均生效 .setDateFormat("yyyy-MM-dd") // 禁此序列化內部類 .disableInnerClassSerialization() //生成不可執行的Json(多了 )]}' 這4個字符) .generateNonExecutableJson() //禁止轉義html標籤 .disableHtmlEscaping() //格式化輸出 .setPrettyPrinting() .create(); //:內部類(Inner Class)和嵌套類(Nested Class)的區別