JSON解析類庫之Gson(3) --- Gson注解
---Gson類庫學習, 生成與解析json資料,json字元串與Java對象互轉
一、前言
Gson注解給我們的使用帶來很多友善,特别是Java實體類字段與獲得的JSON字元串的字段不一一對應時,注解發揮巨大作用,同時也簡化了代碼的開發。
二、Gson的注解
注:在Gson中有5類注解 。

◆ ◆ ◆ 1 @SerializedName注解(JSON字段重命名) ---------------------------------------------------------------------------------------------------- 該注解能指定該字段在JSON中對應的字段名稱,就是将POJO中的字段與JSON字元串中的字段對應起來。 輸出的json使用另外一個名字,預設轉換出來的json中和對象的字段是一樣的,當然也 可以設定成不同,使用SerializedName 注解 。
作用1:轉換關鍵字key,json轉換成JavaBean時,json字段的key 預設必須和我們聲明類的字段名稱一樣,當伺服器端傳回了關鍵字怎麼辦,比如key 為new switch這樣,我們在聲明類的時候不能寫這樣的字段,可能你想伺服器端改動,他可能要改資料庫,但是我告訴你,做服務端的大部分不願意改動他的json,是很自私的!這時候重命名注解都排上用場了 。 第二種場景:伺服器端傳回的json 的key 簡直太醜,或者太長,你想簡化,my_parent_name,可以簡化成mpn 。
從前面的POJO的生成與解析可以看出,json的字段和值是和pojo的名稱和類型是一一對應的,但也有一定容錯機制(如第一篇文章中,基本類型轉換中,第3行将字元串的99.99轉成double型,你可别告訴我都是字元串啊),但有時候也會出現一些不和諧的情況,如:
期望的json格式
{"id":"100",name":"chunlynn","emailAddress":"[email protected]","title":"engineer"}
實際
{"id":"100",name":"chunlynn","email_address":"[email protected]","title":"engineer"}
如果我們是通過http調用其他系統的接口而獲得到的JSON字元串資料,顯然JSON字元串的結果我們是無法改變的,而JSON的字段和我們的POJO中字段并沒有一一對應,這樣解析肯定會出錯。這些以下劃線命名的方式,在使用PHP作為背景開發語言時是很常見的情況,php和js在命名時一般采用下劃線風格,而Java中一般采用的駝峰法,若要自己使用下劃線風格時我會感到不适應,且不符合Java命名規範,怎麼辦?難到沒有兩全齊美的方法麼?
Gson提供了一個 SerializedName的注解類,這應該就是我們要找的。
那麼對于JSON中email_address這個字段對應POJO的字段則變成:
@SerializedName(
"email_address"
)
private String emailAddress;
這樣的話,很好的保留了前端、背景、Java/Android各自的命名習慣。 注意: SerializedName中的value屬性值,永遠都是指JSON字元串中的字段值(POJO序列化後的值)。如 email_address指的就是JSON字元串中的字段值,通過注解@ SerializedName("email_address")将它和POJO中的字段值emailAddress關聯映射起來。
你以為這樣就完了麼?
如果接口中設計不嚴謹,或者其它地方可以重用該類,其它字段都一樣,就emailAddress 字段不一樣,比如有下面三種情況那怎麼?重新寫一個?
{"id":"100",name":"chunlynn","emailAddress":"[email protected]","title":"engineer"}
{"id":"100",name":"chunlynn","email_address":"[email protected]","title":"engineer"}
{"id":"100",name":"chunlynn","email":"[email protected]","title":"engineer"}
為POJO字段提供備選屬性名 SerializedName注解提供了兩個屬性,上面用到了其中一個,别外還有一個屬性alternate,接收一個String數組。 注:alternate需要2.4及以上版本。 alternate是反序列化時才有用。不管 SerializedName中的值是多少,反序列化後對應的POJO的字段值都是emailAddress。
@SerializedName(value
=
"emailAddress",
alternate
=
{
"email",
"email_address"
})
private String emailAddress;
如果JSON中有 email 就會解析成 emailAddress ,如果有 email_address 也會解析成 emailAddress. 注意1:value中的值不能出現在alternate中; 注意2:alternate的備選字段, 會後面的替換前面的。 當上面的三個屬性(email_address、email、emailAddress)中都出現,或出現任意一個時均可以得到正确的結果。 注:當多種情況同時出時,以最後一個出現的值為準。
◇情況1: 實體類:
import
com.google.gson.annotations.SerializedName;
public class Employee {
private String id;
private String name;
@SerializedName(value = "emailAddress", alternate = { "email", "email_address" })
private String emailAddress;
//為了代碼簡潔,這裡移除了getter和setter方法、toString方法等
}
測試類【反序列化】:
package
com.chunlynn.gson;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class GsonTest12 {
public static void main(String[] args) {
Gson gson = new GsonBuilder()//
//.setPrettyPrinting()//格式化輸出(序列化)
.enableComplexMapKeySerialization() 支援Map的key為複雜對象的形式
.create();
/*
{\"id\":\"100\",\"name\":\"chunlynn\",\"emailAddress\":\"[email protected]\"}
{\"id\":\"100\",\"name\":\"chunlynn\",\"email_address\":\"[email protected]\"}
{\"id\":\"100\",\"name\":\"chunlynn\",\"email\":\"[email protected]\"}
*/
String json1 = "{\"id\":\"100\",\"name\":\"chunlynn\",\"email_address\":\"[email protected]\"}";
String json2 = "{\"id\":\"100\",\"name\":\"chunlynn\",\"emailAddress\":\"[email protected]\",\"email_address\":\"[email protected]\",\"email\":\"[email protected]\"}";
Employee employee1 = gson.fromJson(json1, Employee.class);
System.out.println("email_address字段反序列化 ===> " + employee1);
//email_address字段反序列化 ===> Employee [id=100, name=chunlynn, [email protected]]
Employee employee2 = gson.fromJson(json2, Employee.class);
System.out.println("多種格式字段反序列化 ===> " + employee2);
// 多種格式字段反序列化 ===> Employee [id=100, name=chunlynn, [email protected]]
}
}
結果反序列化完全成功。這個注解在我們處理調用的遠端接口傳回的JSON字段與我們自己定義的POJO的字段不比對時非常有用。
◇情況2: 實體類:
public
class
Employee {
private String id;
private String name;
//序列化後就變成了email (json串中的字段名)
@SerializedName(value
=
"email",
alternate
=
{
"emailAddress",
"email_address"
})
private String emailAddress;
//為了代碼簡潔,這裡移除了getter和setter方法、toString方法、構造方法等
}
測試類【序列化與反序列化】:
package
com.chunlynn.gson;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class GsonTest13 {
public static void main(String[] args) {
Gson gson = new GsonBuilder()//
//.setPrettyPrinting()//格式化輸出(序列化)
.enableComplexMapKeySerialization() 支援Map的key為複雜對象的形式
.create();
Employee empyee = new Employee("1001", "jeffchen", "[email protected]");
String jsonString = gson.toJson(empyee);
System.out.println("使用注解後的序列化==" + jsonString);
// 使用注解後的序列化=={"id":"1001","name":"jeffchen","email":"[email protected]"}
Employee employee3 = gson.fromJson(jsonString, Employee.class);
System.out.println("使用注解後的反序列化==" + employee3);
// 使用注解後的反序列化==Employee [id=1001, name=jeffchen, emailAddress[email protected]]
}
}
◆ ◆ ◆ 2 @Expose注解(字段過濾) ---------------------------------------------------------------------------------------------------- 指定哪些是要暴露轉換的屬性。有時候我們不需要把實體的所有屬性都導出,隻想把一部分屬性導出為Json,或隻想對一部分POJO的字段進行反序列化。
源碼:預設既可以序列化又可以反序列化。下面是Gson的 Expose 注解源碼:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Expose {
public
boolean
serialize()
default
true;
public boolean deserialize() default true;
}
Expose注解有兩個屬性,預設值都是true,即預設同時對序列化和反序列化都有效。
即使用了Expose預設注解後:标注了 Expose注解的字段才會被序列化輸出,同時,反序列化時,标注了 Expose注解的字段才會被反序列化。
◇情況1:預設注解 @Expose ,序列化和反序列化都有效 實體類:
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public
class
Employee2 {
private String id;
@Expose
//等同于@Expose(deserialize = true,serialize = true)
private
String
name;
@
Expose
//序列化後就變成了email (json串中的字段名)
@SerializedName(value = "email", alternate = { "emailAddress", "email_address" })
private String emailAddress;
private Date birthday;
@
Expose
private String title;
//為了代碼簡潔,這裡移除了getter和setter方法、toString方法、構造方法等
}
測試類: 注意:使用了@Expose注解,則必須在GsonBuilder類執行個體化時進行設定。隻有配置了 .excludeFieldsWithoutExposeAnnotation() 時,@Expose才會起作用。
package
com.chunlynn.gson;
import java.util.Date;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class GsonTest14 {
public static void main(String[] args) {
Gson gson = new GsonBuilder()//
//.setPrettyPrinting()//格式化輸出(序列化)
.excludeFieldsWithoutExposeAnnotation() // 不導出實體中沒有用@Expose注解的屬性。
.setDateFormat("yyyy-MM-dd HH:mm:ss") //序列化時間轉化為特定格式
.create();
Employee2 employee2 = new Employee2("1002", "chunlynn", "[email protected]", new Date(), "engineer");
String jsonString = gson.toJson(employee2);
System.out.println("使用了@Expose注解後的序列化輸出 ===》 " + jsonString);
//使用了@Expose注解後的序列化輸出 ===》 {"name":"chunlynn","email":"[email protected]","title":"engineer"}
Employee2 retEmployee = gson.fromJson(jsonString, Employee2.class);
System.out.println("使用了@Expose注解後的反序列化解析==》" + retEmployee);
//使用了@Expose注解後的反序列化解析==》Employee2 [id=null, name=chunlynn, [email protected], birthday=null, title=engineer]
String jsonString2 = "{\"id\":\"1007\",\"name\":\"jeffchen\",\"email\":\"[email protected]\",\"title\":\"boss\"}";
Employee2 reEmployee2 = gson.fromJson(jsonString2, Employee2.class);
System.out.println("使用了@Expose注解後的反序列化解析2==》" + reEmployee2);
// 使用了@Expose注解後的反序列化解析2==》Employee2 [id=null, name=jeffchen, [email protected], birthday=null, title=boss]
}
}
上面的實體類中,我們使用的是@Expose的預設屬性,預設情況下對序列化和反序列化都有效。
Expose注解類兩個屬性:serialize和deserialize可以分别設定序列化和反序列化。
分為以下幾種情況: 1:不添加@Expose注解等同于@Expose(deserialize = false,serialize = false) 不做任何解析。 2:@Expose(deserialize = true,serialize = false) 隻解析時用,也就是反序列化可以,序列化不可以 3:@Expose(deserialize = false,serialize = true) 序列化可以,反序列化不行 4:@Expose(deserialize = true,serialize = true) 既可以序列化,也可以反序列化,等同于預設。
下面執行個體,将分别示範這四種情況。
◇情況2:分别設定序列化與反序列化暴露字段
實體類:
public
class
Employee3 {
private String id;
@Expose
//等同于 @Expose(deserialize = true,serialize = true)
private String name;
@Expose
@SerializedName(value = "email", alternate = { "emailAddress", "email_address" })
private String emailAddress;
@Expose(serialize = true, deserialize = false)
private Date birthday;
@Expose(serialize = false, deserialize = true)
private
String
title;
//為了代碼簡潔,這裡移除了getter和setter方法、toString方法、構造方法等
}
測試類:
package
com.chunlynn.gson;
import java.util.Date;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class GsonTest15 {
public static void main(String[] args) {
Gson gson = new GsonBuilder()//
//.setPrettyPrinting()//格式化輸出(序列化)
.excludeFieldsWithoutExposeAnnotation() // 不導出實體中沒有用@Expose注解的屬性
.setDateFormat("yyyy-MM-dd HH:mm:ss") //序列化時間轉化為特定格式
.create();
Employee3 employee3 = new Employee3("1005", "chunlynn", "[email protected]", new Date(), "engineer");
/**
* 序列化
*/
String jsonStr = gson.toJson(employee3);
System.out.println("使用@Expose()注解後的序列化輸出 ==》 " + jsonStr);
//使用了@Expose注解後的序列化輸出 ===》
//{"name":"chunlynn","email":"[email protected]","birthday":"2017-05-05 11:20:36"}
/**
* 反序列化[1]
*/
Employee3 retEmployee = gson.fromJson(jsonStr, Employee3.class);
System.out.println("使用了@Expose()注解後的反序列化解析==》" + retEmployee);
//使用了@Expose()注解後的反序列化解析==》
//Employee3 [id=null, name=chunlynn, [email protected], birthday=null, title=null]
/**
* 反序列化[2]
*/
String jsonString2 = "{\"id\":\"1007\",\"name\":\"jeffchen\",\"email\":\"[email protected]\",\"title\":\"boss\"}";
Employee3 reEmployee2 = gson.fromJson(jsonString2, Employee3.class);
System.out.println("使用了@Expose()注解後的反序列化解析2==》" + reEmployee2);
// 使用了@Expose()注解後的反序列化解析2==》
//Employee3 [id=null, name=jeffchen, [email protected], birthday=null, title=boss]
}
}
◆ ◆ ◆ 3、4 @Since(double v) 與 @Until(double v)注解 (版本控制) ---------------------------------------------------------------------------------------------------- 有時候我們的實體類會随着版本的更新而修改。一些新的字段是後續加進來的,在新的版本軟體中才使用。 @Since(double v) 與 @Until(double v)注解源碼:
@Retention
(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface Since {
/**
* the value indicating a version number since this member
* or type has been present.
*/
double value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface Until {
/**
* the value indicating a version number until this member
* or type should be ignored.
*/
double value();
}
@Since
和
@Until
都接收一個
Double
值。
Since(4.0),表示目前版本大于等于4.0時才有效。目前版本是指在GsonBuilder.setVersion(double v)中設定的版本。 Until(4.0),表示目前版本小于4.0時才有效。
實體類:
public
class
Employee4 {
private String id;
@Expose
//等同于 @Expose(deserialize = true,serialize = true)
private String name;
@Expose
@SerializedName(value = "email", alternate = { "emailAddress", "email_address" })
private String emailAddress;
@Expose(serialize = true, deserialize = false)
private Date birthday;
@Expose(serialize = false, deserialize = true)
private String title;
@Expose
@Since(4.0)
//表示該字段從4.0開始生效
private String phoneNum;
@Expose
@Until(2.0)
//表示2.0及其以後該字段就失效了
private String habbit;
//為了代碼簡潔,這裡移除了getter和setter方法、toString方法、構造方法等
}
測試類: 注意:使用了@Since(double v)、@Until(double v)注解,則必須在GsonBuilder類執行個體化時進行設定。隻有配置了 . .setVersion(double v) 時,@Since(double v)、@Until(double v)才會起作用。
package
com.chunlynn.gson;
import java.util.Date;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class GsonTest16 {
public static void main(String[] args) {
Gson gson = new GsonBuilder()//
//.setPrettyPrinting()//格式化輸出(序列化)
.excludeFieldsWithoutExposeAnnotation() // 不導出實體中沒有用@Expose注解的屬性
.setDateFormat("yyyy-MM-dd HH:mm:ss") //序列化時間轉化為特定格式
.setVersion(5.0) //設定目前版本号
.create();
Employee4 employee = new Employee4("1005", "chunlynn", "[email protected]", new Date(), "engineer", "10086",
"羽毛球");
/**
* 序列化
*/
String jsonStr = gson.toJson(employee);
System.out.println("使用@Since()和@Until()注解後的序列化輸出 ==》 " + jsonStr);
//使用@Since()和@Until()注解後的序列化輸出 ==》
//{"name":"chunlynn","email":"[email protected]","birthday":"2017-05-05 11:52:40","phoneNum":"10086"}
/**
* 反序列化[3]
*/
Employee4 retEmployee = gson.fromJson(jsonStr, Employee4.class);
System.out.println("使用@Since()和@Until()注解後的反序列化解析==》" + retEmployee);
//使用@Since()和@Until()注解後的反序列化解析==》
//Employee4 [id=null, name=chunlynn, [email protected], birthday=null, title=null, phoneNum=10086, habbit=null]
/**
* 反序列化[4]
*/
String jsonString2 = "{\"id\":\"1007\",\"name\":\"jeffchen\",\"email\":\"[email protected]\",\"title\":\"boss\",\"phoneNum\":\"10010\",\"habbit\":\"遊泳\"}";
Employee4 reEmployee2 = gson.fromJson(jsonString2, Employee4.class);
System.out.println("使用@Since()和@Until()注解後的反序列化解析2==》" + reEmployee2);
//使用@Since()和@Until()注解後的反序列化解析2==》
//Employee4 [id=null, name=jeffchen, [email protected], birthday=null, title=boss, phoneNum=10010, habbit=null]
}
}
◆ ◆ ◆ 5 JsonAdapter 注解 (使用TypeAdapter時的注解) ---------------------------------------------------------------------------------------------------- 該注解在TypeAdapter的章節中進行講解,不過一般很少用這個注解。
注解講解完。
◆ ◆ 該系列的其他文章 : JSON解析類庫之Gson(1) --- 簡單JavaBean對象、帶泛型的Bean對象與JSON互轉
JSON解析類庫之Gson(2) --- 泛型對象Map、List與JSON字元串互轉
JSON解析類庫之Gson(3) --- Gson注解
JSON解析類庫之Gson(4)--- TypeAdapter接管序列化與反序列化(上)
--------------------------------------------------------------------------------------------------- 版權聲明:本文為部落客(chunlynn)原創文章,轉載請注明出處 :http://blog.csdn.net/chenchunlin526/article/details/71173404