使用Gson解析和创建json


  • 使用Gson解析和创建json
  • 概述
  • 创建和json对应的对象
  • 使用gson解析json
  • 1 解析对象
  • 2 解析数组
  • 使用gson生成json
  • 特殊用法
  • 服务器json回调解析实例


概述

本文主要讲述了如果使用gson来解析含有数组和对象等比较复杂的json,比如对象中含有对象,对象中有list等。首先会介绍如何在Android Studio中使用插件方便的将json映射成对象,然后使用gson实现对象和json的相互转化,最后会详细介绍如何使用泛型封装服务器回调。

如果需要手动解析请参考:Android手动创建和解析Json

gson的github地址

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 创建和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
    }
  ]
}

生成的对象是

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() +
                '}';
    }
}
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 +
                '}';
    }
}

这样一个跟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());

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"
  }
]

根据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() +
                '}';
    }
}

解析上面的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());

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);

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

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

默认忽略空的字段,如果不想忽略,可以使用

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

4 特殊用法

不映射特定成员变量
加上@Expose注解。然后使用的时候用如下语句创建gson对象。

new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()

不映射特定修饰符的成员变量

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

上面的代码会排除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);
}