GSON速學必會

一. GSON 簡介

GSON是一個Java語言編寫的用於處理JSON數據格式的開源應用程序編程接口項目。它將Java對象轉換爲JSON表示。還能夠用於將JSON字符串轉換爲等效的Java對象。html

gson包包含了JSON數據處理的全部常見類和接口。gson內部的子包reflectannotation, 和 streamreflect包包含處理Java泛型類型信息的類和接口。annotation包包含相關的類和接口,用於對象屬性的自定義名稱映射。stream包包含與讀寫相關的類和接口。java

GSON設計的初衷以下:jquery

  • 有一個簡單的轉換機制,能夠將Java對象轉換爲JSON。GSON Java項目有大量的實用方法做爲api供開發人員使用。
  • 容許將先前存在的不可修改的Java對象轉換爲JSON和從JSON轉換。
  • 定製對象的表示。GSON爲對象字段提供了名稱的自定義映射,同時將其序列化爲JSON字符串。
  • 提供一個緊湊和格式化的輸出。默認狀況下,爲Java對象生成的JSON字符串是緊湊的形式。GSON提供漂亮的打印設備以使其以人類可讀的格式。

1. 在 GSON 中建立你的第一個 JSON

在本節中,將學習實例化GSON及其各類方法的含義,而後是一個快速示例代碼,展現包裝類型Java對象的基本序列化。web

步驟1 - 實例化GSON

要使用GSON庫,Gson類須要實例化一個com .google.GSON的對象。GSON對象不維護任何狀態,這個特性有助於在多個地方重用GSON對象。ajax

GSON庫提供了實例化的兩種方法:編程

  • 默認方法
  • 構造器使用設置方法

默認方法

在這種方法中,可使用new關鍵字實例化GSON類對象。這種方法建立了一個沒有設置的object實例。json

構造器使用設置方法

在這種方法中,可使用GsonBuilder類和create方法建立一個GSON類對象:api

Gson gson = new GsonBuilder ().create ();

前面的代碼調用了GsonBuildercreate方法,它返回一個Gson對象進行初始化。數組

下表列舉了GSON公共的一些方法:瀏覽器

方法 描述
fromJson 此方法用於反序列化以獲取Java對象。 API中有此方法的重載的形式。
toJson 該方法將Java對象序列化爲等效的JSON表示形式。 API中有此方法的重載的形式。
toJsonTree 該方法使用它們的泛型類型序列化對象。API中有此方法的重載的形式。

2. 一個簡單的例子

讓咱們看看一個簡單的例子代碼,展現的基本使用GSON庫對Java包裝類進行序列化/反序列化對象的JSON字符串:

import com.google.gson.Gson;

public class QuickStartDemo {

    public static void main(String[] args) {

        Gson gson = new Gson();

    /*Java Wrapper Type*/
        String jsonInteger = gson.toJson(new Integer(1));
        String jsonDouble = gson.toJson(new Double(12345.5432));

        System.out.println("GSON toJson Method Use ");
        System.out.println(jsonInteger);
        System.out.println(jsonDouble);

        Integer javaInteger = gson.fromJson(jsonInteger, Integer.class);
        Double javaDouble = gson.fromJson(jsonDouble, Double.class);

        System.out.println("GSON fromJson Method Use ");
        System.out.println(javaInteger);
        System.out.println(javaDouble);
    }
}

輸出結果爲:

GSON toJson Method Use
1
12345.5432
GSON fromJson Method Use
1
12345.5432

前面的代碼演示了toJsonfromJson的兩種方法的快速使用。

在代碼的第一部分中,使用默認方法實例化了一個Gson類對象,並使用值112345.5432實例化了兩個Java 包裝類對象,即Integer類和Double類。這些對象傳遞給toJson方法,該方法生成JSON等效字符串形式。

方法                           詳細說明
toJSON        參數:使用Java類對象進行序列化。 返回:JSON對象的字符串表示形式
fromJSON   參數:第一個參數是JSON表示的字符串類型,第二個參數是預期的Java類類型。返回:預期的Java類對象

在代碼的最後一部分中,JSON等效字符串傳遞給fromJson方法。 該方法有兩個參數,第一個參數是一個字符串,第二個參數是一個預期的Java類類型。 fromJson方法的返回類型始終是Java類型。

二. 須要知道的12個GSON特性

在本節中,將瞭解GSON庫支持的主要功能以及如何實現這些功能。

1. 對 Java 對象的支持

GSON中的對象被稱爲JsonElement的類型:

GSON庫能夠將任何用戶定義的類對象轉換爲JSON表示。Student類是一個用戶定義的類,GSON能夠將任何Student對象序列化爲JSON。
如下是 Student.java 的代碼:

package com.lee.jsondemo;

public class Student {

    private String name;

    private String subject;

    private int mark;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public int getMark() {
        return mark;
    }

    public void setMark(int mark) {
        this.mark = mark;
    }

}

