Gson使用總結
Gson.toJson(Object); Gson.fromJson(Reader,Class); Gson.fromJson(String,Class); Gson.fromJson(Reader,Type); Gson.fromJson(String,Type); 複製程式碼
2.基本資料型別解析
Gson可以結合泛型使用,但用到泛型時,需指定type
,如new TypeToken<List<String>>(){}.getType()
;TypeToken
的構造方法是protected的,所有這麼寫new TypeToken<List<String>>(){}
Gson gson = new Gson();
反序列化:
int i = gson.fromJson("1",Integer.class); boolean b = gson.fromJson("\"true\"",Boolean.class); double d = gson.fromJson("1.1",Double.class); double d1 = gson.fromJson("\"1.2\"",Double.class); String str = gson.fromJson("TomCruise",String.class); List<String>stringList = gson.fromJson("[\"aa\",\"bb\"]",new TypeToken<List<String>>(){}.getType()); 複製程式碼
序列化:
String jsonInt = gson.toJson(2); String jsonBoolean = gson.toJson(false);// false String jsonString = gson.toJson("String"); //"String" List<String>list = new ArrayList<>(); list.add("a"); list.add("b"); String jsonList = gson.toJson(list); 複製程式碼
3.POJO類解析
POJO類:User
@JsonAdapter(UserTypeAdapter.class) public final class User { @Expose @Since(4) private String name; @Expose @Until(4) private int age; @Expose private Date date; @Expose private List<User>children; private User parent; //@SerializedName(value = "email_address",alternate = {"emailAddress","email"}) private String emailAddress; public User(String name, int age){ this.name = name; this.age = age; } ... ... } 複製程式碼
Gson自動化:
Gson gson = new Gson(); String json = "{\"name\":\"John\",\"age\":22,\"email_address\":\"[email protected]\"}"; User userF = gson.fromJson(json,User.class);//反序列化 User userT = new User("Tom",10); userT.setAddress("xxx"); String jsonUser = gson.toJson(userT);//序列化 複製程式碼
注:字串中應注意使用轉義字元,如\"name\"
欄位重新命名:@SerializedName
Java中一般採用駝峰命名,如emailAddress
,但後臺有時命名方式不同,如php形式的email_address
,此時@SerializedName
註解就能起大作用。
@SerializedName
可以更改欄位名,還能提供備用名屬性:alternate
,使用如下:
@SerializedName(value = "email_address",alternate = {"emailAddress","email"}) 複製程式碼
當上面的三個屬性(email_address、email、emailAddress)中出現任意一個時都能進行解析。
注:當多種情況同時出時,以最後一個出現的值為準。
4.泛型使用
Gson可以結合泛型使用,但用到泛型時,需指定type
,如new TypeToken<List<String>>(){}.getType()
;TypeToken
的構造方法是protected的,所有這麼寫new TypeToken<List<String>>(){}
; 無論使用List<User>
還是List<String>
,最終都是List.class
(泛型擦除
)
引入泛型可以很大程度上方便介面的設計,如後臺的返回資料格式常見兩種:
{"code":"0","message":"success","data":{}}
和{"code":"0","message":"success","data":[]
data的型別一種是物件,一種是資料,若無泛型的支援,則需定義兩個httpResponse類,引入泛型,則只需定義一個泛型類,不用去寫無謂的程式碼,能更專注於邏輯功能。
public final class HttpResult<T> { private int code; private boolean success; private T data; ... ... } 複製程式碼
使用時:
Gson gson = new Gson(); Type objType = new TypeToken<HttpResult<User>>(){}.getType(); Type listType = new TypeToken<HttpResult<List<User>>>(){}.getType(); HttpResult<User> objUser = gson.fromJson("{\"code\":200,\"data\":{\"age\":70,\"name\":\"Cap\"},\"success\":true}",objType); HttpResult<List<User>> listUser = gson.fromJson("{\"code\":200,\"data\":[{\"age\":70,\"name\":\"Cap\"}],\"success\":true}",listType); gson.toJson(objUser); gson.toJson(listUser); 複製程式碼
5、Null、日期格式化等Gson配置
Gson gson = new GsonBuilder() //格式化輸出 .setPrettyPrinting() //序列化null .serializeNulls() // 設定日期時間格式,另有2個過載方法 // 在序列化和反序化時均生效 .setDateFormat("yyyy-MM-dd") // 禁此序列化內部類 .disableInnerClassSerialization() //生成不可執行的Json(多了 )]}' 這4個字元) .generateNonExecutableJson() //禁止轉義html標籤 .disableHtmlEscaping() .create(); User user = new User("John",30); user.setDate(new Date()); //日期格式化 Log.i("format",gson.toJson(user)); 複製程式碼
二、手動流式序列化和流式反序列化
利用JsonReader
和JsonWriter
手動讀取
JsonReader
讀取:
try { JsonReader jsonReader = new JsonReader(new StringReader("[{\"name\":\"Cap\",\"age\":70, \"address\":\"[email protected]\"}" + ",{\"name\":\"Thor\",\"age\":1000, \"address\":\"[email protected]\"}]")); jsonReader.beginArray(); while (jsonReader.hasNext()){ jsonReader.beginObject(); Log.d("JsonReaderArray",jsonReader.nextName()+":"+jsonReader.nextString()); Log.d("JsonReaderArray",jsonReader.nextName()+":"+jsonReader.nextInt()); Log.d("JsonReaderArray",jsonReader.nextName()+":"+jsonReader.nextString()); jsonReader.endObject(); } jsonReader.endArray(); }catch (Exception e){ e.printStackTrace(); } 複製程式碼
JsonWriter
讀取:
try { StringWriter writer = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(writer);jsonWriter.beginArray(); jsonWriter.beginObject(); jsonWriter.name("name") .value("Stark") .name("age") .value(50) .name("email") .value("[email protected]"); jsonWriter.endObject(); jsonWriter.beginObject(); jsonWriter.name("name") .value("BlackWidow") .name("age") .value(40) .name("email") .value("[email protected]"); jsonWriter.endObject(); jsonWriter.endArray(); jsonWriter.flush(); Log.i("JsonWriter","writer:"+writer.toString()); }catch (Exception e){ e.printStackTrace(); } 複製程式碼
注: beginObject和endObject配套使用,beginArray和endArray配套使用
三、過濾忽略欄位
需要使用new GsonBuilder()
配置
生成Gson
物件。對於Gson gson = new Gson()
直接生成的Gson
物件不起
作用。
1.@Expose註解
有兩個屬性值deserialize
預設為true,serialize
預設為true。定義在欄位上,表明是否在序列化或反序列化過程中暴露出來。
注:是不匯出的不加
@Expose @Expose(deserialize = true,serialize = true) //序列化和反序列化都都生效,等價於上一條 @Expose(deserialize = true,serialize = false) //反序列化時生效 @Expose(deserialize = false,serialize = true) //序列化時生效 @Expose(deserialize = false,serialize = false) // 和不寫註解一樣 複製程式碼
User配置如上文 POJO類:User 所示;
Gson gson = new GsonBuilder() .excludeFieldsWithoutExposeAnnotation()//Expose生效 //.serializeNulls() //.setPrettyPrinting() .create(); User user = new User("Tom",50); User child = new User("Kid",6); User parent = new User("parent",80); List<User> children = new ArrayList<>(); children.add(child); user.setChildren(children); user.setParent(parent); Log.d("expose","User:"+gson.toJson(user)); Log.i("expose","User:"+gson.fromJson("{\"age\":50,\"children\":[{\"age\":6,\"name\":\"Kid\"}],\"name\":\"Tom\",\"parent\":{\"age\":80,\"name\":\"parent\"}}" ,User.class)); 複製程式碼
2.版本號(@Since和@Until)
使用方法:當前版本(GsonBuilder中設定的版本) 大於等於Since的值時該欄位匯出,小於Until的值時該該欄位匯出。
User配置如上文 POJO類:User 所示;
Gson gson = new GsonBuilder() .setVersion(4) //設定版本號 .create(); User user = new User("Tom",50); User child = new User("Kid",6); User parent = new User("parent",80); List<User> children = new ArrayList<>(); children.add(child); user.setChildren(children); user.setParent(parent); Log.d("version","User:"+gson.toJson(user)); Log.i("version","User:"+gson.fromJson("{\"age\":50,\"children\":[{\"age\":6,\"name\":\"Kid\"}],\"name\":\"Tom\",\"parent\":{\"age\":80,\"name\":\"parent\"}}" ,User.class)); 複製程式碼
3.許可權修飾符
即public
static
final
private
protected
這些修飾符
使用方法:
class ModifierSample { final String finalField = "final"; static String staticField = "static"; public String publicField = "public"; protected String protectedField = "protected"; String defaultField = "default"; private String privateField = "private"; } 複製程式碼
ModifierSample modifierSample = new ModifierSample(); Gson gson = new GsonBuilder() .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PRIVATE) .create(); System.out.println(gson.toJson(modifierSample)); // 結果:{"publicField":"public","protectedField":"protected","defaultField":"default"} 複製程式碼
4.自定義過濾策略(最靈活方便)
基於GsonBuilder
的addSerializationExclusionStrategy
和addDeserializationExclusionStrategy
,使用如下:
Gson gson = new GsonBuilder() .addSerializationExclusionStrategy(new ExclusionStrategy() { //基於欄位排除 @Override public boolean shouldSkipField(FieldAttributes f) { //Expose expose = f.getAnnotation(Expose.class); //return expose!=null && !expose.serialize(); return false; } //基於類排除 @Override public boolean shouldSkipClass(Class<?> clazz) { return clazz == int.class||clazz== Integer.class; } }).create(); 複製程式碼
四、POJO與JSON欄位名的對映規則
GsonBuilder
提供了FieldNamingStrategy
介面和setFieldNamingPolicy
和setFieldNamingStrategy
兩個方法,以及GSON的@SerializedName註解。
1.@SerializedName註解
注:@SerializedName註解擁有最高優先順序 ,在加有@SerializedName註解的欄位上FieldNamingStrategy不生效!
@SerializedName
可以更改欄位名,還能提供備用名屬性:alternate
,使用如下:
@SerializedName(value = "email_address",alternate = {"emailAddress","email"}) 複製程式碼
2.FieldNamingPolicy
結合GsonBuilder.setFieldNamingPolicy
使用,對於:
User user = new User("Cap", 70); user.emailAddress = "[email protected]"; 複製程式碼
Gson gson = new GsonBuilder() .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES) .create(); 複製程式碼
對應的欄位效果是:
FieldNamingPolicy | 結果(僅輸出emailAddress欄位) |
---|---|
IDENTITY | {"emailAddress":"[email protected]"} |
LOWER_CASE_WITH_DASHES | {"email-address":"[email protected]"} |
LOWER_CASE_WITH_UNDERSCORES | {"email_address":"[email protected]"} |
UPPER_CAMEL_CASE | {"EmailAddress":"[email protected]"} |
UPPER_CAMEL_CASE_WITH_SPACES | {"Email Address":"[email protected]"} |
3.自定義實現
GsonBuilder.setFieldNamingStrategy
方法需要與Gson提供的FieldNamingStrategy
介面配合使用,用於實現將POJO的欄位與JSON的欄位相對應。
注:FieldNamingPolicy
也實現了FieldNamingStrategy
介面,即FieldNamingPolicy
也可以使用setFieldNamingStrategy
方法。
使用:
Gson gson = new GsonBuilder() .setFieldNamingStrategy(new FieldNamingStrategy() { @Override public String translateName(Field f) { //實現自己的規則 return null; } }) .create(); 複製程式碼
五、接管序列化和反序列化過程
使用TypeAdapter
介面,或JsonSerializer
、JsonDeserializer
注:TypeAdapter
以及JsonSerializer
和JsonDeserializer
都需要與GsonBuilder.registerTypeAdapter
或GsonBuilder.registerTypeHierarchyAdapter
配合使用;
注:註冊了 TypeAdapter之後,@SerializedName 、FieldNamingStrategy、Since、Until、Expose都失去了效果,直接由TypeAdapter之後接管。
registerTypeAdapter
與registerTypeHierarchyAdapter
的區別:
registerTypeAdapter | registerTypeHierarchyAdapter | |
---|---|---|
支援泛型 | 是 | 否 |
支援繼承 | 否 | 是 |
1.TypeAdapter
使用:
Gson gson=new GsonBuilder().registerTypeAdapter(User.class, new TypeAdapter<User>() { @Override public void write(JsonWriter out, User value) throws IOException { out.beginObject(); out.name("mName") .value(value.getName()); out.endObject(); out.flush(); } @Override public User read(JsonReader in) throws IOException { User user = new User("a",4); in.beginObject(); if (in.nextName().equals("mName")) user.setName(in.nextString()); in.endObject(); return user; } }).create(); User user = new User("我",10); Log.i("adapter","user:"+gson.toJson(user)); Log.i("adapter","user:"+gson.fromJson("{\"mName\":\"我\"}",User.class)); 複製程式碼
2.JsonSerializer和JsonDeserializer
TypeAdapter
接管了序列化和反序列化過程,而JsonSerializer
和JsonDeserializer
則只分別單獨接管序列化和反序列化過程。
使用:
Gson gson=new GsonBuilder() .registerTypeAdapter(User.class, new JsonSerializer<User>() { @Override public JsonElement serialize(User src, Type typeOfSrc, JsonSerializationContext context) { JsonObject jsonElement = new JsonObject(); jsonElement.addProperty("name","serialize"); return jsonElement; } }) .registerTypeAdapter(User.class, new JsonDeserializer<User>() { @Override public User deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { User user = new User("",10); user.setName(json.getAsJsonObject().get("mName").getAsString()); return user; } }).create(); 複製程式碼
3.TypeAdapterFactory
用於建立TypeAdapter
的工廠類,通過對比Type
,確定有沒有對應的TypeAdapter
,沒有就返回null
,與GsonBuilder.registerTypeAdapterFactory
配合使用。
Gson gson = new GsonBuilder() .registerTypeAdapterFactory(new TypeAdapterFactory() { @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { return null; } }) .create(); 複製程式碼
4.@JsonAdapter註解
作用在POJO類 上的,接收一個引數,且必須是TypeAdpater,JsonSerializer或JsonDeserializer這三個其中之一。
前面的JsonSerializer
和JsonDeserializer
都要配合GsonBuilder.registerTypeAdapter
使用,但每次使用都要註冊也太麻煩了,JsonAdapter
就是為了解決這個痛點的。
使用:
@JsonAdapter(UserTypeAdapter.class) public final class User { ..... } 複製程式碼
public class UserTypeAdapter implements JsonSerializer<User> { @Override public JsonElement serialize(User src, Type typeOfSrc, JsonSerializationContext context) { JsonObject jsonElement = new JsonObject(); jsonElement.addProperty("name","serialize"); return jsonElement; } } 複製程式碼
User user = new User("我",10); Log.i("adapter","user:"+new Gson().toJson(user));//直接使用簡單的new GSON()即可,無需配置註冊 複製程式碼