這篇文章主要講述了Gson的使用.包括從最基礎的基本類型的序列化,到對象,數組,集合,再到Gson註解,Gson Builder,再到格式化,自定義序列化與反序列化等內容.html
另外文章篇幅較長,建議挑選所需部分查看.全部例子都提供了完整源碼,在文章的後面.java
JSON全稱爲JavaScript Object Notation,一種輕量級的數據交換格式.git
相似於XML但比XML更小,更易解析.github
Gson是Google提供的可使Java對象與JSON互轉的類庫,可將Java對象轉換爲JSON,也可將JSON轉換成Java對象.json
目前最新的是2.8.6版本.api
dependencies { implementation 'com.google.code.gson:gson:2.8.6' }
<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.6</version> </dependency>
點擊下載.數組
int intJSON = 1; long longJSON = 1L; double doubleJSON = 1.0; float floatJSON = 1.0f; byte byteJSON = 1; char charJSON = 'G'; short shortJSON = 1; boolean boooleanJSON = true; System.out.println(gson.toJson(intJSON)); System.out.println(gson.toJson(longJSON)); System.out.println(gson.toJson(doubleJSON)); System.out.println(gson.toJson(floatJSON)); System.out.println(gson.toJson(byteJSON)); System.out.println(gson.toJson(charJSON)); System.out.println(gson.toJson(shortJSON)); System.out.println(gson.toJson(boooleanJSON)); System.out.println("----------------------------------------"); System.out.println(gson.fromJson("1",Integer.class)); System.out.println(gson.fromJson("1.0",Double.class)); System.out.println(gson.fromJson("1",Long.class)); System.out.println(gson.fromJson("true",Boolean.class)); System.out.println(gson.fromJson("B",Character.class));
就是對應輸出,沒啥好說的.yii
Gson gson = new Gson(); System.out.println(gson.toJson(new A())); String str = "{'field':'gggg','field2':33,'field3':'G','field4':'true'}"; A a = gson.fromJson(str,A.class); System.out.println(a.getField1()); System.out.println(a.getField2()); System.out.println(a.getField3()); System.out.println(a.getField4());
A類:maven
class A { private String field1 = "123"; private int field2 = 1; private char field3 = 'X'; private Boolean field4 = true; }
序列化出來的對象用{}表示.ide
反序列化時,注意格式,注意名字對應,用單引號引發來,還有char會自動變爲String類型,另外對於布爾類型能夠加單引號或不加單引號,均可以正常反序列化.
int [] a = new int []{1,2,3}; double [] b = new double []{1.0,2.0,3.0}; String [] c = new String []{"123","456"}; System.out.println(gson.toJson(a)); System.out.println(gson.toJson(b)); System.out.println(gson.toJson(c)); int [] aa = gson.fromJson("[6,7,8]",int [].class); double [] bb = gson.fromJson("[6.0,8.0,9.0]",double [].class); String [] cc = gson.fromJson("['123123','5464']",String [].class); System.out.println(Arrays.toString(aa)); System.out.println(Arrays.toString(bb)); System.out.println(Arrays.toString(cc));
對普通數組的話,{}變成了[]. 還有就是反序列化時,默認會在逗號後面添一個空格.
List<String> list = new ArrayList<>(); list.add("123"); list.add("456"); System.out.println(gson.toJson(list)); List<AAAA> list2 = new ArrayList<>(); list2.add(new AAAA()); list2.add(new AAAA("45345",8888,false)); System.out.println(gson.toJson(list2)); System.out.println("---------------------------------"); Type type = new TypeToken<List<String>>(){}.getType(); String strList = "['234234','45457']"; List<String> list3 = gson.fromJson(strList, type); System.out.println(list3); String strList2 = "[" + "{'field1':'9999','field2':666,'field3':'true'}" + "," + "{'field1':'sdlkfkl','field2':-234234,'field3':'false'}" + "]"; List<AAAA> list4 = gson.fromJson(strList2, new TypeToken<List<AAAA>>(){}.getType()); System.out.println(list4);
class AAAA { private String field1 = "123"; private int field2 = 5; private boolean field3 = true; }
序列化沒什麼問題,直接toJson便可,反序列化時,須要配合java.lang.reflect.Type使用,明確指出所要轉換的類型:
Type type = new TypeToken<List<String>>(){}.getType();
TypeToken<T>中T爲所須要的類型,再把這個Type對象傳遞給fromJson便可完成轉換.
List序列化出來的用[]表示.
Map<String,Integer> map = new HashMap<>(); map.put("123",88); map.put("2349",999); System.out.println(gson.toJson(map)); String str = "{'123':23423423,'9999':-234234}"; Map<String,Integer> map2 = gson.fromJson(str, new TypeToken<Map<String,Integer>>(){}.getType()); System.out.println(map2.get("123").toString()); System.out.println(map2.get("9999").toString());
Map一樣序列化時直接toJson,反序列化時使用java.lang.reflect.Type.Map序列化出來的用{}表示.
Set<String> set = new HashSet<>(); set.add("123123"); set.add("2349594"); set.add("-234()@#$@#"); System.out.println(gson.toJson(set)); String str = "['38483','@*#$(@#$)','SD<FGDF>G']"; Set<String> set2 = gson.fromJson(str, new TypeToken<Set<String>>(){}.getType()); set2.stream().forEach(System.out::println);
set序列化出來的用[]表示.
System.out.println(gson.toJson(new AAA())); String str = "{'field2':333,'field3':null}"; System.out.println(gson.fromJson(str, AAA.class));
class AAA { private String field1 = null; private Integer field2 = null; private Double field3 = 3.0; @Override public String toString() { return "field1:"+field1+",field2:"+field2+",field3:"+field3; } }
Gson會忽略空值,在序列化時看不到null對應的鍵值對,反序列化時,直接對應爲空.
一個對象裏面包含了List,Map,Set,null.
System.out.println(gson.toJson(new Test()));
class Test { private List<String> listField = new ArrayList<>(); private Map<String,Double> mapField = new HashMap<>(); private Set<Integer> setField = new HashSet<>(); private List<User> userListFiled = new ArrayList<>(); private Map<String,User> userMapField = new HashMap<>(); private Set<User> userSetField = new HashSet<>(); private Set<String> nullSetField = null; private Map<String,User> nullMapField = null; private List<User> nullListField = null; private Long longField = 23423423423L; private int intField = 234234; private Double doubleField = 234234.23423; private User userField = new User(); { listField.add("234234"); mapField.put("23432",-234.0); setField.add(-23423); userListFiled.add(new User("3459",-23423,new int []{4,5,5})); userListFiled.add(new User()); userMapField.put("()",new User()); userMapField.put("------", new User("345345",3434,new int []{4,44})); userSetField.add(new User()); userSetField.add(new User()); } } class User { private String name = "noName"; private int age = 0; private int [] nums = new int[]{2,3,4}; public User() { } public User(String name,int age,int [] nums) { this.name = name; this.age = age; this.nums = nums; } }
這個就不反序列化了,能夠看到對象,Map用{},List,Set用[].與上面的一致.
SerializedName註解有兩個參數,分別是value與alternate.SerializedName由註解名字能夠知道與序列化成的Json名字有關.
默認狀況下,json的鍵名與對象的字段名一致,@SerializedName能夠解決序列化/反序列化時json鍵名與對象字段名不一致的問題,使其將json能夠正確映射到對應的字段.
單獨使用一個參數時,即@SerializedName("xxx")或@SerializedName(value="xxx"),序列化時,對象字段會變爲@SerializedName中的值,反序列化時,若不是@SerializedName()中的值則不會反序列化:
public class SerializedNameValueTest { public static void main(String[] args) { Gson gson = new Gson(); System.out.println(gson.toJson(new SerializedNameValueTest().new User())); String str = "{'this is a name':'what????','this is an age':13,'email':'33333@222.com'}"; System.out.println(gson.fromJson(str,User.class)); String str2 = "{'name':'askldfklaslk','age':-222,'email':'234234@23423.com'}"; System.out.println(gson.fromJson(str2, User.class)); } class User { @SerializedName("this is a name") private String name = "123"; @SerializedName("this is an age") private int age = 0; private String email = "xxx@xxx.com"; private double[] nums = new double[] { 1.0, 2.0 }; @Override public String toString() { return "name:" + name + ",age:" + age + ",eamil:" + email + ",nums:" + Arrays.toString(nums); } } }
最後一個反序列化不成功,由於'name'不對應@SerializedName()中的'this is a name'.
同時使用二者能夠解決上面的問題,即name字段--->json中的'this is a name'--->name字段:
public class SerializedNameValueAndAlternateTest { public static void main(String[] args) { Gson gson = new Gson(); System.out.println(gson.toJson(new SerializedNameValueAndAlternateTest().new User())); String str = "{'this is a name':'what????','this is an age':13,'email':'33333@222.com'}"; System.out.println(gson.fromJson(str, User.class)); String str2 = "{'name':'askldfklaslk','age':-222,'email':'234234@23423.com'}"; System.out.println(gson.fromJson(str2, User.class)); } class User { @SerializedName(value = "this is a name",alternate = "name") private String name = "123"; @SerializedName(value = "this is an age",alternate = "age") private int age = 0; private String email = "xxx@xxx.com"; private double[] nums = new double[] { 1.0, 2.0 }; @Override public String toString() { return "name:" + name + ",age:" + age + ",eamil:" + email + ",nums:" + Arrays.toString(nums); } } }
alternate就是爲反序列化準備的,若找不到value中對應的值,則尋找alternate對應的值,找不到再設爲null.
若同時存在value與alternate:
String str3 = "{'name':'altername','this is a name':'value'}"; System.out.println(gson.fromJson(str3, User.class)); String str4 = "{'this is a name':'value','name':'altername'}"; System.out.println(gson.fromJson(str4, User.class));
則以"最晚"出現的值爲標準.
@Expose能夠忽略某個字段,有兩個參數:
默認狀況下都是true,分別表示序列化與反序列化.
System.out.println(gson.toJson(new User()));
class User { @Expose(serialize = false) private String name = "123"; @Expose(deserialize = false) private int age = 0; @Expose(serialize = false,deserialize = false) private String email = "xxx@xxx.com"; @Expose(serialize = true,deserialize = true) private double [] nums = new double [] {1.0,2.0}; }
name不容許序列化,age不容許反序列化,email不容許序列化與反序列化,nums既容許也容許反序列化.(此時效果等於沒加@Expose) 輸出:
咦?好像沒用的樣子?
由於Gson對象會默認忽略@Expose,想要@Expose生效須要使用Gson Builder:
GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.excludeFieldsWithoutExposeAnnotation(); Gson gson = gsonBuilder.create(); System.out.println(gson.toJson(new User())); String str = "{'name':'234','age':-3,'email':'23423','nums':[3,4,3]}"; System.out.println(gson.fromJson(str, User.class));
class User { @Expose(serialize = false) private String name = "123"; @Expose(deserialize = false) private int age = 0; @Expose(serialize = false,deserialize = false) private String email = "xxx@xxx.com"; @Expose(serialize = true,deserialize = true) private double [] nums = new double [] {1.0,2.0}; @Override public String toString() { return "name:"+name+",age:"+age+",eamil:"+email+",nums:"+Arrays.toString(nums); } }
不能反序列化age與email,輸出的是age與email的默認值.
前面的例子基本上都是經過
Gson gson = new Gson();
來直接實例化一個Gson來使用Gson的,使用Gson Builder能夠設置Gson的某些屬性,使用其中的create()返回一個Gson.
建立一個簡單的Gson,經過create()建立:
GsonBuilder gsonBuilder = new GsonBuilder(); Gson gson = gsonBuilder.create();
使用
gsonBuilder.setFieldNamingPolicy();
設置json中鍵的命名規則.6個值可選:
public class NamingRulesTest { public static void main(String[] args) { NamingRulesTest n = new NamingRulesTest(); GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.IDENTITY); System.out.println(gsonBuilder.create().toJson(n.new User())); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES); System.out.println(gsonBuilder.create().toJson(n.new User())); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DOTS); System.out.println(gsonBuilder.create().toJson(n.new User())); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES); System.out.println(gsonBuilder.create().toJson(n.new User())); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE); System.out.println(gsonBuilder.create().toJson(n.new User())); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES); System.out.println(gsonBuilder.create().toJson(n.new User())); } class User { @SuppressWarnings("unused") private String Name_Name_name = "123"; @SuppressWarnings("unused") private int _age_age_Age_age = 645; @SuppressWarnings("unused") private double numsNumsNums = 34.45; } }
注意,若某個字段有了@SerializedName,則這個字段遵循@SerializedName的策略.
重寫FieldNamingStrategy中的translateName(Field field),把自定義的FieldNamingStrategy傳遞給GsonBuilder的setFieldNamingStrategy().
好比想要前綴加上某人的名字:
public class CustomNamingRulesTest { public static void main(String[] args) { FieldNamingStrategy myNamingStrategy = new FieldNamingStrategy(){ @Override public String translateName(Field field) { return "kr"+field.getName(); } }; GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setFieldNamingStrategy(myNamingStrategy); Gson gson = gsonBuilder.create(); System.out.println(gson.toJson(new CustomNamingRulesTest().new User())); } class User { @SuppressWarnings("unused") private String name = "123"; @SuppressWarnings("unused") private int num = 5; } }
默認狀況下,Gson實例不容許序列化null,若是想要序列化null,藉助GsonBuilder的serializeNulls()方法:
public class NullTest { public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.serializeNulls(); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES); System.out.println(gsonBuilder.create().toJson(new NullTest().new User())); } class User { @SuppressWarnings("unused") private String thisIsANullField; @SuppressWarnings("unused") private Integer andThisIsANullFieldToo; } }
前面已經接觸到了@Expose這樣的排除策略,下面看看更增強大的配合GsonBuilder使用的排除策略.主要有四種:屬性名排除,類型排除,修飾符排除,@Expose排除.
public class ExclusionNameTest { public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.serializeNulls(); ExclusionStrategy exclusionName = new ExclusionStrategy(){ @Override public boolean shouldSkipField(FieldAttributes f) { return f.getName().endsWith("e"); } @Override public boolean shouldSkipClass(Class<?> arg0) { return false; } }; gsonBuilder.setExclusionStrategies(exclusionName); System.out.println(gsonBuilder.create().toJson(new ExclusionNameTest().new User())); } class User { private String name; private int num; } }
排除字段名以e結尾的字段.下面是重點:
public boolean shouldSkipField(FieldAttributes f) { return f.getName().endsWith("e"); }
重寫的shouldSkipField從名字能夠看出跳過某些字段,返回true表示跳過,即排除這個字段.上面的例子中若名字以e結尾則跳過,所以輸出:
public class ExclusionTypeTest { public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.serializeNulls(); ExclusionStrategy exclusionType = new ExclusionStrategy(){ @Override public boolean shouldSkipField(FieldAttributes arg0) { return false; } @Override public boolean shouldSkipClass(Class<?> cls) { return cls == String.class; } }; gsonBuilder.setExclusionStrategies(exclusionType); System.out.println(gsonBuilder.create().toJson(new ExclusionNameTest().new User())); } class User { @SuppressWarnings("unused") private String name; @SuppressWarnings("unused") private int num; } }
重寫的shouldSkipClass表示要跳過的類,這裏跳過了String,只剩下num.
@Override public boolean shouldSkipClass(Class<?> cls) { return cls == String.class; }
這個不用重寫方法了,直接使用GsonBuilder的excludeFieldsWithModifiers(),參數是java.lang.reflect.Modifier:
這個可選的比較多就不一一列舉了,只選了一個final的例子:
public class ExclusionModifierTest { public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.excludeFieldsWithModifiers(Modifier.FINAL); System.out.println(gsonBuilder.create().toJson(new User())); } } class User { @SuppressWarnings("unused") private final String name = "123"; @SuppressWarnings("unused") private static int num; }
這個準確來講是排除沒有被@Expose註解的字段:
public class ExclusionExposeTest { public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.excludeFieldsWithoutExposeAnnotation(); System.out.println(gsonBuilder.create().toJson(new ExclusionExposeTest().new User())); } class User { @SuppressWarnings("unused") private String name; @SuppressWarnings("unused") private int num; @Expose(serialize = true,deserialize = true) private int age; } }
這是有關於反序列化時JSON的容錯機制的問題,由於一般來講將一個對象經過Gson轉換成json沒什麼大問題,可是將json轉換爲對象的時候就...就難說了,由於不知道是否符合標準的json格式,所以Gson提供了必定的容錯機制,就是Lenient.
Lenient翻譯過來是"寬容的"的意思,能夠經過:
GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setLenient();
開啓.
Gson內部有一個JsonReader類,默認狀況下,JsonReader是嚴格的且僅接受符合RFC 4627標準的json(RFC 4627標準能夠看看這裏),設置爲lenient後能夠"容忍"如下幾種錯誤:
設置setLenient()後,Gson會盡量解析有錯誤的json,若實在無能爲力,會拋出MalformedJsonException異常.
下面是一個不嚴格的json的例子:
public class LenientTest { public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setLenient(); String str = "{'name'='234';'num'=6}"; System.out.println(gsonBuilder.create().fromJson(str,User.class)); } class User { private String name; private int num; @Override public String toString() { return "name:"+name+",num:"+num; } } }
下面是一個異常的例子:
String errorStr = "{'name'=????,,,,,,}"; System.out.println(gsonBuilder.create().fromJson(errorStr,User.class));
先看一個例子:
public class FloatTest { public static void main(String[] args) { Gson gson = new Gson(); System.out.println(gson.toJson(new FloatTest().new User())); } class User { @SuppressWarnings("unused") private float f = Float.POSITIVE_INFINITY; } }
會報錯:
它說Infinity在JSON標準是一個非法值.想要重寫這個行爲須要使用GsonBuilder.serializeSpecialFloatingPointValues().
由於JSON規範不容許NaN,-Infinity,Infinity,所以會報錯.下面使用GsonBuilder:
public class FloatTest { public static void main(String[] args) { // Gson gson = new Gson(); // System.out.println(gson.toJson(new FloatTest().new User())); GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.serializeSpecialFloatingPointValues(); System.out.println(gsonBuilder.create().toJson(new FloatTest().new User())); } class User { @SuppressWarnings("unused") private float f = Float.POSITIVE_INFINITY; } }
直接輸出Infinity:
double也相似:
public class DoubleTest { public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.serializeSpecialFloatingPointValues(); System.out.println(gsonBuilder.create().toJson(new DoubleTest().new User())); } class User { @SuppressWarnings("unused") private double ni = Double.NEGATIVE_INFINITY; @SuppressWarnings("unused") private double pi = Double.POSITIVE_INFINITY; @SuppressWarnings("unused") private double nan = Double.NaN; } }
經過@Since與@Until添加版本控制,控制某個版本在序列化與反序列化時忽略或忽略某個字段.
@Since表示從某個版本開始這個字段不忽略,@Until表示這個版本後將忽略該字段.
須要配合GsonBuilder的setVersion使用,設定版本號.
public class VersionTest { public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.serializeNulls(); System.out.println(gsonBuilder.setVersion(0.9).create().toJson(new VersionTest().new User())); System.out.println(gsonBuilder.setVersion(1.0).create().toJson(new VersionTest().new User())); System.out.println(gsonBuilder.setVersion(1.4).create().toJson(new VersionTest().new User())); System.out.println(gsonBuilder.setVersion(1.5).create().toJson(new VersionTest().new User())); } class User { @Since(1.0) private String name; @Until(1.4) private int num; } }
@Since的範圍包含了左區間端點,@Until的範圍不包含右區間端點.
可使用setDateForamt()來格式化日期輸出:
gsonBuilder.setDateFormat(int style); gsonBuilder.setDateFormat(String pattern); gsonBuilder.setDateFormat(int dateStyle,int timeStyle);
第一個函數的參數爲DateFormat中的常量值,第二個函數的參數是相似SimpleDateFormat中的String,第三個函數的參數與第一個相似,分開日期與時間設置.
再說如下setPrettyPrinting()這個函數,看名字就知道,美化打印的.會加上空格.
public class FormatTest { public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setPrettyPrinting(); System.out.println(gsonBuilder.setDateFormat(DateFormat.SHORT, DateFormat.SHORT).create().toJson(new FormatTest().new User())); System.out.println(gsonBuilder.setDateFormat(DateFormat.SHORT,DateFormat.LONG).create().toJson(new FormatTest().new User())); System.out.println(gsonBuilder.setDateFormat(DateFormat.MEDIUM, DateFormat.MEDIUM).create().toJson(new FormatTest().new User())); System.out.println(gsonBuilder.setDateFormat(DateFormat.LONG, DateFormat.MEDIUM).create().toJson(new FormatTest().new User())); System.out.println(gsonBuilder.setDateFormat(DateFormat.FULL, DateFormat.FULL).create().toJson(new FormatTest().new User())); System.out.println(gsonBuilder.setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(new FormatTest().new User())); } class User { @SuppressWarnings("unused") private Date date = new Date(); } }
枚舉其實也與普通的字段相似,序列化與反序列化正常操做.
public class EnumTest { public static void main(String[] args) { Gson gson = new Gson(); System.out.println(gson.toJson(new EnumTest().new User())); String str = "{\"season\":\"SUMMER\",\"name\":\"8888\"}"; System.out.println(gson.fromJson(str,User.class)); } enum Season { SPRING, SUMMER, AUTUMN, WINTER } class User { private Season season = Season.SPRING; private String name = "123"; @Override public String toString() { return "season:"+season.toString()+",name:"+name; } } }
主要配合@SerializedName()使用,例如對於月份,可使用1,2,3來表示:
public class EnumTest { public static void main(String[] args) { Gson gson = new Gson(); System.out.println(gson.toJson(new EnumTest().new User())); String str = "{\"season\":\"SUMMER\",\"name\":\"8888\",\"month\":\"2\"}"; System.out.println(gson.fromJson(str,User.class)); } enum Season { SPRING, SUMMER, AUTUMN, WINTER } class User { private Season season = Season.SPRING; private String name = "123"; private Month month = Month.January; @Override public String toString() { return "season:"+season.toString()+",name:"+name+",month:"+month.toString(); } } enum Month { @SerializedName("1") January, @SerializedName("2") February, @SerializedName("3") March, @SerializedName("4") April, @SerializedName("5") May, @SerializedName("6") June, @SerializedName("7") July, @SerializedName("8") August, @SerializedName("9") September, @SerializedName("10") October, @SerializedName("11") November, @SerializedName("12") December } }
這裏主要說一下反序列化泛型.由於序列化泛型...直接toJson()就行了. 想一想這樣的情景:有一個待解析的Json String,類型爲List<T>,所以想有一個這樣的方法:
public <T> List<T> fromJSON(String json,Class<T> cls);
好了,怎麼寫呢,以前用的是TypeToken()實現反序列化:
List<Integer> integerList = new ArrayList<>(); integerList.add(3); integerList.add(-999); gson.toJson(integerList, new TypeToken<List<Integer>>() {}.getType());
答案就是使用ParameterizedType:重寫裏面的getActualTypeArguments(),getOwnerTpye()與getRawType():
public class GenericsTest { public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setPrettyPrinting(); Gson gson = gsonBuilder.create(); List<Integer> integerList = new ArrayList<>(); integerList.add(3); integerList.add(-999); gson.toJson(integerList, new TypeToken<List<Integer>>() {}.getType()); List<String> stringList = new ArrayList<>(); stringList.add("12321"); stringList.add("(@)#$@#"); String t1 = gson.toJson(integerList); String t2 = gson.toJson(stringList); new GenericsTest().fromJSON(t1, Integer.class).stream().forEach(System.out::println); new GenericsTest().fromJSON(t2, String.class).stream().forEach(System.out::println); } public <T> List<T> fromJSON(String json,Class<T> cls) { return new Gson().fromJson(json,new ParameterizedTypeImpl(cls)); } class ParameterizedTypeImpl implements ParameterizedType { private Class cls; public ParameterizedTypeImpl(Class cls) { this.cls = cls; } @Override public Type[] getActualTypeArguments() { return new Type[]{cls}; } @Override public Type getRawType() { return List.class; } @Override public Type getOwnerType() { return null; } } }
@Override public Type[] getActualTypeArguments() { return new Type[]{cls}; }
返回實際參數類型數組,在這裏是String.class與Integer.class.
@Override public Type getRawType() { return List.class; }
返回聲明這個類型的類或接口,在這裏是List.class.
@Override public Type getOwnerType() { return null; }
返回其成員之一的類型,就是說若是徹底限定類名爲A.B,則返回A,在這裏沒有A,所以爲null.
定義好實現ParameterizedTpye接口的類後,把它傳遞給fromJson()做爲第二參數,構造方法的參數爲List<T>中的T.class.
自定義序列化通常用於自定義簡化json. 好比有一個User類:
class User { private String name = "123"; private String email = "xxx@xxx.com"; private int [] nums = new int [] {1,2,3}; }
想要不序列化name,可使用@Expose(serialize = false),可是想要部分序列化nums,好比只是須要第一個nums[0],上面的@Expose,@SerializedName等註解都用不上,這時須要使用JsonSerializer自定義序列化,重寫其中的:
public JsonElement serialize(T t,Type type,JsonSerializationContext context)
能夠返回一個JsonObject,這裏的JsonObject能夠自定義添加屬性(即鍵值對).
須要配合GsonBuilder使用,建立了本身的JsonSerializer<T>後,把它傳遞給GsonBuilder的registerTypeAdapter():
public class SerializeCustomTest { public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); JsonSerializer<User> serializer = new JsonSerializer<SerializeCustomTest.User>() { @Override public JsonElement serialize(User u,Type type,JsonSerializationContext context) { JsonObject object = new JsonObject(); object.addProperty("name",u.getName()); object.addProperty("email",u.getEmail()); object.addProperty("nums",u.getNums()[0]); return object; } }; gsonBuilder.registerTypeAdapter(User.class,serializer); System.out.println(gsonBuilder.create().toJson(new SerializeCustomTest().new User())); } class User { private String name = "123"; private String email = "xxx@xxx.com"; private int [] nums = new int [] {1,2,3}; public int [] getNums() { return nums; } public String getName() { return name; } public String getEmail() { return email; } } }
自定義反序列化主要就是針對有多餘鍵值對的json,好比User只須要name字段,可是傳來的json包含了諸如age這樣的鍵,所以只需挑選所需的進行反序列化.與序列化相似,首先定義本身的JsonDeserializer<T>,重寫其中的:
public T deserialize(JsonElement,Type,JsonDeserializationContext);
返回一個自定義的反序列化的對象.最後在GsonBuilder中registerTypeAdapter()便可.
public class DeserializedCustomTest { public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); JsonDeserializer<User> deserializer = new JsonDeserializer<DeserializedCustomTest.User>() { @Override public User deserialize(JsonElement json,Type type,JsonDeserializationContext context) { JsonObject object = json.getAsJsonObject(); User user = new DeserializedCustomTest().new User(object.get("name").getAsString()); return user; } }; gsonBuilder.registerTypeAdapter(User.class, deserializer); String str = "{\"aaa\":\"bbbb\",\"name\":\"this is a name\",\"age\":\"444\"}"; System.out.println(gsonBuilder.create().fromJson(str,User.class)); } class User { private String name; private int age; public User(String name) { this.name = name; } @Override public String toString() { return "name:"+name+",age:"+age; } } }
能夠設置反序列化時的默認值,經過構造方法實現.好比json中沒有所須要的字段的值,默認狀況下爲null,若是想要不爲null,能夠設定默認值,對於對象能夠設定構造方法.
經過實現InstanceCreator<T>來實現,重寫其中的createInstance方法,再配合GsonBuilder的registerTypeAdapter().
public class InstanceCustomTest { public static void main(String[] args) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter( AA.class, new InstanceCustomTest().new AAInstance( new InstanceCustomTest().new BB("123","456") ) ); String str = "{\"name\":\"123123\"}"; System.out.println(gsonBuilder.create().fromJson(str, AA.class)); } class AAInstance implements InstanceCreator<AA> { private BB bb; public AAInstance(BB bb) { this.bb = bb; } @Override public AA createInstance(Type type) { return new AA(bb); } } class AA { private String name = "AA"; private BB bb; public AA(BB bb) { this.bb = bb; } @Override public String toString() { return "name:"+name+",bb:"+bb.toString(); } } class BB { private String field1; private String field2; public BB(String field1,String field2) { this.field1 = field1; this.field2 = field2; } @Override public String toString() { return "field1:"+field1+",field2:"+field2; } } }
json沒有爲BB類設定值,採用默認值.
這個是自定義序列化/反序列化的註解,能夠簡化JsonSerializer與JsonDeserializer.另外不用配合GsonBuilder使用,直接使用new Gson().toJson()/fromJson()便可,比直接使用JsonSerializer與JsonDeserializer要簡單.
首先使一個類實現JsonSerializer<T>接口,接着把這個類做爲要註解的字段的@JsonAdapter的參數:
class Serializer implements JsonSerializer<User> class ContainUser { private String userId = "x"; @JsonAdapter(Serializer.class) private User user = new User(); }
public class JsonAdapterSerializeTest { public static void main(String[] args) { Gson gson = new Gson(); System.out.println(gson.toJson(new JsonAdapterSerializeTest().new ContainUser())); } class Serializer implements JsonSerializer<User> { @Override public JsonElement serialize(User u,Type type,JsonSerializationContext context) { JsonObject object = new JsonObject(); object.addProperty("name",u.getName()); object.addProperty("email",u.getEmail()); object.addProperty("nums",u.getNums()[0]); return object; } } class ContainUser { private String userId = "x"; @JsonAdapter(Serializer.class) private User user = new User(); } class User { private String name = "123"; private String email = "xxx@xxx.com"; private int [] nums = new int [] {1,2,3}; public int [] getNums() { return nums; } public String getName() { return name; } public String getEmail() { return email; } } }
反序列化也相似.
public class JsonAdapterDeserializeTest { public static void main(String[] args) { Gson gson = new Gson(); String str = "{\"aaaa\":\"bbbb\",\"name\":\"this is a name\",\"age\":\"444\"}"; System.out.println(gson.fromJson(str,User.class)); } class Deserialize implements JsonDeserializer<User> { @Override public User deserialize(JsonElement json,Type type,JsonDeserializationContext context) { JsonObject object = json.getAsJsonObject(); User user = new JsonAdapterDeserializeTest().new User(object.get("name").getAsString()); return user; } } @JsonAdapter(Deserialize.class) class User { private String name = "123"; public User() { } public User(String name) { this.name = name; } @Override public String toString() { return "name:"+name; } } }
實現JsonDeserializer<T>,重寫deserialize(),在所需的類上添加註解.
注意@JsonAdapter註解只能添加在類上.
全部例子的完整源碼.
1.Gson Tutorial Series by Future Studio
2.gson徹底教程
3.gson教程
4.gson用戶指南
6.gson