日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java json序列化库gson(2)

發布時間:2023/12/15 java 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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種實現方式分別為:

FieldNamingPolicy結果(僅輸出emailAddress字段)
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的區別:

?registerTypeAdapterregisterTypeHierarchyAdapter
支持泛型
支持繼承

注:如果一個被序列化的對象本身就帶有泛型,且注冊了相應的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

Gson gson = new Gson(); User user = new User("怪盜kidou", 24, "ikidou@example.com"); System.out.println(gson.toJson(user)); //結果:{"name":"怪盜kidou","age":24,"email":"ikidou@example.com"} //為區別結果,特意把email字段與@SerializedName注解中設置的不一樣

五、TypeAdapter與 JsonSerializer、JsonDeserializer對比

?TypeAdapterJsonSerializer、JsonDeserializer
引入版本2.01.x
Stream API支持不支持*,需要提前生成JsonElement
內存占用比TypeAdapter大
效率比TypeAdapter低
作用范圍序列化??反序列化序列化??反序列化

?

轉載于:https://my.oschina.net/hutaishi/blog/1162303

總結

以上是生活随笔為你收集整理的Java json序列化库gson(2)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。