赞
踩
Gson(又称Google Gson)是Google公司发布的一个开放源代码的Java库,主要用途为序列化Java对象为JSON字符串,或反序列化JSON字符串成Java对象。
Gson官网:gson Gson源码地址:google/gson
使用Maven导入依赖:
- <dependency>
- <groupId>com.google.code.gson</groupId>
- <artifactId>gson</artifactId>
- <version>2.8.5</version>
- </dependency>
Gradle导入依赖:
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
使用Gson的第一步是创建一个Gson对象,创建爱你Gson对象有两种方式:
示例如下:
Gson gson = new Gson();
示例如下:
- GsonBuilder builder = new GsonBuilder();
- Gson gson = builder.create();
下面会用到这个实体类:
- public class Employee {
- private int id;
- private String firstName;
- private String lastName;
- private String email;
- //省略getter/setter,构造方法,toSting方法
- }
在Gson中的序列化即将Java对象转换为其JSON表示形式。 为了进行序列化,首先需要一个Gson对象,该对象可以处理转换。 接下来,需要调用函数toJson()方法并传入Employee对象。
- Employee emp = new Employee(1001, "Lokesh", "Gupta", "howtodoinjava@gmail.com");
-
- Gson gson = new Gson();
-
- String jsonString = gson.toJson(emp);
-
- System.out.println(jsonString);
运行结果:
在这里插入图片描述
在Gson进行反序列指的是将JSON字符串转换为Java对象。 为了进行反序列化,我们需要使用Gson对象调用fromJson()函数,并在解析完成后传递两个参数,即JSON字符串和所需的Java类型。
- String jsonString = "{'id':1001, 'firstName':'Lokesh', 'lastName':'Gupta', 'email':'howtodoinjava@gmail.com'}";
-
- Gson gson = new Gson();
-
- Employee empObject = gson.fromJson(jsonString, Employee.class);
-
- System.out.println(empObject);
运行结果:
默认情况下,Gson以紧凑格式打印JSON,即字段名称及其值,对象字段以及JSON输出中数组内的对象等之间将没有空格。
{"id":1,"firstName":"Lokesh","lastName":"Gupta", "emailId":"howtogoinjava@gmail.com"}
但是,这种紧凑的JSON可能很难阅读。因此,GSON提供了一个漂亮的打印选项,可以在其中打印JSON,以便于更加方便阅读。
- Gson gson = new GsonBuilder()
- .setPrettyPrinting()
- .create();
-
- Employee employeeObj = new Employee(1, "Lokesh", "Gupta", "howtogoinjava@gmail.com");
-
- System.out.println(gson.toJson(employeeObj));
复制
运行结果:
在这里插入图片描述
users.json:
- [
- {
- "name": "Alex",
- "id": 1
- },
- {
- "name": "Brian",
- "id": 2
- },
- {
- "name": "Charles",
- "id": 3
- }
- ]
User.java:
- public class User
- {
- private long id;
- private String name;
-
- public long getId() {
- return id;
- }
- public void setId(long id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
-
- @Override
- public String toString() {
- return "User [id=" + id + ", name=" + name + "]";
- }
- }
复制
将json数组反序列化为Java对象数组:
- String userJson = "[{'name': 'Alex','id': 1}, "
- + "{'name': 'Brian','id':2}, "
- + "{'name': 'Charles','id': 3}]";
-
- Gson gson = new Gson();
-
- User[] userArray = gson.fromJson(userJson, User[].class);
-
- for(User user : userArray) {
- System.out.println(user);
- }
运行结果:
在这里插入图片描述
将json数组反序列化为根–到Java对象列表:
- String userJson = "[{'name': 'Alex','id': 1}, " + "{'name': 'Brian','id':2}, " + "{'name': 'Charles','id': 3}]";
-
- Gson gson = new Gson();
-
- java.lang.reflect.Type userListType = new TypeToken<ArrayList<User>>() {
- }.getType();
-
- ArrayList<User> userArray = gson.fromJson(userJson, userListType);
-
- for (User user : userArray) {
- System.out.println(user);
- }
运行结果:
在这里插入图片描述
如果Json数组是非根对象,则Gson可以将JSON数组解析为成员变量。我们可以按通常的方式使用fromJson()方法,将json数组解析为所需的Java数组或列表。
department.json:
- {
- "id" : 1,
- "name" : "HR",
- "users" : [
- {
- "name": "Alex",
- "id": 1
- },
- {
- "name": "Brian",
- "id": 2
- },
- {
- "name": "Charles",
- "id": 3
- }
- ]
Department.java:
- public class Department {
- private long id;
- private String name;
- private User[] users;
- //省略getter/setter、构造方法、toString方法
- }
JsonArrayToMemberArray.java:
- String departmentJson = "{'id' : 1, "
- + "'name': 'HR',"
- + "'users' : ["
- + "{'name': 'Alex','id': 1}, "
- + "{'name': 'Brian','id':2}, "
- + "{'name': 'Charles','id': 3}]}";
-
- Gson gson = new Gson();
-
- Department department = gson.fromJson(departmentJson, Department.class);
-
- System.out.println(department);
运行结果:
在这里插入图片描述
将json数组反序列化为List类型成员变量。
Department2.java:
- public class Department2 {
- private long id;
- private String name;
- private List<User> users;
- //省略getter/setter、构造方法、toString方法
- }
复制
转换:
- String departmentJson = "{'id' : 1, "
- + "'name': 'HR',"
- + "'users' : ["
- + "{'name': 'Alex','id': 1}, "
- + "{'name': 'Brian','id':2}, "
- + "{'name': 'Charles','id': 3}]}";
-
- Gson gson = new Gson();
-
- Department2 department = gson.fromJson(departmentJson, Department2.class);
-
- System.out.println(department);
运行结果:
在这里插入图片描述
使用Gson.toJson()方法将HashSet序列化为JSON:
- Set<String> userSet = new HashSet<String>();
- userSet.add("Alex");
- userSet.add("Brian");
- userSet.add("Charles");
-
- Gson gson = new Gson();
-
- String jsonString= gson.toJson(userSet);
-
- System.out.println(jsonString);
运行结果:
在这里插入图片描述
使用Gson.fromJson()方法和TypeToken将JSON反序列化为HashSet:
- String jsonString = "['Alex','Brian','Charles','Alex']";
-
- Gson gson = new Gson();
-
- java.lang.reflect.Type setType = new TypeToken<HashSet<String>>(){}.getType();
-
- Set<String> userSet = gson.fromJson(jsonString, setType);
-
- System.out.println(userSet);
运行结果:
在这里插入图片描述
Gson中实现的默认行为是忽略空对象字段。
例如,如果在Employee对象中未指定电子邮件(即email为null),则电子邮件将不会被序列化JSON输出。Gson会忽略null字段,因为此行为允许使用更紧凑的JSON输出格式。
要配置Gson实例以输出null,我们必须使用GsonBuilder对象的serializeNulls()。
- Gson gson = new GsonBuilder()
- .serializeNulls()
- .create();
应用程序随着时间变化,模型类也随之变化。有时候更新/删除字段可能会被打断。
所有这些更改都可以使用@Since注释进行标记,以跟踪模型类,在这些系统使用反序列化JSON数据进行交换时,与其他系统的应用程序交互不会中断。
在Gson中,可以使用@Since注释维护同一对象的多个版本。可以在类,字段以及将来的方法中使用此注释。它采用单个参数– ignoreVersionsAfter。
当我们为Gson实例配置版本号“ M.N”时,所有标记有版本大于M.N的类字段都将被忽略。例如,如果我们将Gson配置为版本号“ 1.2”,则所有版本号更高的字段(例如1.3、1.4…)都将被忽略。
- @Since(1.2)
- private String email;
在Employee类下面,我们对三个字段进行了版本控制,即firstName,lastName和email。
- public class Employee
- {
- private Integer id;
-
- @Since(1.0)
- private String firstName;
-
- @Since(1.1)
- private String lastName;
-
- @Since(1.2)
- private String email;
- }
要创建使用过@Since注解的Gson实例,需要使用GsonBuilder.setVersion()方法:
- Gson gson = new GsonBuilder()
- .setVersion(1.1)
- .create();
让序列号以上的Employee对象序列化。
- Employee employeeObj = new Employee(1, "Lokesh", "Gupta", "howtogoinjava@gmail.com");
-
- Gson gson = new GsonBuilder()
- .setVersion(1.1)
- .setPrettyPrinting()
- .create();
-
- System.out.println(gson.toJson(employeeObj));
输出:
- {
- "id": 1,
- "firstName": "Lokesh",
- "lastName": "Gupta"
- }
我们将JSON字符串反序列化为版本号为Employee的对象。
- String json = "{'id': 1001, "
- + "'firstName': 'Lokesh',"
- + "'lastName': 'Gupta',"
- + "'email': 'howtodoinjava@gmail.com'}";
-
- Gson gson = new GsonBuilder()
- .setVersion(1.1)
- .setPrettyPrinting()
- .create();
-
- Employee employeeObj = gson.fromJson(json, Employee.class);
-
- System.out.println(employeeObj);
输出:
Employee [id=1001, firstName=Lokesh, lastName=Gupta, email=null]
在此Gson @SerializedName示例中,演示在序列化和反序列化过程中更改json和java对象之间的字段名称。
默认情况下,我们假设Java模型类和JSON将具有完全相同的字段名称。
但有时情况并非如此,某些名称有所不同。现在我们必须将json中的someName映射到Java类中的someOtherName。这是@SerializedName注解用到的地方。
@SerializedName注解指示带注解的成员变量应使用提供的名称值作为其字段名称序列化为JSON。此注解将覆盖可能一直在使用GsonBuilder类的任何FieldNamingPolicy,包括默认的字段命名策略。
请注意,在此注解中指定的值必须是有效的JSON字段名称。
注解包含属性
让我们以只有四个字段的Employee类为例。我们要创建一个JSON,其中“ email”被写为字段名“ emailId”:
- public class Employee
- {
- private Integer id;
- private String firstName;
- private String lastName;
-
- @SerializedName(value = "emailId", alternate = "emailAddress")
- private String email;
- }
让我们序列化一个Employee实例并查看JSON输出:
- Employee emp = new Employee(1001, "Lokesh", "Gupta", "howtodoinjava@gmail.com");
-
- Gson gson = new GsonBuilder().setPrettyPrinting().create();
-
- System.out.println(gson.toJson(emp));
输出:
- {
- "id": 1001,
- "firstName": "Lokesh",
- "lastName": "Gupta",
- "emailId": "howtodoinjava@gmail.com"
- }
在将JSON反序列化为Java类的过程中映射不同的字段名称:
Json:
- {
- "id": 1001,
- "firstName": "Lokesh",
- "lastName": "Gupta",
- "email": "howtodoinjava@gmail.com",
- "emailAddress": "admin@gmail.com"
- }
Main.java:
- String json = "{'id': 1001,"
- + "'firstName': 'Lokesh',"
- + "'lastName': 'Gupta',"
- + "'email': 'howtodoinjava@gmail.com',"
- + "'emailAddress': 'admin@gmail.com'}";
-
- Gson gson = new GsonBuilder().setPrettyPrinting().create();
-
- Employee emp = gson.fromJson(json, Employee.class);
-
- System.out.println(emp);
输出:
Employee [id=1001, firstName=Lokesh, lastName=Gupta, email=admin@gmail.com]
Gson允许我们从Java类中排除或忽略不希望包含在序列化和反序列化中的字段。
Gson支持许多内置机制,用于排除顶级类,字段和字段类型。
GSON @Expose注解(com.google.gson.annotations.Expose)可用于标记对象序列化或反序列化时是否公开(包括活不包括)的字段。
@Expose注释在要显式指定应进行序列化或反序列化的所有字段的编程方式中很有用。
@Expose是可选的,并提供两个配置参数:
- @Expose(serialize = false)
- private String lastName;
-
- @Expose (serialize = false, deserialize = false)
- private String emailAddress;
复制
如果我们使用 new Gson() 创建Gson并执行toJson() 和 fromJson() 方法,则@Expose将不会对序列化和反序列化产生任何影响。要使用此批注,我们必须使用GsonBuilder类及其excludeFieldsWithoutExposeAnnotation()方法创建Gson实例。
- Gson gson = new GsonBuilder()
- .excludeFieldsWithoutExposeAnnotation()
- .create();
复制
默认情况下,如果我们仅将字段标记为瞬时态,则Gson会将字段从序列化和反序列化中排除。
请记住,它无法阻止单向转换。它同时阻止了两者。
transient 具有与@Expose相同的效果(serialize = false,deserialize = false)。
- @Expose(serialize = false)
- private String lastName;
-
- private transient String emailAddress;
复制
通过使用GsonBuilder的excludeFieldsWithModifiers()方法,我们可以排除具有某些公共修饰符的字段。
例如,我们要排除一个类的所有静态成员,我们可以这样创建Gson对象:
- Gson gson = new GsonBuilder()
- .excludeFieldsWithModifiers(Modifier.STATIC)
- .create();
我们可以使用任意数量的Modifier常量来“ excludeFieldsWithModifiers”方法。例如:
- Gson gson = new GsonBuilder()
- .excludeFieldsWithModifiers(Modifier.STATIC,
- Modifier.TRANSIENT,
- Modifier.VOLATILE)
- .create();
如果以上任何一种技术都不适合我们,那么我们可以创建自己的策略。
ExclusionStrategy用于确定是否应将字段或顶级类作为JSON输出/输入的一部分进行序列化或反序列化。
例如,在ExclusionStrategy定义下面,将排除所有使用@Hidden注释注释的字段:
- //public @interface Hidden {
- // some implementation here
- //}
-
- // Excludes any field (or class) that is tagged with an "@Hidden"
- public class HiddenAnnotationExclusionStrategy implements ExclusionStrategy
- {
- public boolean shouldSkipClass(Class<?> clazz) {
- return clazz.getAnnotation(Hidden.class) != null;
- }
-
- public boolean shouldSkipField(FieldAttributes f) {
- return f.getAnnotation(Hidden.class) != null;
- }
- }
要使用此排除策略,在GsonBuilder对象中进行设置:
- GsonBuilder builder = new GsonBuilder();
- builder.setExclusionStrategies( new HiddenAnnotationExclusionStrategy() );
-
- Gson gson = builder.create();
对于简单的用例,使用'Gson gson = new Gson();' 标准配置就足够了。 但是,如果打算自定义Gson的行为,则可以使用GsonBuilder自定义的配置来创建新的Gson实例。
GsonBuilder类提供一个.create()方法,该方法返回一个Gson实例。
Gson gson = new GsonBuilder().create();
默认情况下,Gson将创建紧凑的JSON字符串。这对于减少通过网络传输的数据量非常有用。
但是,这种紧凑的JSON对开发人员进行开发/调试应用程序时不友好。使用漂亮的打印来格式化JSON输出:
- Gson gson = new GsonBuilder()
- .setPrettyPrinting()
- .create();
FieldNamingPolicy枚举在序列化期间为JSON字段名称提供了几种标准命名约定。
它有助于Gson实例将Java字段名称正确转换为所需的JSON字段名称。
注意:以下任何命名约定均不会影响以@SerializedName注释的字段。我们将验证使用User类的每个策略生成的名称。
User.java:
- public class User
- {
- private int id;
- private String first_Name;
- private String lastName;
- private String _email;
- }
如何使用FieldNamingPolicy:
- User user = new User(1, "Lokesh", "Gupta", "admin@howtodoinjava.com");
-
- Gson gson = new GsonBuilder()
- .setFieldNamingPolicy(FieldNamingPolicy.IDENTITY)
- .setPrettyPrinting().create();
-
- System.out.println(gson.toJson(user));
以下演示每种命名策略下转换的不同的名称。
使用此命名策略字段名称不变。这个是默认的策略:
- {
- "id": 1,
- "first_Name": "Lokesh",
- "lastName": "Gupta",
- "_email": "admin@howtodoinjava.com"
- }
Gson会将Java字段名称从其驼峰大小写形式修改为小写的字段名称,其中每个单词都用破折号(-)分隔。
- {
- "id": 1,
- "first_-name": "Lokesh",
- "last-name": "Gupta",
- "_email": "admin@howtodoinjava.com"
- }
Gson会将Java字段名称从其驼峰大小写形式修改为小写的字段名称,其中每个单词都用点(.)分隔:
- {
- "id": 1,
- "first_.name": "Lokesh",
- "last.name": "Gupta",
- "_email": "admin@howtodoinjava.com"
- }
Gson会将Java字段名称从其驼峰大小写形式修改为小写的字段名称,其中每个单词都用下划线(_)分隔。
- {
- "id": 1,
- "first__name": "Lokesh",
- "last_name": "Gupta",
- "_email": "admin@howtodoinjava.com"
- }
Gson将确保序列化为JSON格式的Java字段名称的第一个“字母”大写:
- {
- "Id": 1,
- "First_Name": "Lokesh",
- "LastName": "Gupta",
- "_Email": "admin@howtodoinjava.com"
- }
Gson将确保在将Java字段名称的第一个“字母”序列化为JSON格式时将其大写,并且单词之间将使用空格分隔:
- {
- "Id": 1,
- "First_ Name": "Lokesh",
- "Last Name": "Gupta",
- "_Email": "admin@howtodoinjava.com"
- }
默认情况下,Gson会在序列化过程中忽略null值。但是,有时我们想序列化具有空值的字段,以便它必须出现在JSON中。为此,可以使用serializeNulls()方法:
- Employee employeeObj = new Employee(1, "Lokesh", "Gupta", null);
-
- Gson gson = new GsonBuilder()
- .serializeNulls()
- .setPrettyPrinting().create();
-
- System.out.println(gson.toJson(employeeObj));
输出:
- {
- "id": 1,
- "firstName": "Lokesh",
- "lastName": "Gupta",
- "emailId": null
- }
ExclusionStrategy用于确定是否应将字段或顶级类作为JSON输出/输入的一部分进行序列化或反序列化。
shouldSkipField(attribute)方法也是相同的规则。
在下面的示例中,使用@NPI注解和属于Account类的实例的成员字段不会进行序列化和反序列化。
- Gson gson = new GsonBuilder()
- .setExclusionStrategies(new ExclusionStrategy() {
- @Override
- public boolean shouldSkipField(FieldAttributes f) {
- return f.getAnnotation(NPI.class) != null;
- }
-
- @Override
- public boolean shouldSkipClass(Class<?> clazz) {
- return clazz.getAnnotation(Account.class) != null;
- }
- })
- .setPrettyPrinting()
- .create();
在反序列化期间,Gson使用了一个宽松的JsonReader类。这意味着它仅接受兼容的JSON输入。
如果JSON违反结构规则之一,它将抛出MalformedJsonException。如果我们将lenient设置为true,则它将忽视某些违规行为,并尝试读取格式不正确的JSON。
- Gson gson = new GsonBuilder()
- .setLenient()
- .setPrettyPrinting().create();
使用Gson JsonReader类,该类是基于拉式的流JSON解析器。它有助于将JSON作为令牌流读取。
在流模式下,每个JSON数据都被视为一个单独的令牌。
当我们使用JsonReader对其进行处理时,每个令牌将被顺序处理。例如,
- {
- "name":"Lokesh"
- }
在使用JsonReader进行解析时,以上JSON将生成4个令牌:
我们可以使用它的简单构造函数创建一个JsonReader实例,该实例接受java.io.Reader类型的输入流。
- String json = "{}";
- JsonReader jsonReader = new JsonReader( new StringReader(json) );
我们可以根据JSON流的来源使用以下阅读器之一:
创建包含有效JSON源的JsonReader之后,我们可以开始遍历流令牌并查看令牌值。
以下是使用JsonReader以令牌形式读取简单JSON的示例:
- import java.io.IOException;
- import java.io.StringReader;
-
- import com.google.gson.stream.JsonReader;
- import com.google.gson.stream.JsonToken;
-
- public class Main
- {
- public static void main(String[] args) throws Exception
- {
-
- String json = "{'id': 1001,'firstName': 'Lokesh','lastName': 'Gupta','email': null}";
-
- JsonReader jsonReader = new JsonReader(new StringReader(json));
- jsonReader.setLenient(true);
-
- try
- {
- while (jsonReader.hasNext())
- {
- JsonToken nextToken = jsonReader.peek();
-
- if (JsonToken.BEGIN_OBJECT.equals(nextToken)) {
-
- jsonReader.beginObject();
-
- } else if (JsonToken.NAME.equals(nextToken)) {
-
- String name = jsonReader.nextName();
- System.out.println("Token KEY >>>> " + name);
-
- } else if (JsonToken.STRING.equals(nextToken)) {
-
- String value = jsonReader.nextString();
- System.out.println("Token Value >>>> " + value);
-
- } else if (JsonToken.NUMBER.equals(nextToken)) {
-
- long value = jsonReader.nextLong();
- System.out.println("Token Value >>>> " + value);
-
- } else if (JsonToken.NULL.equals(nextToken)) {
-
- jsonReader.nextNull();
- System.out.println("Token Value >>>> null");
-
- } else if (JsonToken.END_OBJECT.equals(nextToken)) {
-
- jsonReader.endObject();
-
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- jsonReader.close();
- }
- }
- }
输出:
- Token KEY >>>> id
- Token Value >>>> 1001
-
- Token KEY >>>> firstName
- Token Value >>>> Lokesh
-
- Token KEY >>>> lastName
- Token Value >>>> Gupta
-
- Token KEY >>>> email
- Token Value >>>> null
在上面的示例中:
Gson JsonParser用于将Json数据解析为JsonElement的解析树,从而解析为JsonObject。
JsonObject可用于使用JSON字符串中的相应键来访问值。
JsonParser类只有一个默认构造函数,并且不需要任何参数或配置。
JsonParser parser = new JsonParser();
JsonParser类提供3种方法来提供JSON作为源并将其解析为JsonElements树。
如果指定的文本不是有效的JSON,则这三个方法都将抛出JsonParseException和JsonSyntaxException。
在JsonElement树中解析了JSON字符串后,我们就可以使用它的各种方法来访问JSON数据元素。
例如,使用一种类型检查方法找出它代表什么类型的JSON元素:
- jsonElement.isJsonObject();
- jsonElement.isJsonArray();
- jsonElement.isJsonNull();
- jsonElement.isJsonPrimitive();
我们可以使用相应的方法将JsonElement转换为JsonObject和JsonArray:
- JsonObject jsonObject = jsonElement.getAsJsonObject();
- JsonArray jsonArray = jsonElement.getAsJsonArray();
一旦有了JsonObject或JsonArray实例,就可以使用其get()方法从中提取字段。
使用JsonParser将JSON解析为JsonElement(和JsonObject),并使用键获取JSON值:
- import com.google.gson.JsonElement;
- import com.google.gson.JsonObject;
- import com.google.gson.JsonParser;
-
- public class Main
- {
- public static void main(String[] args) throws Exception
- {
- String json = "{'id': 1001, "
- + "'firstName': 'Lokesh',"
- + "'lastName': 'Gupta',"
- + "'email': 'howtodoinjava@gmail.com'}";
-
- JsonElement jsonElement = new JsonParser().parse(json);
-
- JsonObject jsonObject = jsonElement.getAsJsonObject();
-
- System.out.println( jsonObject.get("id") );
- System.out.println( jsonObject.get("firstName") );
- System.out.println( jsonObject.get("lastName") );
- System.out.println( jsonObject.get("email") );
- }
- }
输出:
- 1001
- "Lokesh"
- "Gupta"
- "howtodoinjava@gmail.com"
我们可以使用Gson实例及其fromJson()方法来获得相同的结果:
- String json = "{'id': 1001, "
- + "'firstName': 'Lokesh',"
- + "'lastName': 'Gupta',"
- + "'email': 'howtodoinjava@gmail.com'}";
-
- JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class);
-
- System.out.println(jsonObject.get("id"));
- System.out.println(jsonObject.get("firstName"));
- System.out.println(jsonObject.get("lastName"));
- System.out.println(jsonObject.get("email"));
输出:
- String json = "{'id': 1001, "
- + "'firstName': 'Lokesh',"
- + "'lastName': 'Gupta',"
- + "'email': 'howtodoinjava@gmail.com'}";
-
- JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class);
-
- System.out.println(jsonObject.get("id"));
- System.out.println(jsonObject.get("firstName"));
- System.out.println(jsonObject.get("lastName"));
- System.out.println(jsonObject.get("email"));
这是一个完整的示例,展示了如何迭代从JsonReader获得的JsonElement:
- JsonParser parser = new JsonParser();
-
- String json = "{ \"f1\":\"Hello\",\"f2\":{\"f3:\":\"World\"}}";
-
- JsonElement jsonTree = parser.parse(json);
-
- if(jsonTree.isJsonObject()){
- JsonObject jsonObject = jsonTree.getAsJsonObject();
-
- JsonElement f1 = jsonObject.get("f1");
-
- JsonElement f2 = jsonObject.get("f2");
-
- if(f2.isJsonObject()){
- JsonObject f2Obj = f2.getAsJsonObject();
-
- JsonElement f3 = f2Obj.get("f3");
- }
-
- }
Gson在默认序列化和反序列化方面提供了非常出色的功能。
不过,我们可能会遇到默认和内置自定义选项无法解决我们问题的情况。在这种情况下,我们可以通过两个接口JsonSerializer和JsonDeserializer使用自定义序列化和反序列化。
JsonSerializer.java:
- public interface JsonSerializer<T>
- {
- public JsonElement serialize(T value, Type type,
- JsonSerializationContext jsonSerializationContext) {
- }
- }
为Json创建自定义序列化程序后,我们还需要通过GsonBuilder.registerTypeAdapter(Type,Object)注册该序列化程序。
当Gson遇到指定类型的字段时,它会在序列化期间调用其回调方法serialize()。
假设我们遇到一种情况,我们必须将Java对象序列化为json,这样所有布尔值都应写为1或0,而不是打印true或false。
让我们为该要求编写自定义序列化程序。
BooleanSerializer.java:
- import com.google.gson.JsonElement;
- import com.google.gson.JsonPrimitive;
- import com.google.gson.JsonSerializationContext;
- import com.google.gson.JsonSerializer;
-
- public class BooleanSerializer implements JsonSerializer<Boolean> {
-
- public JsonElement serialize(Boolean aBoolean, Type type,
- JsonSerializationContext jsonSerializationContext)
- {
- if(aBoolean){
- return new JsonPrimitive(1);
- }
- return new JsonPrimitive(0);
- }
- }
让我们编写一个程序,使用registerTypeAdapter()注册JsonSerializer实例,并使用该程序将Java对象序列化为json。
- import com.google.gson.Gson;
- import com.google.gson.GsonBuilder;
-
- public class Main
- {
- public static void main(String[] args) throws Exception
- {
- Employee emp = new Employee(1, "Lokesh", "Gupta", "howtodoinjava@gmail.com", true);
-
- Gson gson = new GsonBuilder()
- .registerTypeAdapter(Boolean.class, new BooleanSerializer())
- .setPrettyPrinting()
- .create();
-
- String json = gson.toJson(emp);
-
- System.out.println(json);
- }
- }
注意程序输出,键“ active”的值被序列化为1:
- {
- "id": 1,
- "firstName": "Lokesh",
- "lastName": "Gupta",
- "email": "howtodoinjava@gmail.com",
- "active": 1
- }
定制反序列化器必须实现JsonDeserializer接口。JsonDeserializer接口如下所示:
JsonDeserializer.java:
- public interface JsonDeserializer<T>
- {
- public Boolean deserialize(JsonElement jsonElement,
- Type type, JsonDeserializationContext jsonDeserializationContext)
- throws JsonParseException;
- }
为Json创建自定义反序列化器之后,我们还需要通过GsonBuilder.registerTypeAdapter(Type,Object)注册此反序列化器。
当Gson遇到指定类型的字段时,它会在序列化期间调用其回调方法deserialize()。
假设某些服务将日期字段分别分为天,月和年等部分分别返回给我们。在JSON字符串中,它们可能有意义,但是在Java中,它们只有作为单个java.time.LocalDate对象的一部分时才有意义。
employee.json:
- {
- "id": 1,
- "firstName": "Lokesh",
- "lastName": "Gupta",
- "email": "howtodoinjava@gmail.com",
- "day": 11,
- "month": 8,
- "year": 2019
- }
我们要自定义反序列化并将最后三个字段组合为LocalDate对象。
我们的Employee看起来像这样。包括必要的getter和setter以及构造函数。
Employee.java:
- public class Employee
- {
- private Integer id;
- private String firstName;
- private String lastName;
- private String email;
- private LocalDate dob;
- }
自定义反序列化器类如下所示:
EmployeeDeserializer.java:
- import com.google.gson.JsonDeserializationContext;
- import com.google.gson.JsonDeserializer;
- import com.google.gson.JsonElement;
- import com.google.gson.JsonObject;
- import com.google.gson.JsonParseException;
-
- public class EmployeeDeserializer implements JsonDeserializer<Employee>
- {
- @Override
- public Employee deserialize(JsonElement json, Type typeOfT,
- JsonDeserializationContext context) throws JsonParseException
- {
- JsonObject jsonObject = json.getAsJsonObject();
-
- LocalDate localDate = LocalDate.of(
- jsonObject.get("year").getAsInt(),
- jsonObject.get("month").getAsInt(),
- jsonObject.get("day").getAsInt()
- );
-
- return new Employee(
- jsonObject.get("id").getAsInt(),
- jsonObject.get("firstName").getAsString(),
- jsonObject.get("lastName").getAsString(),
- jsonObject.get("email").getAsString(),
- localDate);
- }
- }
注册反序列化器,然后将给定的JSON解析为java对象:
Main.java:
- public class Main
- {
- public static void main(String[] args) throws Exception
- {
- String json = "{'id': 1001,"
- + "'firstName': 'Lokesh',"
- + "'lastName': 'Gupta',"
- + "'email': 'howtodoinjava@gmail.com', "
- + "'day': 11, "
- + "'month': 8, "
- + "'year': 2019}";
-
- Gson gson = new GsonBuilder()
- .registerTypeAdapter(Employee.class, new EmployeeDeserializer())
- .create();
-
- Employee employee = gson.fromJson(json, Employee.class);
-
- System.out.println(employee);
- }
- }
注意程序输出将3个单独的字段组合到单个LocalDate对象中:
- Employee [id=1001,
- firstName=Lokesh,
- lastName=Gupta,
- email=howtodoinjava@gmail.com,
- dob=2019-08-11]
参考:
【1】:Gson
【4】:GSON - Gson
【5】:GSON – Serialize and Deserialize JSON
【6】:Gson – Pretty Printing for JSON Output
【7】:GSON – Parse JSON array to Java array or list
【8】:GSON – Serialize and deserialize JSON to Set
【9】:Gson – GsonBuilder Configuration Examples
【10】:Gson @Since – Version Support
【11】:Gson @SerializedName
【12】:Gson – JsonReader
【13】:Gson – JsonReader
【14】:Gson – JsonParser
【15】:GSON - JsonParser
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。