Student類進行操做的JavaObjectFeaturesUse.java代碼以下:

import com.google.gson.Gson;
importcom.packt.chapter.vo.Student;

public class JavaObjectFeaturesUse {

public static void main(String[] args){

Gsongson = new Gson();

Student aStudent = new Student();
aStudent.setName("Sandeep");
aStudent.setMark(128);
aStudent.setSubject("Computer Science");

String studentJson = gson.toJson(aStudent);
System.out.println(studentJson);

Student anotherStudent = gson.fromJson(studentJson, Student.class);
System.out.println(anotherStudentinstanceof  Student);
  }
}

執行結果爲:

{"name":"Sandeep","subject":"Computer Science","mark":128}
true

上面的代碼建立了一個name屬性爲sandeep的學生對象,subject屬性設置爲Computer Sciencmark128。而後將一個Gson對象實例化,並將學生對象做爲一個參數傳遞給toJson()方法。它返回一個字符串,該字符串具備Java對象的JSON表示。該字符串做爲控制檯中的第一行打印。學生對象的輸出JSON表示是鍵/值對的集合。學生類的Java屬性成爲JSON字符串中的鍵。

在代碼的最後一部分中,fromJson()方法將JSON生成的字符串做爲第一個輸入參數,Student.class做爲第二個參數,將JSON字符串轉換回Java對象。代碼的最後一行使用Student做爲第二行操做符的實例來驗證由fromJson()方法生成的Java對象是不是Student類型的。在控制檯中,它輸出true,則表示咱們將獲得與JSON相同的值。

2. 序列化與反序列化

GSON有一些類的隱式序列化,好比Java包裝類(IntegerLongDouble等等)、Java.net.urljava.net.URIjava.util.Date,等等。

讓我看個例子:

import java.util.Date;
import com.google.gson.Gson;

public class InbuiltSerializerFeature {
    public static void main(String[] args) {
        Date aDateJson = new Date();
        Gson gson = new Gson();
        String jsonDate = gson.toJson(aDateJson);
        System.out.println(jsonDate);
    }
}

輸出結果爲:

"Sep 15, 2017 10:38:35 PM"

前面的代碼是將Java的Date類對象序列化爲JSON表示。在前面的部分中,您已經瞭解瞭如何使用GSON來序列化和反序列化對象,以及它如何爲用戶定義的Java類對象提供定製化的序列化器和反序列化器。讓咱們看看它是如何工做的。

另外,GSON還爲開發人員提供了可定製的序列化的特性。

下面的代碼是一個可定製序列化器的示例:

public class StudentTypeSerializer implements JsonSerializer<Student> {

    @Override
    public JsonElement serialize(Student student, Type type,
                                 JsonSerializationContext context) {
        JsonObject obj = new JsonObject();

        obj.addProperty("studentname", student.getName());
        obj.addProperty("subjecttaken", student.getSubject());
        obj.addProperty("marksecured", student.getMark());

        return obj;
    }
}

下面的代碼是一個自定義反序列化器的例子:

class StudentTypeDeserializer implements JsonDeserializer<Student> {

    @Override
    public Student deserialize(JsonElement jsonelment, Type type,
                               JsonDeserializationContext context) throws JsonParseException {

        JsonObject jsonObject = jsonelment.getAsJsonObject();

        Student aStudent = new Student();
        aStudent.setName(jsonObject.get("studentname").getAsString());
        aStudent.setSubject(jsonObject.get("subjecttaken").getAsString());
        aStudent.setMark(jsonObject.get("marksecured").getAsInt());

        return aStudent;
    }
}

如下代碼測試自定義序列化器和反序列化器:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class CustomSerializerFeature {

    public static void main(String[] args) {

        GsonBuilder gsonBuilder = new GsonBuilder();

        gsonBuilder.registerTypeAdapter(Student.class, new StudentTypeSerializer());

        Gson gson = gsonBuilder.create();

        Student aStudent = new Student();

        aStudent.setName("Sandeep");

        aStudent.setMark(150);

        aStudent.setSubject("Arithmetic");

        String studentJson = gson.toJson(aStudent);

        System.out.println("Custom Serializer : Json String Representation ");
        System.out.println(studentJson);

        gsonBuilder.registerTypeAdapter(Student.class, new StudentTypeDeserializer());
        Gson gsonde = gsonBuilder.create();
        Student deStudent = gsonde.fromJson(studentJson, Student.class);
        
        System.out.println("Custom DeSerializer : Java Object Creation");
        
        System.out.println("Student Name " + deStudent.getName());
        System.out.println("Student Mark " + deStudent.getMark());
        System.out.println("Student Subject " + deStudent.getSubject());
        System.out.println("is anotherStudent is type of Student " + (deStudent instanceof Student));
    }
}

輸出結果爲:

Custom Serializer : Json String Representation 
{"studentname":"Sandeep","subjecttaken":"Arithmetic","marksecured":150}
Custom DeSerializer : Java Object Creation
Student Name Sandeep
Student Mark 150
Student Subject Arithmetic
is anotherStudent is type of Student true

