Google-Gson註解使用詳解

LightSun發表於2017-10-17

簡介

Gson 是一個強大的序列化和反序列化的一個json庫。可以不完全按照json格式。

各註解說明

  • 一, @Expose: 暴露的意思,作用於field, 搭配GsonBuilder使用。使用步驟:

    • 1, 假設有下面這樣一個資料實體

      public class StudentModuleImpl{
      
      private int age;
      @Expose(
             serialize = false,
             deserialize = false
      )
      private String name;
      @Expose()
      private String id;
      
      @Override
      public int getAge() {
         return age;
      }
      
      @Override
      public void setAge(int age) {
         this.age = age;
      }
      
      @Override
      public String getName() {
         return name;
      }
      
      @Override
      public void setName(String name) {
         this.name = name;
      }
      
      @Override
      public String getId() {
         return id;
      }
      
      @Override
      public void setId(String id) {
         this.id = id;
      }
      
      @Override
      public String toString() {
         return "StudentModuleImpl{" +
                 "name='" + name + '\'' +
                 ", age=" + age +
                 ", id='" + id + '\'' +
                 '}';
      }
      }複製程式碼

      2, 使用 excludeFieldsWithoutExposeAnnotation方法構造gson物件。

      Gson gson = new GsonBuilder() .excludeFieldsWithoutExposeAnnotation().create();複製程式碼

      3, 序列化資料.

      StudentModuleImpl module = new StudentModuleImpl();
         module.setName("heaven7");
         module.setId("xxx");
         module.setAge(25);
      String json = gson.toJson(module, StudentModuleImpl.class);
         log(json);複製程式碼

      得到輸出:

      {"id":"xxx"}複製程式碼

      只序列化了id屬性。why ?
      答案很簡單:

      因為這裡我們的gson使用了gsonBuilder的excludeFieldsWithoutExposeAnnotation()方法來構造.
      它表示任何沒有被@Expose註解的欄位都將被忽略, 並且即使用了@Expose但serialize=false 時也不會被序列化。
      ps: 預設Expose: serialize = true,  deserialize= true
      反序列化同理.複製程式碼
  • 二, @SerializedName (作用域field)
    這個註解只是用於對映資料的key用的。比如常用的json的key.
    上面的例子。如果在id屬性上加個@SerializedName("_id"). 將會輸出
    {"_id":"xxx"}複製程式碼
  • 三, @Since 和 @Until
    這2個註解用於表示資料序列化的最早版本since(自從),和最晚版本until(直到).
    也是搭配GsonBuilder使用的。
    使用例子:

    • 1, 假設有這樣一個資料實體.

      public class Car3 {
      
      @Since(2.0)
      private String mark;
      
      @Since(2.1) 
      private int model;
      
      @Until(1.9)
      private String type;
      
      @Until(2.1)
      private String maker;
      
      private double cost;
      
      private List<String> colors = new ArrayList<String>();
      
      public String getMark() {
      return mark;
      }
      
      public void setMark(String mark) {
      this.mark = mark;
      }
      
      public int getModel() {
      return model;
      }
      
      public void setModel(int model) {
      this.model = model;
      }
      
      public String getType() {
      return type;
      }
      
      public void setType(String type) {
      this.type = type;
      }
      
      public String getMaker() {
      return maker;
      }
      
      public void setMaker(String maker) {
      this.maker = maker;
      }
      
      public double getCost() {
      return cost;
      }
      
      public void setCost(double cost) {
      this.cost = cost;
      }
      
      public List<String> getColors() {
      return colors;
      }
      
      public void setColors(List<String> colors) {
      this.colors = colors;
      }
      
      @Override
      public String toString() {
      return "Car3 [mark=" + mark + ", model=" + model + ", type=" + type
      \+ " , maker=" + maker + ", cost=" + cost + ", colors=" + colors + "]";
      }
      }複製程式碼
    • 2, 設定屬性並序列化
      //這裡設定當前版本為2.0. 那麼since大於2.0的不被序列化和反序列化。
      //until小於2.0的不被序列化和反序列化。
      Gson gson = new GsonBuilder().setVersion(2.0).create();

      Car3 car = new Car3();
      car.setMark("AUDI");
      car.setModel(2014); //2,1
      car.setType("DIESEL");
      car.setMaker("AUDI GERMANY");
      car.setCost(55000);
      
      car.getColors().add("GREY");
      car.getColors().add("BLACK");
      car.getColors().add("WHITE");
      
      /* Serialize */
      String jsonString = gson.toJson(car);
      System.out.println("Serialized jsonString : " + jsonString);複製程式碼

