Java json序列化库gson(2)
2019獨角獸企業重金招聘Python工程師標準>>>
基于策略(自定義規則)
上面介紹的了3種排除字段的方法,說實話我除了@Expose以外,其它的都是只在Demo用上過,用得最多的就是馬上要介紹的自定義規則,好處是功能強大、靈活,缺點是相比其它3種方法稍麻煩一點,但也僅僅只是想對其它3種稍麻煩一點而已。
基于策略是利用Gson提供的ExclusionStrategy接口,同樣需要使用GsonBuilder,相關API 2個,分別是addSerializationExclusionStrategy?和addDeserializationExclusionStrategy?分別針對序列化和反序化時。這里以序列化為例。
Gson gson = new GsonBuilder().addSerializationExclusionStrategy(new ExclusionStrategy() {@Overridepublic boolean shouldSkipField(FieldAttributes f) {// 這里作判斷,決定要不要排除該字段,return true為排除if ("finalField".equals(f.getName())) return true; //按字段名排除Expose expose = f.getAnnotation(Expose.class); if (expose != null && expose.deserialize() == false) return true; //按注解排除return false;}@Overridepublic boolean shouldSkipClass(Class<?> clazz) {// 直接排除某個類 ,return true為排除return (clazz == int.class || clazz == Integer.class);}}).create();二、 POJO與JSON的字段映射規則
還是之前User的例子,已經去除所有注解:
User user = new User("怪盜kidou", 24); user.emailAddress = "ikidou@example.com";GsonBuilder提供了FieldNamingStrategy接口和setFieldNamingPolicy和setFieldNamingStrategy兩個方法。
默認實現
GsonBuilder.setFieldNamingPolicy?方法與Gson提供的另一個枚舉類FieldNamingPolicy配合使用,該枚舉類提供了5種實現方式分別為:
| IDENTITY | {"emailAddress":"ikidou@example.com"} |
| LOWER_CASE_WITH_DASHES | {"email-address":"ikidou@example.com"} |
| LOWER_CASE_WITH_UNDERSCORES | {"email_address":"ikidou@example.com"} |
| UPPER_CAMEL_CASE | {"EmailAddress":"ikidou@example.com"} |
| UPPER_CAMEL_CASE_WITH_SPACES | {"Email Address":"ikidou@example.com"} |
自定義實現
GsonBuilder.setFieldNamingStrategy?方法需要與Gson提供的FieldNamingStrategy接口配合使用,用于實現將POJO的字段與JSON的字段相對應。上面的FieldNamingPolicy實際上也實現了FieldNamingStrategy接口,也就是說FieldNamingPolicy也可以使用setFieldNamingStrategy方法。
用法:
Gson gson = new GsonBuilder().setFieldNamingStrategy(new FieldNamingStrategy() {@Overridepublic String translateName(Field f) {//實現自己的規則return null;}}).create();注意:?@SerializedName注解擁有最高優先級,在加有@SerializedName注解的字段上FieldNamingStrategy不生效!
一、TypeAdapter
TypeAdapter?是Gson自2.0(源碼注釋上說的是2.1)開始版本提供的一個抽象類,用于接管某種類型的序列化和反序列化過程,包含兩個注要方法?write(JsonWriter,T)?和?read(JsonReader)?其它的方法都是final方法并最終調用這兩個抽象方法。
public abstract class TypeAdapter<T> {public abstract void write(JsonWriter out, T value) throws IOException;public abstract T read(JsonReader in) throws IOException;//其它final 方法就不貼出來了,包括`toJson`、`toJsonTree`、`toJson`和`nullSafe`方法。 }注意:TypeAdapter 以及 JsonSerializer 和 JsonDeserializer 都需要與?GsonBuilder.registerTypeAdapter?示或GsonBuilder.registerTypeHierarchyAdapter配合使用,下面將不再重復說明。實例如下:
User user = new User("怪盜kidou", 24); user.emailAddress = "ikidou@example.com"; Gson gson = new GsonBuilder()//為User注冊TypeAdapter.registerTypeAdapter(User.class, new UserTypeAdapter()).create(); System.out.println(gson.toJson(user));UserTypeAdapter的定義:
public class UserTypeAdapter extends TypeAdapter<User> {@Overridepublic void write(JsonWriter out, User value) throws IOException {out.beginObject();out.name("name").value(value.name);out.name("age").value(value.age);out.name("email").value(value.email);out.endObject();}@Overridepublic User read(JsonReader in) throws IOException {User user = new User();in.beginObject();while (in.hasNext()) {switch (in.nextName()) {case "name":user.name = in.nextString();break;case "age":user.age = in.nextInt();break;case "email":case "email_address":case "emailAddress":user.email = in.nextString();break;}}in.endObject();return user;} }當我們為User.class?注冊了?TypeAdapter之后,只要是操作User.class?那些之前介紹的@SerializedName?、FieldNamingStrategy、Since、Until、Expos通通都黯然失色,失去了效果,只會調用我們實現的UserTypeAdapter.write(JsonWriter, User)?方法,我想怎么寫就怎么寫。
再說一個場景,在該系列的第一篇文章就說到了Gson有一定的容錯機制,比如將字符串?"24"?轉成int 的24,但如果有些情況下給你返了個空字符串怎么辦(有人給我評論問到這個問題)?雖然這是服務器端的問題,但這里我們只是做一個示范。
int型會出錯是吧,根據我們上面介紹的,我注冊一個TypeAdapter 把 序列化和反序列化的過程接管不就行了?
Gson gson = new GsonBuilder().registerTypeAdapter(Integer.class, new TypeAdapter<Integer>() {@Overridepublic void write(JsonWriter out, Integer value) throws IOException {out.value(String.valueOf(value)); }@Overridepublic Integer read(JsonReader in) throws IOException {try {return Integer.parseInt(in.nextString());} catch (NumberFormatException e) {return -1;}}}).create(); System.out.println(gson.toJson(100)); // 結果:"100" System.out.println(gson.fromJson("\"\"",Integer.class)); // 結果:-1注:測試空串的時候一定是"\"\""而不是"",""代表的是沒有json串,"\"\""才代表json里的""。
你說這一接管就要管兩樣好麻煩呀,我明明只想管序列化(或反列化)的過程的,另一個過程我并不關心,難道沒有其它更簡單的方法么? 當然有!就是接下來要介紹的?JsonSerializer與JsonDeserializer。
二、JsonSerializer與JsonDeserializer
JsonSerializer?和JsonDeserializer?不用像TypeAdapter一樣,必須要實現序列化和反序列化的過程,你可以據需要選擇,如只接管序列化的過程就用?JsonSerializer?,只接管反序列化的過程就用?JsonDeserializer?,如上面的需求可以用下面的代碼。
Gson gson = new GsonBuilder().registerTypeAdapter(Integer.class, new JsonDeserializer<Integer>() {@Overridepublic Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {try {return json.getAsInt();} catch (NumberFormatException e) {return -1;}}}).create(); System.out.println(gson.toJson(100)); //結果:100 System.out.println(gson.fromJson("\"\"", Integer.class)); //結果-1下面是所有數字都轉成序列化為字符串的例子
JsonSerializer<Number> numberJsonSerializer = new JsonSerializer<Number>() {@Overridepublic JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) {return new JsonPrimitive(String.valueOf(src));} }; Gson gson = new GsonBuilder().registerTypeAdapter(Integer.class, numberJsonSerializer).registerTypeAdapter(Long.class, numberJsonSerializer).registerTypeAdapter(Float.class, numberJsonSerializer).registerTypeAdapter(Double.class, numberJsonSerializer).create(); System.out.println(gson.toJson(100.0f));//結果:"100.0"?
registerTypeAdapter與registerTypeHierarchyAdapter的區別:
| 支持泛型 | 是 | 否 |
| 支持繼承 | 否 | 是 |
注:如果一個被序列化的對象本身就帶有泛型,且注冊了相應的TypeAdapter,那么必須調用Gson.toJson(Object,Type),明確告訴Gson對象的類型。
Type type = new TypeToken<List<User>>() {}.getType(); TypeAdapter typeAdapter = new TypeAdapter<List<User>>() {//略 }; Gson gson = new GsonBuilder().registerTypeAdapter(type, typeAdapter).create(); List<User> list = new ArrayList<>(); list.add(new User("a",11)); list.add(new User("b",22)); //注意,多了個type參數 String result = gson.toJson(list, type);三、TypeAdapterFactory
TypeAdapterFactory,見名知意,用于創建TypeAdapter的工廠類,通過對比Type,確定有沒有對應的TypeAdapter,沒有就返回null,與GsonBuilder.registerTypeAdapterFactory配合使用。
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new TypeAdapterFactory() {@Overridepublic <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {return null;}}).create();四、@JsonAdapter注解
JsonAdapter相較之前介紹的SerializedName?、FieldNamingStrategy、Since、Until、Expos這幾個注解都是比較特殊的,其它的幾個都是用在POJO的字段上,而這一個是用在POJO類上的,接收一個參數,且必須是TypeAdpater,JsonSerializer或JsonDeserializer這三個其中之一。
上面說JsonSerializer和JsonDeserializer都要配合GsonBuilder.registerTypeAdapter使用,但每次使用都要注冊也太麻煩了,JsonAdapter就是為了解決這個痛點的。
使用方法(以User為例):
@JsonAdapter(UserTypeAdapter.class) //加在類上 public class User {public User() {}public User(String name, int age) {this.name = name;this.age = age;}public User(String name, int age, String email) {this.name = name;this.age = age;this.email = email;}public String name;public int age;@SerializedName(value = "emailAddress")public String email; }使用時不用再使用?GsonBuilder去注冊UserTypeAdapter了。
注:@JsonAdapter?僅支持?TypeAdapter或TypeAdapterFactory
五、TypeAdapter與 JsonSerializer、JsonDeserializer對比
| 引入版本 | 2.0 | 1.x |
| Stream API | 支持 | 不支持*,需要提前生成JsonElement |
| 內存占用 | 小 | 比TypeAdapter大 |
| 效率 | 高 | 比TypeAdapter低 |
| 作用范圍 | 序列化?和?反序列化 | 序列化?或?反序列化 |
?
轉載于:https://my.oschina.net/hutaishi/blog/1162303
總結
以上是生活随笔為你收集整理的Java json序列化库gson(2)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为p30 pro 拍照有多强呢
- 下一篇: 院士倪光南:Win10不安全 中国必须用