3. 漂亮的打印

GSON的序列化輸出的JSON表示格式緊湊。若是有大量的Java對象集合,而且每一個對象都有許多序列化的屬性,那麼它們緊湊的JSON表示的可讀性是很是差的,並且看起來很難看。

爲了解決這個問題,GsonBuilder支持漂亮的打印配置,同時爲序列化使用建立一個Gson對象。這個漂亮的打印功能經過適當的標籤縮進和新的換行來美化JSON字符串的輸出。

如下是關於格式化程序的一些重要內容:

  • JsonPrintFormatterJsonCompactFormatter是GSON中的兩種格式化類型的表示。
  • JsonCompactFormatter是GSON的默認格式化程序。
  • JsonPrintFormatter用於漂亮的打印,它不會暴露在API中。因此開發者不能修改。
  • JsonPrintFormatter支持一個默認行長度爲80個字符,兩個字符縮進,以及右側保持四個字符。
  • 能夠經過調用GsonBuildersetPrettyPrinting()方法來使用JsonPrintFormatter

具體看一個例子:

import java.util.ArrayList;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.packt.chapter.vo.Student;

 public class PrettyPrintFeature {


  public static void main(String[] args) {

    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    List<Student> listOfStudent = new ArrayList<Student>();

    Student student1 = new Student();
    student1.setName("Sandeep Kumar Patel");
    student1.setSubject("Arithmetic");
    student1.setMark(234);

    Student student2 = new Student();
    student2.setName("Sangeeta Patel");
    student2.setSubject("Geography");
    student2.setMark(214);

    listOfStudent.add(student1);
    listOfStudent.add(student2);

    String prettyJsonString = gson.toJson(listOfStudent);
    System.out.println(prettyJsonString);
  }

}

輸出結果爲:

[
  {
    "name": "Sandeep Kumar Patel",
    "subject": "Arithmetic",
    "mark": 234
  },
  {
    "name": "Sangeeta Patel",
    "subject": "Geography",
    "mark": 214
  }
]

上面的代碼將學生列表序列化爲JSON表示。它使用GsonBuilder類得到一個Gson對象。使用setPrettyPrinting()方法配置漂亮的打印。能夠看到之前的代碼的輸出已經正確地縮進,而且閱讀起來很愉快。

4. 內部類

Java內部類能夠有兩種類型:

  • 靜態內部類
  • 實例內部類

下面將看到GSON如何處理這些類型的內部類類對象的。

(1) 靜態內部類

GSON能夠隱式地序列化/反序列化靜態內部類。不須要額外的配置。

讓咱們看一個靜態內部類的例子:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

class Student {

    private String studentName;

    private int mark;

    public String getStudentName() {
        return studentName;
    }

    public void setStudentName(String studentName) {
        this.studentName = studentName;
    }

    public int getMark() {
        return mark;
    }

    public void setMark(int mark) {
        this.mark = mark;
    }

    public static class Course {

        private String courseName;

        private String duration;

        public String getCourseName() {
            return courseName;
        }

        public void setCourseName(String courseName) {
            this.courseName = courseName;
        }

        public String getDuration() {
            return duration;
        }

        public void setDuration(String duration) {
            this.duration = duration;
        }
    }
}

public class StaticNestedClassFeature {

    public static void main(String[] args) {

        Gson gson = new GsonBuilder().setPrettyPrinting().create();

        Student.Course aCourse = new Student.Course();
        aCourse.setCourseName("M.TECH.");
        aCourse.setDuration("120 hr");

        String jsonCourse = gson.toJson(aCourse);
        System.out.println(jsonCourse);

        Student.Course anotherCourse = gson.fromJson(jsonCourse, Student.Course.class);

        System.out.println("Course : " + anotherCourse.getCourseName() + "Duration : " + anotherCourse.getDuration());
    }
}

輸出結果爲:

{
  "courseName": "M.TECH.",
  "duration": "120 hr"
}
Course : M.TECH.Duration : 120 hr

在上面的代碼中,Course類是Student類內的靜態內部類。courseNameduration是兩個屬性,以及各自的getter和setter方法在。經過外部類的.操做符調用,能夠在Java中實例化一個靜態的內部類。Student.Course aCourse = new Student.Course()用來初始化內部Course類的。M.TECH.120 hr則是用來實例化它的兩個值。從輸出中能夠看出,GSON可以序列化生成Course對象的JSON表示的靜態內部類。輸出的最後一行顯示GSON成功地將其反序列化。

(2) 實例內部類

Java中的一個實例內部類能夠經過使用外部類對象來實例化。下面的代碼演示了GSON如何序列化和反序列化一個實例內部類的Java類對象:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

class Student {

    private String studentName;
    private int mark;

    public String getStudentName() {
        return studentName;
    }

