2018年1月3日

GSON 進階教學

GSON進階教學

完成基礎教學後,本章節教你如何處理在非正常情況下,如何完成反序列與序列動作。

  • 泛型轉換
  • 序列化與反序列化時,客製化輸入出JOSN字串@SerializedName
  • 忽略物件屬性輸出@Expose

泛型轉換

泛型做Json序列/反序列時,比較麻煩地方是泛型在運行期間相關的參數就會被抹除所以無法知道原來的類別。我們建立一個播放器(Play)類別,它為泛型的類型,它可撥放MP3、CD等等,所以建立一個CD媒介(CD)類別。Play使用類型為泛型T,

物件 屬性
播放器 Play 類型 type
CD媒介 CD 歌 songs
/**'
 *  播放器
 * @param 
 */
public class Play {
    T type ;
    public Play(T t){
        this.type = t;
     }

    @Override
    public String toString() {
        return this.type.toString();
    }
}
/**
 * CD 音樂物件
 */
public class CD {
    private List songs ;

    public CD(String ...songs){
        this.songs = new ArrayList() ;
        for(String song : songs){
            this.songs.add(song) ;
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder() ;
        sb.append("");
        for(String s:songs){
            sb.append(""+s+",\r\n");
        }
        sb.append("");
        return sb.toString();
    }
}

我們現在建立cd01歌曲資料,用toJson序列可以正常動作,但是要做反序列直接轉換無法正常動作,所以需要利用TypeToken來建立類型,在fromJson回傳正確類型,

public class PlayTest {

    public static void main(String[] ags){
        CD cd01 = new CD("lemon tree ","She","I want it that way");
        Play play = new Play

序列化與反序列化時,名稱不同

之前的範例都是JSON欄位名稱與物件名稱相同,如果輸入JSON欄位名稱不同時,可以利用@SerializedName去定義輸入欄位名稱,但是需要Gson 2.4 版之後開始支援的 alternate 屬性。

  1. 反序列與序列相同設定
    物件屬性可能跟JSON不一樣,如書(Book)屬性為bid,但是JSON字串欄位為bookID,這種狀況就可以使用@SerializedName(value=”bookID”)來定義接收/與輸入屬性為bookID,
public class BookTest {

    public  static void main(String[] args){
           //input json string
        String book_json = "{\"bookID\":\"9626344946\",\"title\":\"The Moonlit Road and Other Stories\",\"author\":\" Bierce, Ambrose/ Croker, B. M./ Crawford, F. Marion/ Le Fanu, Joseph Sheridan/ Keeble, Jonathan (NRT)\"}";
        Gson gson = new Gson();
        Type type = new TypeToken(){}.getType();
        Book book = gson.fromJson(book_json,type);
        // convert Book object 
        System.out.println(book.toString()) ;
        // output json string
        System.out.println(gson.toJson(book)) ;
    }

}

/**
 * name : 書明細
 */
public class Book {
    @Expose(serialize = false, deserialize = false)
    @SerializedName(value="bookID")
    private String bid;
    private String title;
    private String author;

    public Book(String bid, String title, String author)  {
        this.bid = bid ;
        this.title = title ;
        this.author = author ;
    }

    public String getBId() {
        return bid;
    }

    public void setBId(String id) {
        this.bid = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer() ;
        sb.append("") ;
        sb.append("bid:"+bid+"\n") ;
        sb.append("title:"+title+"\n") ;
        sb.append("author:"+author+"\n") ;
        sb.append("") ;
        return sb.toString() ;
    }

}

結果:
bid:9626344946
title:The Moonlit Road and Other Stories
author: Bierce, Ambrose/ Croker, B. M./ Crawford, F. Marion/ Le Fanu, Joseph Sheridan/ Keeble, Jonathan (NRT)

{“bookID”:”9626344946”,”title”:”The Moonlit Road and Other Stories”,”author”:” Bierce, Ambrose/ Croker, B. M./ Crawford, F. Marion/ Le Fanu, Joseph Sheridan/ Keeble, Jonathan (NRT)”}

2.如果JSON輸出與輸入名稱不相同時,就需要alternate 來定義反序列輸入欄位名稱,如 @SerializedName(value=”bookID”, alternate = “ISBN”),那輸入會以ISBN或是bookID為bid的欄位。

public class BookTest {

    public  static void main(String[] args){
        String book_json = "{\"ISBN\":\"9626344946\",\"title\":\"The Moonlit Road and Other Stories\",\"author\":\" Bierce, Ambrose/ Croker, B. M./ Crawford, F. Marion/ Le Fanu, Joseph Sheridan/ Keeble, Jonathan (NRT)\"}";
        Gson gson = new Gson();
        Type type = new TypeToken(){}.getType();
        Book book = gson.fromJson(book_json,type);
        System.out.println(book.toString()) ;

    }

}

/**
 * name : 書明細
 */
public class Book {
    @Expose
    @SerializedName(value="bid",alternate = "ISBN")
    private String bid;
    private String title;
    private String author;

    public Book(String bid, String title, String author)  {
        this.bid = bid ;
        this.title = title ;
        this.author = author ;
    }

    public String getBId() {
        return bid;
    }

    public void setBId(String id) {
        this.bid = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer() ;
        sb.append("") ;
        sb.append("bid:"+bid+"\n") ;
        sb.append("title:"+title+"\n") ;
        sb.append("author:"+author+"\n") ;
        sb.append("") ;
        return sb.toString() ;
    }
}

結果:
bid:9626344946
title:The Moonlit Road and Other Stories
author: Bierce, Ambrose/ Croker, B. M./ Crawford, F. Marion/ Le Fanu, Joseph Sheridan/ Keeble, Jonathan (NRT)

{“bookID”:”9626344946”,”title”:”The Moonlit Road and Other Stories”,”author”:” Bierce, Ambrose/ Croker, B. M./ Crawford, F. Marion/ Le Fanu, Joseph Sheridan/ Keeble, Jonathan (NRT)”}

忽略物件屬性輸出@Expose

介紹最後一種情況當JAVA物件有些敏感資料不想要輸出字串時,可以使用Gson的@Expose註解標示,提供兩種標示serialize和deserialize,預設為true,也就是當沒有定義@Expose表示都要輸出欄位。
@Expose: serialize/deserialize預設為true

屬性 serialize deserialize
Expose true true
Expose false false
Expose false true
Expose true false

####參考資料
1. https://bng86.gitbooks.io/android-third-party-/content/gson.html
2. http://j796160836.pixnet.net/blog/post/30530326-%E7%9E%AD%E8%A7%A3json%E6%A0%BC%E5%BC%8F
3. http://blog.csdn.net/zzp_403184692/article/details/8266575
4. https://jimwayne.blogspot.tw/2016/09/gson.html