目前主流的json解析類庫有jackson,fastjson,gson,gson的serialization deserialization解析功能無疑是最強大的,基本上完美支持複雜對象的json化和反json化,其餘兩個庫在轉換複雜對象時都容易出現問題。若是在不考慮效率的狀況下,我強烈推薦使用gson類庫。java
首先須要添加依賴git
//gradle dependencies { compile 'com.google.code.gson:gson:2.8.2' } //maven <dependencies> <!-- Gson: Java to Json conversion --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.2</version> <scope>compile</scope> </dependency> </dependencies>
接下來看一些代碼例子,gson設計的很是易用,基本上一看就懂。github
// 建立gson對象,gson對象是內部無狀態的,因此建立一個能夠屢次使用,能夠想象成一個轉換器 Gson gson = new Gson(); //轉換成json只用直接放入對象就行,gson在內部會提取對象的類型信息 gson.toJson(1); // ==> 1 gson.toJson("abcd"); // ==> "abcd" gson.toJson(new Long(10)); // ==> 10 int[] values = { 1 }; gson.toJson(values); // ==> [1] // 反json化,此時須要傳入類型參數,由於json中是沒有保存關於java類型的信息的 int one = gson.fromJson("1", int.class); Integer one = gson.fromJson("1", Integer.class); Long one = gson.fromJson("1", Long.class); String str = gson.fromJson("\"abc\"", String.class);
固然,gson也支持對對象類型的轉換json
class BagOfPrimitives { private int value1 = 1; private String value2 = "abc"; //使用transient標識的變量不會被json化 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"}
不過注意你不能json化一個具備循環引用的對象,會致使死循環(簡單來講就是a有一個變量爲b,b也有一個變量爲a,此時不管json化誰都會致使死循環)數組
1.徹底可使用private修飾變量類型,由於gson內部是使用反射來進行json化的,因此private也徹底能夠讀取的到
2.徹底沒有必要使用任何的annotations 來標註哪一個字段須要被包含(有不少其餘庫是使用annotations 來標記的),gson默認會序列化當前類中的全部字段(包括他的全部父類)
3.若是一個字段被標記爲transient,他不會被Json化
4.gson對值爲null的字段有很好的支持maven
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);
對集合類型是作了特殊支持的,輸出的效果基本和數組同樣,除了元素以外不會輸出其餘的字段例如 size之類的ide
Gson gson = new Gson(); Collection<Integer> ints = Arrays.asList(1,2,3,4,5); // Serialization String json = gson.toJson(ints); // ==> json is [1,2,3,4,5] // Deserialization //對於泛型類型,由於直接取得的class並不包括泛型類型,因此須要建立type再傳入 Type collectionType = new TypeToken<Collection<Integer>>(){}.getType(); Collection<Integer> ints2 = gson.fromJson(json, collectionType);
由於gson內部是使用getClass來獲取類型信息,返回的類型都不包括泛型參數類型,因此直接像以前使用的話,序列化和反序列化都會失敗
(其實不僅是gson,java的泛型自己就被吐槽好久了,各類毛病)gradle
class Foo<T> { T value; } Gson gson = new Gson(); Foo<Bar> foo = new Foo<Bar>(); gson.toJson(foo); //不能成功序列化 gson.fromJson(json, foo.getClass()); // 沒法反序列化
若是想要成功序列化帶有泛型類型的對象,須要使用Type對象ui
//注意這裏的TypeToken帶有{},實際上是一個匿名類,由於TypeToken的構造器是非Public的,不能直接構造,我也不太清楚爲何要這樣設計 Type fooType = new TypeToken<Foo<Bar>>() {}.getType(); gson.toJson(foo, fooType); gson.fromJson(json, fooType);
有時候你可能會在一個集合中放入不一樣的類型(雖然我我的強烈不推薦這樣寫,由於泛型的做用就是爲了省掉沒必要要的cast,你還放入不一樣類型,這不是自找麻煩嗎?)
可是若是你真的這樣寫了,gson仍是能夠幫你轉換this
Collection collection = new ArrayList(); collection.add("hello"); collection.add(5); collection.add(new Event("GREETINGS", "guest")); class Event { private String name; private String source; private Event(String name, String source) { this.name = name; this.source = source; } }
你徹底能夠像直接同樣直接序列化這個集合,沒有任何問題。
可是以前也說過,json沒有保存關於java對象類型的任何信息(做爲一個通用的數據交換格式他這樣作是正確的,不然這段json數據就只有gson才能解析了)。
以前咱們在反序列化的同時都要手動傳入類型參數,可是做爲一個混合集合,顯然沒有一個所謂的’類型參數’,因此直接反序列化是不可能了。
若是你想要反序列化這樣的json,有如下幾種選擇。
1.使用原始的json類庫手動解析
2.註冊一個collection 的adapter(咱們下一篇會講),自定義解析過程(仍是須要手動解析)
因此若是想要反序列化這樣的集合,不管怎麼樣都要手寫解析,沒什麼辦法,因此最好仍是不要在泛型集合裏放入不一樣的類型
除了默認的序列化和反序列化行爲,gson還容許自定義某些類的序列化和反序列化行爲。自定義行爲通常用於須要使json對象具備和原來類不一樣的表示形式,或者默認行爲會報錯的狀況。主要分爲三個類
Json Serializers: 自定義某種對象類型的序列化行爲
Json Deserializers: 自定義某種對象類型的反序列化行爲
Instance Creators: 自定義某種對象的建立行爲
此時咱們須要配置gsonbuilder,而後用gsonbuilder來建立gson對象,builder模式你們應該很熟悉了
代碼以下
GsonBuilder gsonBuilder= new GsonBuilder(); gson.registerTypeAdapter(MyType.class, new MySerializer()); gson.registerTypeAdapter(MyType.class, new MyDeserializer()); gson.registerTypeAdapter(MyType.class, new MyInstanceCreator()); Gson gson=gsonBuilder.create();
爲某類型註冊了自定義的序列化和反序列化行爲以後,在轉換的過程當中一旦遇到該類型的對象,就會調用你註冊的行爲來序列化。
這些的類的實現也很容易。
//自定義序列化,須要實現JsonSerializer接口 private class DateTimeSerializer implements JsonSerializer<DateTime> { public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.toString()); } } //自定義序列化,須要實現DateTimeDeserializer 接口 private class DateTimeDeserializer implements JsonDeserializer<DateTime> { public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return new DateTime(json.getAsJsonPrimitive().getAsString()); } } //自定義對象建立,須要實現InstanceCreator private class MoneyInstanceCreator implements InstanceCreator<Money> { public Money createInstance(Type type) { return new Money("1000000", CurrencyCode.USD); } }
在我我的使用gson的過程當中,我發現有些時候是不得不用自定義序列化和反序列化的,由於在使用默認的行爲的狀況下,對一些複雜對象常常出錯,具體緣由我也不知道爲何,不少時候都是出現了死循環,可能java一些類中自己就存在雙向引用吧,此外還有一些其餘的異常,主要緣由都是java一些類自己的繼承結構太深了。
咱們以序列化Image爲例(該類直接序列化會報錯)
這個代碼是我實際項目中使用的,將javafx的image對象序列化(固然對於圖像對象,最後還要使用壓縮流來減小體積)
public class GsonImage implements JsonSerializer<Image>,JsonDeserializer<Image> { @Override public Image deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { Gson gson=new Gson(); byte[] bs=gson.fromJson(json.getAsString(), byte[].class); BufferedImage image = null; try { //從字節數組建立圖片 image = ImageIO.read(new ByteArrayInputStream(bs)); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } Image image2=SwingFXUtils.toFXImage(image, null); return image2; } @Override public JsonElement serialize(Image image, Type typeOfSrc, JsonSerializationContext context) { Gson gson=new Gson(); ByteArrayOutputStream stream=new ByteArrayOutputStream(); BufferedImage bufferedImage=SwingFXUtils.fromFXImage(image, null); try { ImageIO.write(bufferedImage, "PNG", stream); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } byte[] imgBytes=stream.toByteArray(); //實際上序列化的是字節數組 String string=gson.toJson(imgBytes); return new JsonPrimitive(string); } }
除了三種自定義行爲以外,gsonbuilder還提供了一些配置
setPrettyPrinting() //設置輸出格式爲可讀性優先(默認是體積小優先) serializeNulls() //設置輸出null(默認null會被忽略) excludeFieldsWithModifiers()//設置不被包括在序列化中的修飾符(默認爲static //transient,可是你能夠覆蓋設置)
關於gson就介紹到這裏
能夠訪問gson的github幫助頁面來獲取更多信息
https://github.com/google/gson/blob/master/UserGuide.md