    public void setStudentName(String studentName) {
        this.studentName = studentName;
    }

    public int getMark() {
        return mark;
    }

    public void setMark(int mark) {
        this.mark = mark;
    }

    public class Course {

        private String courseName;

        private String duration;

        public String getCourseName() {
            return courseName;
        }

        public void setCourseName(String courseName) {
            this.courseName = courseName;
        }

        public String getDuration() {
            return duration;
        }

        public void setDuration(String duration) {
            this.duration = duration;
        }
    }
}

public class InstanceNestedClassFeature {

    public static void main(String[] args) {

        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        Student outstudent = new Student();
        Student.Course instanceCourse = outstudent.new Course();

        instanceCourse.setCourseName("M.TECH.");
        instanceCourse.setDuration("12 hr");

        String jsonCourse = gson.toJson(instanceCourse);
        System.out.println(jsonCourse);

        Student.Course anotherCourse = gson.fromJson(jsonCourse, Student.Course.class);
        System.out.println("Course : " + anotherCourse.getCourseName() + "Duration : " + anotherCourse.getDuration());
    }
}

輸出結果爲:

{
  "courseName": "M.TECH.",
  "duration": "12 hr"
}
Course : M.TECH.Duration : 12 hr

在前面的代碼中,Course是一個實例內部類,有兩個字段和它們的getter和setter方法。Course對象的nstanceccourse是使用外部類對象outstudent實例化的。這個內部類對象被放置到序列化和反序列化中,從而在控制檯上產生結果。在反序列化過程當中,fromJson()方法使用Student做爲第二個參數。固然,它幫助GSON成功地將其反序列化到內部類對象中。

5. 數組

GSON支持將Java數組轉換爲JSON表示。

讓咱們來看一個數組的例子:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class ArrayFeature {

    public static void main(String[] args) {

        Gson gson = new GsonBuilder().create();

        int[] numberArray = { 121, 23, 34, 44, 52 };

        String[] fruitsArray = { "apple", "oranges", "grapes" };

        String jsonNumber = gson.toJson(numberArray);
        String jsonString = gson.toJson(fruitsArray);

        System.out.println(jsonNumber);
        System.out.println(jsonString);

        int[] numCollectionArray = gson.fromJson(jsonNumber, int[].class);
        String[] fruitBasketArray = gson.fromJson(jsonString, String[].class);

        System.out.println("Number Array Length " + numCollectionArray.length);
        System.out.println("Fruit Array Length " + fruitBasketArray.length);

    }

}

輸出結果爲:

[121,23,34,44,52]
["apple","oranges","grapes"]
Number Array Length 5
Fruit Array Length 3

6. 泛型

GSON使用com.google.gson.reflect.TypeToken來支持泛型類型的Java類對象,用於序列化和反序列化。使用TypeToken類的目的是使用Java泛型類型的類型擦除的特性。

類型擦除發生在編譯期,在這裏,Java泛型類型被徹底刪除,以產生字節碼。所以,在將JSON字符串反序列化爲泛型Java類時,它可能會沒有正確地反序列化。

下面的代碼演示了泛型類型序列化/反序列化以及TypeToken類是用來解決這個問題:

import java.lang.reflect.Type;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

class StudentGeneric<T, E> {

    T mark;

    E name;

    public T getMark() {
        return mark;
    }

    public void setMark(T mark) {
        this.mark = mark;
    }

    public E getName() {
        return name;
    }

    public void setName(E name) {
        this.name = name;
    }
}

public class GenericTypeFeature {

    @SuppressWarnings("unchecked")
    public static void main(String[] args) {

        Gson gson = new Gson();
        StudentGeneric<Integer, String> studGenericObj1 = new StudentGeneric<Integer, String>();
        studGenericObj1.setMark(25);
        studGenericObj1.setName("Sandeep");

        String json = gson.toJson(studGenericObj1);
        System.out.println("Serialized Output :");
        System.out.println(json);

        StudentGeneric<Integer, String> studGenericObj2 = gson.fromJson(json, StudentGeneric.class);
        System.out.println("DeSerialized Output :");
        System.out.println("Mark : " + studGenericObj2.getMark());

        Type studentGenericType = new TypeToken<StudentGeneric<Integer, String>>() {}.getType();
        
        StudentGeneric<Integer, String> studGenericObj3 = gson.fromJson(json, studentGenericType);
        System.out.println("TypeToken Use DeSerialized Output :");
        System.out.println("Mark : " + studGenericObj3.getMark());
    }

}

輸出結果爲:

Serialized Output :
{"mark":25,"name":"Sandeep"}
DeSerialized Output :
Mark : 25.0
TypeToken Use DeSerialized Output :
Mark : 25

