zoukankan      html  css  js  c++  java
  • GSON速学必会

    一. GSON 简介

    GSON是一个Java语言编写的用于处理JSON数据格式的开源应用程序编程接口项目。它将Java对象转换为JSON表示。还可以用于将JSON字符串转换为等效的Java对象。

    gson包包含了JSON数据处理的所有常见类和接口。gson内部的子包reflectannotation, 和 streamreflect包包含处理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 ();
    

    前面的代码调用了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包装类(Integer LongDouble等等)、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. 博客

  • 相关阅读:
    新手找客户,牢记20句话
    我国第二套人民币纸分币明天起停止流通
    新病毒仿"熊猫烧香" 利用 Vista系统漏洞疯狂传播
    开发新客户的5个巧招
    Google推出语音本地搜索 与微软展开竞争
    最近大牛生病了
    成功创业的“六字真言”
    ios的AutoresizingMask
    ASIHttpRequest 详细解析
    How to get md5 and SHA1 in objective c (iOS sdk)
  • 原文地址:https://www.cnblogs.com/IcanFixIt/p/7549842.html
Copyright © 2011-2022 走看看