1. 程式人生 > >2018-Gson解析和建立json

2018-Gson解析和建立json

  • 概述

    本文主要講述瞭如果使用gson來解析含有陣列和物件等比較複雜的json,比如物件中含有物件,物件中有list等。首先會介紹如何在Android Studio中使用外掛方便的將json對映成物件,然後使用gson實現物件和json的相互轉化,最後會詳細介紹如何使用泛型封裝伺服器回撥。

    A Java serialization/deserialization library to convert Java Objects into JSON and back 
    一個將Java物件轉化成json的Java序列化/反序列化庫。

    gson主要是用用來解析json為物件和將物件轉化成json。

    gradle依賴

    compile 'com.google.code.gson:gson:2.8.0'
    • 1

    1 建立和json對應的物件

    這個可以使用Android Studio的外掛,這裡推薦使用GsonFormat,直接在Android Studio的設定,外掛中搜索GsonFormat,安裝之後重啟即可使用。新建一個Java類,點選選單欄的code,Generate…,輸入json字串,在左下角的setting中可以勾選split generate,可以分開生成多個物件。 
    勾選use serializedName,可以選擇自動新增serializedName註解,這是gson的註解,意思是序列化時的名字,json對映的是這個名字,而不是欄位名,不加這個註解就是對映欄位名。 
    以下面的json字串為例:

    {
      "students": [
        {
          "name": "jadyli",
          "gender": "male",
          "age": 18
        },
        {
          "name": "Juliet",
          "gender": "female",
          "age": 20
        }
      ]
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    生成的物件是

    public class StudentInfo {
    
        private List<Student> students;
    
        public List<Student> getStudents
    () { return students; } public void setStudents(List<Student> students) { this.students = students; } @Override public String toString() { return "StudentInfo{" + "students=" + students.toString() + '}'; } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    public class Student {
        private String name;
        private String gender;
        private int age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getGender() {
            return gender;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", gender='" + gender + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    這樣一個跟json對應得物件就建立好了。

    2 使用gson解析json

    2.1 解析物件

    解析物件使用fromJson(String json, Class classOfT),後面的class需要傳入具體型別。物件裡面有物件或陣列也可以自動解析哦。

    String json = "{\"students\":[{\"name\":\"jadyli\",\"gender\":\"male\",\"age\":18},
                                {\"name\":\"Juliet\",\"gender\":\"female\",\"age\":20}]}";
    StudentInfo studentInfo = new Gson().fromJson(json, StudentInfo.class);
    System.out.println(studentInfo.toString());
    • 1
    • 2
    • 3
    • 4

    2.2 解析陣列

    直接解析陣列使用fromJson(String json, Type typeOfT) 
    這個Type,可以使用TypeToken類獲得,比如new TypeToken<List<Student>>() {}.getType()。 
    這裡的例子我們要提高json的複雜度,下面這個json表示班級資訊,有兩個班級,A班和B班,每個班級有學生若干。

    [
      {
        "students": [
          {
            "name": "jadyli",
            "gender": "male",
            "age": 18
          },
          {
            "name": "Juliet",
            "gender": "female",
            "age": 20
          }
        ],
        "class": "A"
      },
      {
        "students": [
          {
            "name": "jack",
            "gender": "male",
            "age": 27
          },
          {
            "name": "Avril",
            "gender": "female",
            "age": 17
          }
        ],
        "class": "B"
      }
    ]
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    根據json建立相應的物件。我們發現,我們的json中含有Java關鍵字class,這個時候@SerializedName註解就派上用場了,我們把欄位給為clssX,同時註解裡填上真實的名字class。Student物件不變。

    public class ClassInfo {
    
        @SerializedName("class")
        private String classX;
        private List<Student> students;
    
        public String getClassX() {
            return classX;
        }
    
        public void setClassX(String classX) {
            this.classX = classX;
        }
    
        public List<Student> getStudents() {
            return students;
        }
    
        public void setStudents(List<Student> students) {
            this.students = students;
        }
    
        @Override
        public String toString() {
            return "ClassInfo{" +
                    "classX='" + classX + '\'' +
                    ", students=" + students.toString() +
                    '}';
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    解析上面的json陣列。

    List<ClassInfo> classInfoList = new Gson().fromJson("[" +
                                    "{\"students\":[{\"name\":\"jadyli\",\"gender\":\"male\",\"age\":18}," + "{\"name\":\"Juliet\",\"gender\":\"female\",\"age\":20}],\"class\":\"A\"}," +
                                    "{\"students\":[{\"name\":\"jack\",\"gender\":\"male\",\"age\":27},{\"name\":\"Avril\",\"gender\":\"female\",\"age\":17}],\"class\":\"B\"}]",
                            new TypeToken<List<ClassInfo>>() {
                            }.getType());
                    System.out.println(classInfoList.toString());
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3 使用gson生成json

    一般toJson(Object src)方法就夠用了。

    String[] names = {"jadyli", "Juliet"};
    String[] genders = {"male", "female"};
    int[] ages = {18, 20};
    List<Student> students = new ArrayList<>();
    for (int i = 0; i < names.length; i++) {
        Student student = new Student();
        student.setName(names[i]);
        student.setGender(genders[i]);
        student.setAge(ages[i]);
        students.add(student);
    }
    String jsonStr = new Gson().toJson(students);
    System.out.println(jsonStr);
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    new Gson().toJson(Object src)輸出的是沒有格式化的json字串,要是想輸出格式化了的,可以使用

    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    String jsonStr = gson.toJson(students);
    • 1
    • 2

    預設忽略空的欄位,如果不想忽略,可以使用

    Gson gson = new GsonBuilder().serializeNulls().create();
    String jsonStr = gson.toJson(students);
    • 1
    • 2

    4 特殊用法

    不對映特定成員變數 
    加上@Expose註解。然後使用的時候用如下語句建立gson物件。

    new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()
    • 1

    不對映特定修飾符的成員變數

    Gson gson = new GsonBuilder()
        .excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT, Modifier.VOLATILE)
        .create();
    • 1
    • 2
    • 3

    上面的程式碼會排除statictransientvolatile修飾的成員變數。

    指定排除策略

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    public @interface Foo {
      // Field tag only annotation
    }
    
    public class SampleObjectForTest {
      @Foo private final int annotatedField;
      private final String stringField;
      private final long longField;
      private final Class<?> clazzField;
    
      public SampleObjectForTest() {
        annotatedField = 5;
        stringField = "someDefaultValue";
        longField = 1234;
      }
    }
    
    public class MyExclusionStrategy implements ExclusionStrategy {
      private final Class<?> typeToSkip;
    
      private MyExclusionStrategy(Class<?> typeToSkip) {
        this.typeToSkip = typeToSkip;
      }
    
      public boolean shouldSkipClass(Class<?> clazz) {
        return (clazz == typeToSkip);
      }
    
      public boolean shouldSkipField(FieldAttributes f) {
        return f.getAnnotation(Foo.class) != null;
      }
    }
    
    public static void main(String[] args) {
      Gson gson = new GsonBuilder()
          .setExclusionStrategies(new MyExclusionStrategy(String.class))
          .serializeNulls()
          .create();
      SampleObjectForTest src = new SampleObjectForTest();
      String json = gson.toJson(src);
      System.out.println(json);
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    4 伺服器json回撥解析例項

    這個比較複雜,放到了下一篇部落格