在上面的代碼中,StudentGeneric類接受兩個泛型參數,並有各自的getter和setter方法。StudentGeneric類對象使用IntegerString做爲markname的類型來建立的。在序列化時,mark被初始化爲25,但反序列化輸出顯示爲25.0,這是一個不正確的值,由於類型擦除屬性在編譯時從類中刪除了泛型類型的參數。使用TypeToken類來解決這個問題。getType()方法返回具備泛型參數的原始類類型,它幫助GSON正確地反序列化對象,並將正確值輸出爲25。

7. 對 null 對象的支持

GSON也可以對null對象進行序列化/反序列化的JSON表示。

讓咱們看一個空對象的例子:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class NullSupportFeature {

    public static void main(String[] args) {
        Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create();

        Student aStudent = new Student();
        aStudent.setName("Sandeep Kumar Patel");
        aStudent.setSubject(null);
        aStudent.setMark(234);

        String studentJson = gson.toJson(aStudent);

        System.out.println(studentJson);

        Student javaStudentObject = gson.fromJson(studentJson, Student.class);

        System.out.println("Student Subject: " + javaStudentObject.getSubject());
        System.out.println("Student Name: " + javaStudentObject.getName());
    }
}

輸出結果爲:

{
  "name": "Sandeep Kumar Patel",
  "subject": null,
  "mark": 234
}
Student Subject:null
Student Name:Sandeep Kumar Patel

8. 版本支持

GSON提供了版本化的序列化/反序列化的Java對象的JSON表示。這有助於迭代開發和發佈值對象。GSON API提供了一種機制來知足這些不一樣版本數據的請求。

讓咱們看一個版本支持的例子:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Since;

@Since(1.0)
class Student {

    private String name;

    private String subject;

    private int mark;

    @Since(1.1)
    private String gender;

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public int getMark() {
        return mark;
    }

    public void setMark(int mark) {
        this.mark = mark;
    }
}

public class VersionSupportFeature {

    public static void main(String[] args) {

        Student aStudent = new Student();
        aStudent.setName("Sandeep Kumar Patel");
        aStudent.setSubject("Algebra");
        aStudent.setMark(534);
        aStudent.setGender("Male");

        System.out.println("Student json for Version 1.0 ");
        Gson gson = new GsonBuilder().setVersion(1.0).setPrettyPrinting().create();
        String jsonOutput = gson.toJson(aStudent);
        System.out.println(jsonOutput);

        System.out.println("Student json for Version 1.1 ");
        gson = new GsonBuilder().setVersion(1.1).setPrettyPrinting().create();
        jsonOutput = gson.toJson(aStudent);
        System.out.println(jsonOutput);
    }
}

輸出結果爲:

Student json for Version 1.0 
{
  "name": "Sandeep Kumar Patel",
  "subject": "Algebra",
  "mark": 534
}
Student json for Version 1.1 
{
  "name": "Sandeep Kumar Patel",
  "subject": "Algebra",
  "mark": 534,
  "gender": "Male"
}

9. 對無參數構造方法的支持

儘管Java對象進行序列化/反序列化或JSON字符串,GSON建立一個默認實例的類的構造方法。有一個默認的Java類的無參數構造方法是很好的。若是一個類沒有默認構造函數,GSON提供一個class.google.gson.InstanceCreator接口實現來處理它。

方法 詳細說明
createInstance 參數:java.lang.reflect.Type類的實例;返回值:T類型的默認對象實例,引用對象實例的類類型。

讓咱們看一個無參構造方法的例子:

import java.lang.reflect.Type;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.InstanceCreator;

class Employee {

    private String name;
    private Salary salary;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Salary getSalary() {
        return salary;
    }

    public void setSalary(Salary salary) {
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Employee [name=" + name + ", salary=" + salary + " ]";
    }
}

class Salary {

    private int salaryAmount;

    Salary(int salary) {
        this.salaryAmount = salary;
    }

    @Override
    public String toString() {
        return "Salary [salaryAmount=" + salaryAmount + "]";
    }
}

class SalaryInstanceCreator implements InstanceCreator<Salary> {
    @Override
    public Salary createInstance(Type type) {
        return new Salary(25000);
    }
}

public class InstanceCreatorUse {

    public static void main(String[] args) {

        String jsonString = "{\"name\" :\"Sandeep\" , \"salary\": {}}";

        Gson gson = new GsonBuilder().serializeNulls().registerTypeAdapter(Salary.class, new SalaryInstanceCreator())
                .setPrettyPrinting().create();

        System.out.println(gson.fromJson(jsonString, Employee.class));
    }
}

上面的代碼演示了一個JSON字符串類型的Employee類,該字符串被反序列化爲Employee類型的對象。

  • 輸入:一個 JSON 對象:jsonString = "{\"name\" :\"Sandeep\" , \"salary\": {}}";
  • 輸出:一個 Java 對象:重寫了toString()方法:Employee [name=Sandeep, salary=Salary [salaryAmount=25000]]

使用com .google. gson.InstanceCreator來實現一個SalaryInstanceCreator類,並重寫createInstance()方法,該方法返回值25000的參數化的Salary構造方法。