得到輸出:

Serialized jsonString : {"mark":"AUDI","maker":"AUDI GERMANY","cost":5555.0,"colors":["GREY","BLACK","WHITE"]}複製程式碼

然後我們發現module, type屬性並沒有序列化。原因就是

 @Since(2.1)  //since 大於設定的2.0
 private int model;
 @Until(1.9) //until 小雨設定的2.0
 private String type;複製程式碼
  • 四, @JsonAdapter.
    這個註解的作用可以自定義序列化和反序列化。比如你想給你的HashMap資料自定義序列化和反序列化。
    作用範圍: class 和 field. 就是說可以放在類和欄位上.
    比如上面的Car3. 我可以用自定義的TypeAdapter.。

    public class Car3TypeAdapter extends TypeAdapter<Car3> {
    
      @Override
      public void write(JsonWriter writer, Car3 car) throws IOException {
          writer.beginObject();
    
          writer.name("mark").value(car.getMark());
          writer.name("model").value(car.getModel());
          writer.name("type").value(car.getType());
          writer.name("maker").value(car.getMaker());
    
          double costIncludingVAT = car.getCost() + 0.21 * car.getCost();// Add 21% VAT
          writer.name("cost").value(costIncludingVAT);
    
          writer.name("colors");
          writer.beginArray();
          for (String color : car.getColors()) {
              writer.value(color);
          }
          writer.endArray();
          writer.endObject(); }
    
      @Override
      public Car3 read(JsonReader reader) throws IOException {
    
          Car3 car = new Car3();
          reader.beginObject();
          while (reader.hasNext()) {
              String name = reader.nextName();
              if (name.equals("mark")) {
                  car.setMark(reader.nextString());
              } else if (name.equals("model")) {
                  car.setModel(reader.nextInt());
              } else if (name.equals("type")) {
                  car.setType(reader.nextString());
              } else if (name.equals("maker")) {
                  car.setType(reader.nextString());
              } else if (name.equals("cost")) {
                  double cost = reader.nextDouble();
                  double costExcludingVAT = cost / 1.21;
                  car.setCost(costExcludingVAT);  //Remove VAT 21%
              } else if (name.equals("colors") && reader.peek() != JsonToken.NULL) {
                  car.setColors(readStringArray(reader));
              } else {
                  reader.skipValue();
              }
          }
          reader.endObject();
          return car;          }
    public List<String> readStringArray(JsonReader reader) throws IOException {
          List<String> colors = new ArrayList<String>();
    
          reader.beginArray();
          while (reader.hasNext()) {
              colors.add(reader.nextString());
          }
          reader.endArray();
          return colors;
      }
    }複製程式碼

    然後加上註解

    @JsonAdapter(Car3TypeAdapter.class)
    public class Car3 {
     ......
    }複製程式碼

    這樣。以後序列化和反序列化就會用靜態註冊的Car3TypeAdapter. 需要注意的是,
    可以動態註冊TypeAdapter. 而且動態註冊優先順序高於靜態註冊的。

    public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter)複製程式碼

    至此,註解是基本說完了。

  • 實際上,gson還有更加豐富的api.比如

    //from GsonBuilder
    public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies);
    public GsonBuilder addSerializationExclusionStrategy(ExclusionStrategy strategy) 
    public GsonBuilder addDeserializationExclusionStrategy(ExclusionStrategy strategy)
    //通過上面3個方法 可以自定義序列化和反序列化的不包含策略。複製程式碼

    當然還有。

    //註冊 建立TypeAdapter的工廠
    public GsonBuilder registerTypeAdapterFactory(TypeAdapterFactory factory)
    //註冊 建立TypeAdapter(層級關係)的工廠
    public GsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter)複製程式碼

    這個我就不細說了。 google一下很多教程。

thanks for reading !!!

相關文章