GSON速学必会
转自:https://www.cnblogs.com/IcanFixIt/p/7549842.html
参考:https://www.jb51.net/article/283930.htm
一. GSON 简介
GSON是一个Java语言编写的用于处理JSON数据格式的开源应用程序编程接口项目。它将Java对象转换为JSON表示。还可以用于将JSON字符串转换为等效的Java对象。
gson
包包含了JSON数据处理的所有常见类和接口。gson
内部的子包reflect
, annotation
, 和 stream
。reflect
包包含处理Java泛型类型信息的类和接口。annotation
包包含相关的类和接口,用于对象属性的自定义名称映射。stream
包包含与读写相关的类和接口。
GSON设计的初衷如下:
- 有一个简单的转换机制,可以将Java对象转换为JSON。GSON Java项目有大量的实用方法作为api供开发人员使用。
- 允许将先前存在的不可修改的Java对象转换为JSON和从JSON转换。
- 定制对象的表示。GSON为对象字段提供了名称的自定义映射,同时将其序列化为JSON字符串。
- 提供一个紧凑和格式化的输出。默认情况下,为Java对象生成的JSON字符串是紧凑的形式。GSON提供漂亮的打印设备以使其以人类可读的格式。
1. 在 GSON 中创建你的第一个 JSON
在本节中,将学习实例化GSON及其各种方法的含义,然后是一个快速示例代码,展示包装类型Java对象的基本序列化。
步骤1 - 实例化GSON
要使用GSON库,Gson类需要实例化一个com .google.GSON
的对象。GSON对象不维护任何状态,这个特性有助于在多个地方重用GSON对象。
GSON库提供了实例化的两种方法:
- 默认方法
- 构造器使用设置方法
默认方法
在这种方法中,可以使用new
关键字实例化GSON
类对象。这种方法创建了一个没有设置的object
实例。
构造器使用设置方法
在这种方法中,可以使用GsonBuilder
类和create
方法创建一个GSON类对象:
Gson gson = new GsonBuilder ().create ();
前面的代码调用了GsonBuilder
的create
方法,它返回一个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
前面的代码演示了toJson
和fromJson
的两种方法的快速使用。
在代码的第一部分中,使用默认方法实例化了一个Gson
类对象,并使用值1
和12345.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 Scienc
,mark
为128
。然后将一个Gson
对象实例化,并将学生对象作为一个参数传递给toJson()
方法。它返回一个字符串,该字符串具有Java对象的JSON表示。该字符串作为控制台中的第一行打印。学生对象的输出JSON表示是键/值对的集合。学生类的Java属性成为JSON字符串中的键。
在代码的最后一部分中,fromJson()
方法将JSON生成的字符串作为第一个输入参数,Student.class
作为第二个参数,将JSON字符串转换回Java对象。代码的最后一行使用Student
作为第二行操作符的实例来验证由fromJson()
方法生成的Java对象是否是Student
类型的。在控制台中,它输出true
,则表示我们将得到与JSON相同的值。
2. 序列化与反序列化
GSON有一些类的隐式序列化,比如Java包装类(Integer
、Long
、Double
等等)、Java.net.url
、java.net.URI
、java.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字符串的输出。
以下是关于格式化程序的一些重要内容:
JsonPrintFormatter
和JsonCompactFormatter
是GSON中的两种格式化类型的表示。JsonCompactFormatter
是GSON的默认格式化程序。JsonPrintFormatter
用于漂亮的打印,它不会暴露在API中。所以开发者不能修改。JsonPrintFormatter
支持一个默认行长度为80个字符,两个字符缩进,以及右侧保持四个字符。- 可以通过调用
GsonBuilder
的setPrettyPrinting()
方法来使用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
类内的静态内部类。courseName
和duration
是两个属性,以及各自的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
类对象使用Integer
和String
作为mark
和name
的类型来创建的。在序列化时,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.STATIC
,Modifier.PUBLIC
和Modifier.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字符串,它有两个属性:name
和department
。这个输出是由于Gson对象,使用默认的方法创建的。因此,在序列化时,它省略了static
和transient
修饰的属性。 - 输出的第二行有一个
Employee
类JSON字符串,它有四个属性:name
、gender
、designation
和department
。这个输出是由于Gson对象使用构造器的方式和excludeFieldWithModifiers()
方法。当没有参数传递时,它会序列化Employee
对象中存在的所有字属性类型。 - 输出的第三行有一个
Employee
类JSON字符串,该字符串包含三个属性:name
、gender
和department
。输出是由于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为开发人员提供了灵活性,可以创建一个自定义注解,用于排除属性和类。下面的步骤演示了如何创建自定义注解:
- 声明一个标记Java接口。一个标记接口是简单的Java接口,没有任何属性或方法。简而言之,一个空的Java接口是一个标记接口。该接口的名称将用作自定义排除注解。
- 一个Java类来实现
com.google.gson.ExclusionStrategy
。ExclusionStrategy
接口提供了两种方法。通过实现这个接口,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. 官网网址
- 主页: http://code.google.com/p/google-gson/
- 手册和文档:http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/index.html
- 维基百科:http://en.wikipedia.org/wiki/GSON
- 源码:http://code.google.com/p/google-gson/source/checkout
- 设计文档:https://sites.google.com/site/gson/gson-design-document
- 反馈:http://code.google.com/p/google-gson/feeds
2. 文章和教程
- 谷歌提供的用户指南:https://sites.google.com/site/gson/gson-user-guide
- Mkyong的博客:http://www.mkyong.com/java/how-do-convert-java-object-to-from-json-format-gson-api/
3. 社区
- 官方论坛:https://groups.google.com/forum/?fromgroups#!forum/google-gson
- 非官方论坛:http://stackoverflow.com/questions/tagged/gson