這個SalaryInstanceCreator使用registerTypeAdapter()方法註冊爲GSON。

當GSON找到空的Salary字符串時,它將尋找類型Salary的默認構造方法。因爲不存在默認的Salary構造方法,因此它尋找類型適配器的GsonBuilder設置,並找到SalaryInstanceCreator。並調用createInstance()方法。

所以,當對一個空的Salary類對象進行反序列化時,GSON將得到25000做爲默認值。

10. 屬性命名的支持

該特性爲開發人員在序列化Java對象時提供自定義名稱提供了靈活性。JSON表示變得更有意義和可讀性。

GSON提供了一個具備內置屬性命名支持的FieldNamingPolicy類:

import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;

class College {

    @SerializedName("instituteName")
    private String name;

    private String[] coursesOffer;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String[] getCoursesOffer() {
        return coursesOffer;
    }

    public void setCoursesOffer(String[] coursesOffer) {
        this.coursesOffer = coursesOffer;
    }
}

public class FieldNamingFeature {

    public static void main(String[] args) {

        Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).setPrettyPrinting()
                .create();

        College aCollege = new College();
        aCollege.setName("VIT University, Vellore");
        String[] courses = { "BTECH, MTECH, BSC, MSC" };
        aCollege.setCoursesOffer(courses);

        String jsonCollege = gson.toJson(aCollege);
        System.out.println(jsonCollege);
        College anotherCollege = gson.fromJson(jsonCollege, College.class);
        System.out.println("College Name : " + anotherCollege.getName());
    }
}

輸出結果爲:

{
  "instituteName": "VIT University, Vellore",
  "CoursesOffer": [
    "BTECH, MTECH, BSC, MSC"
  ]
}
College Name : VIT University, Vellore

(1) 用戶自定義屬性命名

除了基本的屬性命名功能以外,GSON還提供了一個FieldNamingStrategy類,以使開發人員可以建立本身的屬性命名策略。如下步驟演示如何建立自定義屬性命名策略:

  • 建立一個 Java 類並實現FieldNamingStrategy接口
  • 重寫translateName方法
  • 該方法提供了自定義屬性命名策略的真正實現。GSON在處理自定義屬性名稱策略時,使用該方法中的邏輯做爲屬性名:
方法 詳細說明
translateName 參數:java.lang.reflect.Field;返回:已更改的屬性名字符串

讓咱們看一個用戶定義屬性命名的示例:

import java.lang.reflect.Field;
import com.google.gson.FieldNamingStrategy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

class College {

    private String name;

    private String[] coursesOffer;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String[] getCoursesOffer() {
        return coursesOffer;
    }

    public void setCoursesOffer(String[] coursesOffer) {
        this.coursesOffer = coursesOffer;
    }
}

class CustomFieldStrategy implements FieldNamingStrategy {

    @Override
    public String translateName(Field aField) {

        String nameOfField = aField.getName();

        return nameOfField.toUpperCase();
    }
}

public class CustomFieldNamingFeature {

    public static void main(String[] args) {

        Gson gson = new GsonBuilder().setFieldNamingStrategy(new CustomFieldStrategy()).setPrettyPrinting().create();

        College aCollege = new College();
        aCollege.setName("VIT University, Vellore");
        String[] courses = { "BTECH, MTECH, BSC, MSC" };
        aCollege.setCoursesOffer(courses);

        String jsonCollege = gson.toJson(aCollege);
        System.out.println(jsonCollege);
    }
}

輸出結果爲:

{
  "NAME": "VIT University, Vellore",
  "COURSESOFFER": [
    "BTECH, MTECH, BSC, MSC"
  ]
}

11. 屬性排除策略

GSON API也支持序列化期間的屬性排除。開發人員能夠在序列化Java對象時排除某些屬性。GSON提供了兩種不一樣的方法來實現屬性的排除:

  • 配置GsonBuilder
  • 使用註解

前面的圖形顯示了GSON中兩種不一樣的屬性排除策略方法的摘要。每一種方法都有詳細的解釋。

(1)配置GsonBuilder

GsonBuilder提供excludeFieldsWithModifiers()方法來排除屬性序列化。該方法提供了排除全部具備指定修飾符的類屬性的能力。該方法的原型特徵以下:

public GsonBuilder excludeFieldsWithModifiers(int... modifiers)
  • 輸入參數:...符號,表示入參是java.lang.reflect.Modifier類型可變參數,例如Modifier.STATICModifier.PUBLICModifier.PRIVATE
  • 返回類型:返回一個GsonBuilder類型的引用對象。

讓咱們來看一個配置GsonBuilder的示例:

import java.lang.reflect.Modifier;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

class Employee {

    private String name;
    private transient String gender;
    private static String designation;
    protected String department;

    public Employee() {
        this("Abcd Employee", "MALE", "Tech Lead", "IT Services");
    }

    @SuppressWarnings("static-access")
    public Employee(String name, String gender, String designation,
                    String department) {
        this.name = name;
        this.gender = gender;
        this.designation = designation;
        this.department = department;
    }
}

public class FieldExclusionFeature {

    public static void main(String[] args) {

        Gson gson = new Gson();

        String json = gson.toJson(new Employee("Sandeep", "Male", "Tech Lead", "IT Services"));
        System.out.println(json);

        Gson gson2 = new GsonBuilder().excludeFieldsWithModifiers().create();
        json = gson2.toJson(new Employee("Sandeep", "MALE", "Tech Lead", "IT Services"));
        System.out.println(json);

        Gson gson3 = new GsonBuilder().excludeFieldsWithModifiers(Modifier.STATIC).create();
        json = gson3.toJson(new Employee("Sandeep", "MALE", "Tech Lead", "IT Services"));
        System.out.println(json);
    }

}

輸出結果爲:

{"name":"Sandeep","department":"IT Services"}
{"name":"Sandeep","gender":"MALE","designation":"Tech Lead","department":"IT Services"}
{"name":"Sandeep","gender":"MALE","department":"IT Services"}

咱們能夠從以前的代碼中獲得三個啓示:

  • 輸出的第一行有一個Employee類JSON字符串,它有兩個屬性:namedepartment。這個輸出是因爲Gson對象,使用默認的方法建立的。所以,在序列化時,它省略了statictransient修飾的屬性。
  • 輸出的第二行有一個Employee類JSON字符串,它有四個屬性:namegenderdesignationdepartment。這個輸出是因爲Gson對象使用構造器的方式和excludeFieldWithModifiers()方法。當沒有參數傳遞時,它會序列化Employee對象中存在的全部字屬性類型。
  • 輸出的第三行有一個Employee類JSON字符串,該字符串包含三個屬性:namegenderdepartment。輸出是因爲Gson對象使用構造器的方式和excludeFieldsWithModifiers()方法。Modifier.STATIC做爲一個參數傳遞給這個方法,它不序列化Employee對象的任何靜態屬性。

(2)使用註解

GSON提供@Expose註解實如今序列化期間排除指定屬性。屬性標有@Expose註解的將序列化爲JSON表示。GSON的excludeFieldsWithoutExposeAnnotation()方法必須在配置GsonBuilder使用@Expose註解時被調用。

讓咱們來看一個使用@Expose註解的例子:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;

class Vegetable {

    private String name;
    @Expose
    private int price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

public class FieldExclusionAnnotationUse {

    public static void main(String[] args) {

        Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
                .create();
        Vegetable aVegetable = new Vegetable();
        aVegetable.setName("Potato");
        aVegetable.setPrice(26);
        String jsonVegetable = gson.toJson(aVegetable);

        System.out.println("JSON Representation of Vegetable : ");
        System.out.println(jsonVegetable);
    }
}

輸出結果爲:

JSON Representation of Vegetable : 
{"price":26}

咱們能夠從前面的代碼中得出如下幾點啓示:

  • 前一段代碼的輸出有一個帶屬性price的JSON字符串。這個輸出是因爲Gson對象使用構造器的方式和excludeFieldsWithoutExposeAnnotation()方法。
  • 序列化Java對象時,它只序列化帶有@Expose的屬性。

(3)用戶自定義屬性排除註解

GSON爲開發人員提供了靈活性,能夠建立一個自定義註解,用於排除屬性和類。下面的步驟演示瞭如何建立自定義註解:

  1. 聲明一個標記Java接口。一個標記接口是簡單的Java接口,沒有任何屬性或方法。簡而言之,一個空的Java接口是一個標記接口。該接口的名稱將用做自定義排除註解。
  2. 一個Java類來實現com.google.gson.ExclusionStrategyExclusionStrategy接口提供了兩種方法。經過實現這個接口,Java類提供了定製排除註解的功能。當GSON在序列化或反序列化並找到一個自定義註解時,它會查看實現了ExclusionStrategy接口的Java類,以找出如何處理它。

ExclusionStrategy接口提供了兩種方法:

方法名 詳細說明
shouldSkipField 參數:FieldAttributes 引用類型;返回Boolean值:true:屬性將被序列化/反序列化輸出的一部分;false:屬性將不會被序列化/反序列化輸出的一部分。
shouldSkipClass 參數:Class類的引用類型。返回Boolean值:true:類將序列化/反序列化輸出的一部分;false:類將不會被序列化/反序列化輸出的一部分。

讓咱們來看一個用戶定義的屬性排除註解的示例:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
@interface MyExclude {
}

class CustomExclusionStrategy implements ExclusionStrategy {

    private final Class<?> typeToExclude;

    CustomExclusionStrategy(Class<?> typeToExclude) {
        this.typeToExclude = typeToExclude;
    }

    public boolean shouldSkipClass(Class<?> classname) {
        return (classname == typeToExclude);
    }

    public boolean shouldSkipField(FieldAttributes f) {
        return f.getAnnotation(MyExclude.class) != null;
    }

}

class Vegetable {

    private String name;
    @MyExclude
    private int price;

    public Vegetable() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

public class UserDefinedFieldExclusion {

    public static void main(String[] args) {

        Gson gson = new GsonBuilder().setExclusionStrategies(new CustomExclusionStrategy(MyExclude.class)).create();

        Vegetable aVegetable = new Vegetable();
        aVegetable.setName("Potato");
        aVegetable.setPrice(26);
        String jsonVegetable = gson.toJson(aVegetable);

        System.out.println(jsonVegetable);
    }
}

輸出結果爲:

{"name":"Potato"}

上面的代碼執行如下步驟:

  • 使用java.lang.annotation建立用戶自定義註解@MyExclude
  • 使用帶有MyExclude.class參數的CustomExclusionStrategy類實例化一個自定義排除策略。
  • 使用setExclusionStrategies方法,GsonBuilder配置這個新的排除策略。
  • 如今,由GsonBuilder建立的Gson對象將排除帶有@MyExclude註解的字段。

12. 應用GSON

在JSON格式和它相應的語言庫GSON的發明以後,Java web應用程序的開發(客戶端與服務器端進行通訊並以JSON格式對數據進行響應)得到了大量的流行,這使得Web 2.0應用程序很是成功。

如下StudentJsonDataServlet.java展現了一個Java servlet如何返回Student類型的JSON數據,並在瀏覽器中呈現爲HTML表格:

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gson.Gson;
import com.packt.myapp.data.Student;

@WebServlet("/StudentJsonDataServlet")
public class StudentJsonDataServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public StudentJsonDataServlet() {
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        Gson gson = new Gson();

        List<Student> listOfStudent = getStudentData();

        String jsonString = gson.toJson(listOfStudent);

        response.setContentType("application/json");

        response.getWriter().write(jsonString);
    }

    /**
     * Returns List of Static Student data
     */
    private List<Student> getStudentData() {

        Student s1 = new Student();
        s1.setName("Sandeep");
        s1.setSubject("Computer");
        s1.setMark(85);

        Student s2 = new Student();
        s2.setName("John");
        s2.setSubject("Science");
        s2.setMark(85);

        Student s3 = new Student();
        s3.setName("Ram");
        s3.setSubject("Computer");
        s3.setMark(85);

        List<Student> listOfStudent = new ArrayList<Student>();
        listOfStudent.add(s1);
        listOfStudent.add(s2);
        listOfStudent.add(s3);

        return listOfStudent;
    }
}

StudentJsonDataServlet將學生的詳細信息做爲JSON字符串返回。並向瀏覽器代表,數據響應是一個json類型的頭文件,須要設置爲application/json

如下studentstableview.html是在瀏覽器中渲染servlet響應的文件:

<html>
  <head>
  <title>Students JSON Table View</title>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  </head>
  <body>
    <div id="student-data-container"></div>
    <script>
    $(document).ready(function(){

      var getStudentTableHtml, html, 

      htmlStudent, container =$('#student-data-container'),

      ajaxRequest = $.ajax({
        url: "StudentJsonDataServlet",

        dataType: "JSON",

        success: function(data){

          htmlStudent = getStudentTableHtml(data);

          container.html(htmlStudent)
        }
    }),

    getStudentTableHtml = function(data){

      html = [];

      html.push("<TABLE border='2px' cellspacing='2px'>");
      html.push("<TR>");
      html.push("<TH>NAME</TH>");
      html.push("<TH>SUBJECT</TH>");
      html.push("<TH>MARK</TH>");
      html.push("</TR>");

      $.each(data,function(index, aStudent){
        html.push("<TR>");
        html.push("<TD>");
        html.push(aStudent.name);
        html.push("</TD>");
        html.push("<TD>");
        html.push(aStudent.subject);
        html.push("</TD>");
        html.push("<TD>");
        html.push(aStudent.mark);
        html.push("</TD>");
        html.push("</TR>");
      });
      html.push("</TABLE>")

      return html.join("");
    }
  })
    </script>
  </body>
</html>

上面的代碼展現了在DOM就緒事件上調用jQuery Ajax事件。servlet使用GSON API將Student對象的列表轉換爲相應的JSON表示,並將其做爲響應內容發送到客戶端。如下截圖中的Firebug控制檯顯示了JSON對象中的Ajax請求和響應:

在獲得響應時,jQuery調用success方法來處理。做爲返回,成功處理程序調用getStudentTableHtml()方法在HTML中構建一個表格。

該方法使用for循環來迭代每一個學生JSON對象來構建表格的行。下面截圖顯示了學生JSON響應數據構建的學生詳細信息的HTML表格:

三. 你應該瞭解的幫助文檔

若是你須要相關GSON資料文檔的幫助,這裏有一些網址是很是有用的:

1. 官網網址

2. 文章和教程

3. 社區

4. 博客

相關文章
相關標籤/搜索