Google Gson用法详解

文章目录

    • 一、简介
    • 二、依赖
    • 三、基本用法
    • 1、创建Gson实例
      • 1.1、new Gson()
      • 1.2、GsonBuilder.build()
    • 2、Java对象–>JSON
    • 3、JSON–>Java对象
    • 4、漂亮地输出
    • 5、JSON array --> Java array/list
      • 5.1 、 JSON array -->Java对象
      • 5.2 、JSON array–>List
      • 5.3 、JSON array–>成员变量
        • 5.3.1、数组类型成员变量
        • 5.3.2、List类型成员变量
    • 6、JSON <---->Set
      • 6.1、Set–>JSON
      • 6.2、JSON–>Set
    • 7、Null值处理
      • 7.1、如何在序列化时允许空值
    • 8、版本支持
      • 8.1、@Since注解
      • 8.2、如何使用@Since注解编写版本化的类
      • 8.3、创建具备版本支持的Gson实例
      • 8.4、实例
        • 8.4.1、 具备版本支持的序列化
        • 8.4.2、具备版本支持的反序列化
    • 9、更改Java对象和JSON的字段名映射
      • 9.1、@SerializedName
      • 9.2、序列化期时更改字段名称
      • 9.3、反序列化时更改字段名称
    • 10、排除或忽略字段
      • 10.1、@Expose注解
        • 10.1.1. 怎么用 @Expose
        • 10.1.2、创建Gson实例
      • 10.2、用修饰符排除字段
        • 10.2.1、transient 字段
        • 10.2.2、其他修饰符
      • 10.3、排除策略
    • 四、GsonBuilder
    • 1、GsonBuilder.setPrettyPrinting()–漂亮地打印JSON
    • 2、FieldNamingPolicy
      • 2.1、FieldNamingPolicy.IDENTITY
      • 2.2、FieldNamingPolicy.LOWER_CASE_WITH_DASHES
      • 2.3、FieldNamingPolicy.LOWER_CASE_WITH_DOTS
      • 2.4、FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES
      • 2.5、 FieldNamingPolicy.UPPER_CAMEL_CASE
      • 2.6、FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES
    • 3、GsonBuilder.serializeNulls()——空值的序列化
    • 4、GsonBuilder.setExclusionStrategies()
    • 5、GsonBuilder.setLenient()——宽松的JSON语法规则
    • 五、JsonReader
    • 1、JsonReader
    • 2、Tokens
    • 3、如何创建GSON JsonReader
    • 4、读取JSON流
    • 六、JsonParser
    • 1、创建JsonParser
    • 2、转化JSON
    • 3、 JsonElement, JsonObject 和JsonArray
    • 4、Gson JsonParser 示例
    • 5、使用fromJson() 获取JsonObject
    • 6、迭代JSON树结构
    • 七、自定义序列化和反序列化
    • 1、自定义序列化
      • 1.1、JsonSerializer接口
      • 1.2、自定义序列化示例
    • 2、自定义反序列化
      • 2.1、JsonDeserializer接口
      • 2.2、自定义反序列化示例

一、简介

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'1.

三、基本用法

1、创建Gson实例

使用Gson的第一步是创建一个Gson对象,创建爱你Gson对象有两种方式:

  • 使用 new Gson()
  • 创建GsonBuilder实例,使用 create() 方法

1.1、new Gson()

示例如下:

Gson gson = new Gson();

1.2、GsonBuilder.build()

示例如下:

GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();

2、Java对象–>JSON

下面会用到这个实体类:

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

运行结果:

Google Gson用法详解_工具

3、JSON–>Java对象

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

运行结果:

Google Gson用法详解_工具_02

4、漂亮地输出

默认情况下,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));

运行结果:

Google Gson用法详解_java_03

5、JSON array --> Java array/list

5.1 、 JSON array -->Java对象

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;}@Overridepublic 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);
}

运行结果:

Google Gson用法详解_字段_04

5.2 、JSON array–>List

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

运行结果:

Google Gson用法详解_json_05

5.3 、JSON array–>成员变量

如果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}]

5.3.1、数组类型成员变量

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

运行结果:

Google Gson用法详解_字段_06

5.3.2、List类型成员变量

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

运行结果:

Google Gson用法详解_json_07

6、JSON <---->Set

6.1、Set–>JSON

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

运行结果:

Google Gson用法详解_java_08

6.2、JSON–>Set

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

运行结果:

Google Gson用法详解_Gson_09

7、Null值处理

Gson中实现的默认行为是忽略空对象字段。

例如,如果在Employee对象中未指定电子邮件(即email为null),则电子邮件将不会被序列化JSON输出。Gson会忽略null字段,因为此行为允许使用更紧凑的JSON输出格式。

7.1、如何在序列化时允许空值

要配置Gson实例以输出null,我们必须使用GsonBuilder对象的serializeNulls()。

Gson gson = new GsonBuilder().serializeNulls().create();

8、版本支持

应用程序随着时间变化,模型类也随之变化。有时候更新/删除字段可能会被打断。

所有这些更改都可以使用@Since注释进行标记,以跟踪模型类,在这些系统使用反序列化JSON数据进行交换时,与其他系统的应用程序交互不会中断。

8.1、@Since注解

在Gson中,可以使用@Since注释维护同一对象的多个版本。可以在类,字段以及将来的方法中使用此注释。它采用单个参数– ignoreVersionsAfter。

当我们为Gson实例配置版本号“ M.N”时,所有标记有版本大于M.N的类字段都将被忽略。例如,如果我们将Gson配置为版本号“ 1.2”,则所有版本号更高的字段(例如1.3、1.4…)都将被忽略。

@Since(1.2)
private String email;

8.2、如何使用@Since注解编写版本化的类

在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;
}

8.3、创建具备版本支持的Gson实例

要创建使用过@Since注解的Gson实例,需要使用GsonBuilder.setVersion()方法:

Gson gson = new GsonBuilder().setVersion(1.1).create();

8.4、实例

8.4.1、 具备版本支持的序列化

让序列号以上的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"
}

8.4.2、具备版本支持的反序列化

我们将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]

9、更改Java对象和JSON的字段名映射

在此Gson @SerializedName示例中,演示在序列化和反序列化过程中更改json和java对象之间的字段名称。

9.1、@SerializedName

默认情况下,我们假设Java模型类和JSON将具有完全相同的字段名称。

但有时情况并非如此,某些名称有所不同。现在我们必须将json中的someName映射到Java类中的someOtherName。这是@SerializedName注解用到的地方。

@SerializedName注解指示带注解的成员变量应使用提供的名称值作为其字段名称序列化为JSON。此注解将覆盖可能一直在使用GsonBuilder类的任何FieldNamingPolicy,包括默认的字段命名策略。

请注意,在此注解中指定的值必须是有效的JSON字段名称。

注解包含属性

  • value –序列化或反序列化时所需的字段名称。
  • alternate–反序列化时字段的备用名称。除了“值”属性外,它还提供了更多可能的名称。如果有多个字段匹配一个属性,则Gson将使用最后处理的那个。

9.2、序列化期时更改字段名称

让我们以只有四个字段的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"
}

9.3、反序列化时更改字段名称

在将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]

10、排除或忽略字段

Gson允许我们从Java类中排除或忽略不希望包含在序列化和反序列化中的字段。

Gson支持许多内置机制,用于排除顶级类,字段和字段类型。

10.1、@Expose注解

GSON @Expose注解(com.google.gson.annotations.Expose)可用于标记对象序列化或反序列化时是否公开(包括活不包括)的字段。

@Expose注释在要显式指定应进行序列化或反序列化的所有字段的编程方式中很有用。

10.1.1. 怎么用 @Expose

@Expose是可选的,并提供两个配置参数:

  • serialize –如果为true,则在序列化时会在JSON中写出带有此注解的字段。
  • deserialize –如果为true,则从JSON反序列化带有此注解的字段。
@Expose(serialize = false) 
private String lastName;@Expose (serialize = false, deserialize = false) 
private String emailAddress;

10.1.2、创建Gson实例

如果我们使用 new Gson() 创建Gson并执行toJson() 和 fromJson() 方法,则@Expose将不会对序列化和反序列化产生任何影响。要使用此批注,我们必须使用GsonBuilder类及其excludeFieldsWithoutExposeAnnotation()方法创建Gson实例。

Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();

10.2、用修饰符排除字段

10.2.1、transient 字段

默认情况下,如果我们仅将字段标记为瞬时态,则Gson会将字段从序列化和反序列化中排除。

请记住,它无法阻止单向转换。它同时阻止了两者。

transient 具有与@Expose相同的效果(serialize = false,deserialize = false)。

@Expose(serialize = false) 
private String lastName;private transient String emailAddress;

10.2.2、其他修饰符

通过使用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();

10.3、排除策略

如果以上任何一种技术都不适合我们,那么我们可以创建自己的策略。

ExclusionStrategy用于确定是否应将字段或顶级类作为JSON输出/输入的一部分进行序列化或反序列化。

  • 对于序列化,如果shouldSkipClass(Class)或shouldSkipField(fieldAttributes)方法返回true,则该类或字段类型将不属于JSON输出。
  • 对于反序列化,如果shouldSkipClass(Class)或shouldSkipField(fieldAttributes)方法返回true,则不会将其设置为Java对象结构的一部分。

例如,在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();

四、GsonBuilder

对于简单的用例,使用’Gson gson = new Gson();’ 标准配置就足够了。 但是,如果打算自定义Gson的行为,则可以使用GsonBuilder自定义的配置来创建新的Gson实例。

GsonBuilder类提供一个.create()方法,该方法返回一个Gson实例。

Gson gson = new GsonBuilder().create();

1、GsonBuilder.setPrettyPrinting()–漂亮地打印JSON

默认情况下,Gson将创建紧凑的JSON字符串。这对于减少通过网络传输的数据量非常有用。

但是,这种紧凑的JSON对开发人员进行开发/调试应用程序时不友好。使用漂亮的打印来格式化JSON输出:

Gson gson = new GsonBuilder().setPrettyPrinting().create();

2、FieldNamingPolicy

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

以下演示每种命名策略下转换的不同的名称。

2.1、FieldNamingPolicy.IDENTITY

使用此命名策略字段名称不变。这个是默认的策略:

{"id": 1,"first_Name": "Lokesh","lastName": "Gupta","_email": "admin@howtodoinjava.com"
}

2.2、FieldNamingPolicy.LOWER_CASE_WITH_DASHES

Gson会将Java字段名称从其驼峰大小写形式修改为小写的字段名称,其中每个单词都用破折号(-)分隔。

{"id": 1,"first_-name": "Lokesh","last-name": "Gupta","_email": "admin@howtodoinjava.com"
}

2.3、FieldNamingPolicy.LOWER_CASE_WITH_DOTS

Gson会将Java字段名称从其驼峰大小写形式修改为小写的字段名称,其中每个单词都用点(.)分隔:

{"id": 1,"first_.name": "Lokesh","last.name": "Gupta","_email": "admin@howtodoinjava.com"
}

2.4、FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES

Gson会将Java字段名称从其驼峰大小写形式修改为小写的字段名称,其中每个单词都用下划线(_)分隔。

{"id": 1,"first__name": "Lokesh","last_name": "Gupta","_email": "admin@howtodoinjava.com"
}

2.5、 FieldNamingPolicy.UPPER_CAMEL_CASE

Gson将确保序列化为JSON格式的Java字段名称的第一个“字母”大写:

{"Id": 1,"First_Name": "Lokesh","LastName": "Gupta","_Email": "admin@howtodoinjava.com"
}

2.6、FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES

Gson将确保在将Java字段名称的第一个“字母”序列化为JSON格式时将其大写,并且单词之间将使用空格分隔:

{"Id": 1,"First_ Name": "Lokesh","Last Name": "Gupta","_Email": "admin@howtodoinjava.com"
}

3、GsonBuilder.serializeNulls()——空值的序列化

默认情况下,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
}

4、GsonBuilder.setExclusionStrategies()

ExclusionStrategy用于确定是否应将字段或顶级类作为JSON输出/输入的一部分进行序列化或反序列化。

  • 对于序列化,如果shouldSkipClass(Class)方法返回true,则该类或字段类型将不会在JSON中输出。
  • 对于反序列化,如果shouldSkipClass(Class)返回true,则不会将其设置为Java对象结构的一部分。

shouldSkipField(attribute)方法也是相同的规则。

在下面的示例中,使用@NPI注解和属于Account类的实例的成员字段不会进行序列化和反序列化。

Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {@Overridepublic boolean shouldSkipField(FieldAttributes f) {return f.getAnnotation(NPI.class) != null;}@Overridepublic boolean shouldSkipClass(Class<?> clazz) {return clazz.getAnnotation(Account.class) != null;}}).setPrettyPrinting().create();

5、GsonBuilder.setLenient()——宽松的JSON语法规则

在反序列化期间,Gson使用了一个宽松的JsonReader类。这意味着它仅接受兼容的JSON输入。

如果JSON违反结构规则之一,它将抛出MalformedJsonException。如果我们将lenient设置为true,则它将忽视某些违规行为,并尝试读取格式不正确的JSON。

Gson gson = new GsonBuilder().setLenient().setPrettyPrinting().create();

五、JsonReader

使用Gson JsonReader类,该类是基于拉式的流JSON解析器。它有助于将JSON作为令牌流读取。

1、JsonReader

  • JsonReader是流式JSON解析器,也是pull parser的示例。pull parser解析JSON令牌并将其推送到事件处理程序中。
  • 它有助于读取JSON(RFC 7159)编码值作为令牌流。
  • 它读取字面值(字符串,数字,布尔值和null)以及对象和数组的开始和结束定界符。
  • 令牌以深度优先顺序遍历,与JSON文档中出现的顺序相同。

2、Tokens

在流模式下,每个JSON数据都被视为一个单独的令牌。

当我们使用JsonReader对其进行处理时,每个令牌将被顺序处理。例如,

{"name":"Lokesh"
}

在使用JsonReader进行解析时,以上JSON将生成4个令牌:

  • Token 1 = {

  • Token 2 = name

  • Token 3 = Lokesh

  • Token 4 = }

3、如何创建GSON JsonReader

我们可以使用它的简单构造函数创建一个JsonReader实例,该实例接受java.io.Reader类型的输入流。

String json = "{}";
JsonReader jsonReader = new JsonReader( new StringReader(json) );

我们可以根据JSON流的来源使用以下阅读器之一:

  • BufferedReader
  • LineNumberReader
  • CharArrayReader
  • InputStreamReader
  • FileReader
  • FilterReader
  • PushbackReader
  • PipedReader
  • StringReader

4、读取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 >>>> 1001Token KEY >>>> firstName
Token Value >>>> LokeshToken KEY >>>> lastName
Token Value >>>> GuptaToken KEY >>>> email
Token Value >>>> null

在上面的示例中:

  • 如果JsonReader的hasNext()方法具有更多令牌,则返回true。
  • peek()方法返回下一个JSON令牌,但不移至该令牌。
  • 随后多次调用peek()将返回相同的JSON令牌。
  • 可以使用JsonToken类的常量检查返回令牌的类型。
  • 使用beginArray()和endArray()方法检查数组的左括号和右括号“ [”和“]”。使用beginObject()和endObject()方法检查对象的左括号和右括号“ {”和“}”。
  • 令牌的密钥为JsonToken.NAME类型。使用nextName()方法获取密钥名称。
  • 确定令牌的类型后,使用诸如nextLong(),nextString(),nextInt()等方法获取令牌的值。可以使用nextNull()或skipValue()使用空文字。
  • 所有next …()方法都返回当前标记的值,并将内部指针移至下一个。
  • 当遇到未知名称时,严格的解析器应该失败,并带有异常。宽大的解析器应调用skipValue()以递归地跳过该值的嵌套令牌,否则可能会发生冲突。

六、JsonParser

Gson JsonParser用于将Json数据解析为JsonElement的解析树,从而解析为JsonObject。

JsonObject可用于使用JSON字符串中的相应键来访问值。

1、创建JsonParser

JsonParser类只有一个默认构造函数,并且不需要任何参数或配置。

JsonParser parser = new JsonParser();

2、转化JSON

JsonParser类提供3种方法来提供JSON作为源并将其解析为JsonElements树。

  • JsonElement parse(JsonReader json)–使用JsonReader读取JSON作为令牌流,并从JSON流中返回下一个值作为分析树。
  • JsonElement parse(java.io.Reader json)–使用指定的阅读器读取JSON并将JSON字符串解析为解析树。
  • JsonElement parse(java.lang.String json)–将指定的JSON字符串解析为解析树。

如果指定的文本不是有效的JSON,则这三个方法都将抛出JsonParseException和JsonSyntaxException。

3、 JsonElement, JsonObject 和JsonArray

在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()方法从中提取字段。

4、Gson JsonParser 示例

使用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"

5、使用fromJson() 获取JsonObject

我们可以使用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"));

6、迭代JSON树结构

这是一个完整的示例,展示了如何迭代从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使用自定义序列化和反序列化。

1、自定义序列化

1.1、JsonSerializer接口

JsonSerializer.java:

public interface JsonSerializer<T> 
{public JsonElement serialize(T value, Type type,JsonSerializationContext jsonSerializationContext) {}
}

为Json创建自定义序列化程序后,我们还需要通过GsonBuilder.registerTypeAdapter(Type,Object)注册该序列化程序。

当Gson遇到指定类型的字段时,它会在序列化期间调用其回调方法serialize()。

1.2、自定义序列化示例

假设我们遇到一种情况,我们必须将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
}

2、自定义反序列化

2.1、JsonDeserializer接口

定制反序列化器必须实现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()。

2.2、自定义反序列化示例

假设某些服务将日期字段分别分为天,月和年等部分分别返回给我们。在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> 
{  @Overridepublic 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

【2】: Gson – Introduction

【3】: Gson – Installation

【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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/554855.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Socket通信原理

Socket通信原理 一、Socket的定义 1、Socket是一个网络通信的套接字&#xff08;接口&#xff09; 二、Socket的实现流程 1、Socket在客户端和服务端发生了什么&#xff1f; 服务器&#xff1a; a.socket()创建socket对象 b.bind()为socket对象绑定协议&#xff0c;赋予名…

CRC校验原理及步骤

1、CRC是用来干嘛的&#xff1f; 检测数据传输过程中是否出现错误&#xff08;某些位&#xff0c;或某几位&#xff0c;或者某块区域位错误&#xff09;。 2、CRC是否能校正数据传输中的错误&#xff1f; CRC只能检错&#xff0c;不能纠错。如果发现错误&#xff0c;可根据双…

在组策略中用户策略仅对特定计算机生效,将组策略应用到满足条件的计算机---配置组策略筛选...

配置组策略筛选Microsoft?Windows?Management Instrumentation (WMI) 大概是我们已知的 Microsoft 保存最好的秘密。尽管如此&#xff0c;但毫无疑问&#xff0c;WMI 是 Microsoft 主要的针对 Windows 的管理支持技术。在Windows Server 2008的组策略高级管理中&#xff0c;对…

Idea 类和包的路径后面出现100%methods;84% lines coveredIdea coverage覆盖率测试工具的使用

Idea 类和包的路径后面出现100%methods;84% lines covered 其他先不说&#xff0c;先看一下出现的问题&#xff1a; 类和包的路径后面多了100%methods;84% lines covered&#xff0c;以前类路径后面是什么都没的&#xff1b; 长话短说&#xff1b; 产生原因&#xff1a; 因…

SpringBoot:整合监听器/过滤器和拦截器

整合监听器/过滤器和拦截器 在实际开发过程中&#xff0c;经常会碰见一些比如系统启动初始化信息、统计在线人数、在线用户数、过滤敏/高词汇、访问权限控制(URL级别)等业务需求。实现以上的功能&#xff0c;都会或多或少的用到过滤器、监听器、拦截器。 一.SpringBoot整合过…

全国计算机英语四六级准考证打印准考证号,2017全国大学生英语四六级准考证打印...

2017年上半年度CET考试时间为6月17日&#xff0c;同学们打印准考证了吗?为方便大家打印四六级准考证&#xff0c;yjbys小编为大家分享英语四级考试准考证打印官方主页入口如下&#xff1a;2017年上半年度CET考试时间及报名方式一、考试科目及时间1.笔试考试时间日期(6月17日)考…

Centos7配置Jenkins

Centos7配置Jenkins jenkins 官方下载地址&#xff1a;https://mirrors.jenkins-ci.org/redhat/ maven 官方下载地址&#xff1a;https://archive.apache.org/dist/maven/maven-3/ tomcat 官方下载地址&#xff1a;https://tomcat.apache.org/download-90.cgi 1、配置jdk …

计算机硬盘用u盘维修,U盘装机大师修复磁盘坏道详细教程

我们都知道当我们的磁盘使用的时间久了就会容易出现各种问题&#xff0c;然而硬盘的坏道是最常见的问题之一。关于磁盘出现坏道有很多原因&#xff0c;诸如硬盘本身质量问题&#xff0c;老化&#xff0c;使用不当等等。我们的硬盘内存太小也会导致应用软件对硬盘频繁访问&#…

多屏幕炒股计算机配置,多屏幕股票交易计算机配置建议使用i59400F计算机主机配置(最多六个屏幕)...

在经历了几年的熊市股市之后&#xff0c;2019年股市似乎有所回升. 最近&#xff0c;许多用户询问多屏股票交易计算机的配置&#xff0c;例如三屏&#xff0c;四屏&#xff0c;和六屏. 实际上&#xff0c;与普通计算机的最大区别是该图形卡需要配备多屏幕图形卡. 一台计算机可以…

小学二年级上学期计算机教案,小学数学二年级上册分苹果教案设计

小学数学二年级上册分苹果教案设计〖教学目标1.经历分苹果等实际操作&#xff0c;初步体会有余数除法与生活的密切联系&#xff0c;进一步体会除法的意义。2.通过实际操作&#xff0c;抽象出有余数除法的书写格式&#xff0c;并体会余数一定要比除数小。〖教材分析分苹果是二年…

生物计算机的主要原材料是(),新材料为生物计算机打造“神经元”和“突触”...

一项最新研究利用复杂的氧化物&#xff0c;打造出了与神经元和突触相似的元件。图片来自pixabay.com虽然电脑的计算速度比人脑快&#xff0c;但在物体识别任务等方面&#xff0c;人脑还是更胜一筹。除此之外&#xff0c;人脑耗费的能量也远低于电脑。大脑的运作方式可以在一定程…

hotmail接收邮件服务器(pop),Microsoft微软邮箱 outlook、hotmail 打开pop和imap的方法

分享个微软邮箱 outlook、hotmail 打开pop和imap的方法只有打开了pop或者imap &#xff0c; foxmail一类的邮件管理客户端才能正常收邮件&#xff1b;打开了smtp才能正常发邮件。设置方法如图&#xff1a;1.登录进去账户以后&#xff0c;点击右上角的设置&#xff0c;齿轮图标&…

MySQL 索引 是如何提高 查询效率 的?

前言 我们都知道当查询数据库变慢时&#xff0c;需要建索引去优化。但是只知道索引能优化显然是不够的&#xff0c;我们更应该知道索引的原理&#xff0c;因为不是加了索引就一定会提升性能。那么接下来就一起探索MYSQL索引的原理吧 什么是索引 索引其实是一种能高效帮助MYS…

FreeMarker详细介绍

FreeMarker 1. 主要内容 2.FreeMarker概述 2.1. FreeMarker概念 FreeMarker 是一款 模板引擎&#xff1a; 即一种基于模板和要改变的数据&#xff0c; 并用来生成输出文本(HTML网页&#xff0c;电子邮件&#xff0c;配置文件&#xff0c;源代码等)的通用工具。 是一个Java类…

SpringBoot整合Freemarker导出word文档表格

freemarker模板里面的template.process()方法里传入的第一个参数Object类型&#xff0c;如果是一个实体类对象在模板上怎么进行渲染&#xff0c;将实体类的值取出 freemarker会调用ObjectWrapper对传入的对象进行warp&#xff0c;具体类型在代码里面用instanceof进行判断。一般…

ambari 修改服务器名,Ambari修改主页面方法

分享下Ambari修改主页面方法&#xff0c;希望对大家有用。[roothdp159 ambari-web]# brunch watch --serverOct 10:22:43 - info: application started on http://localhost:3333/Oct 10:22:47 - info: compiled 891 files into 5 files, copied 260 in 3988msOct 10:23:12 - i…

快速向服务器传文件格式,客户端如何向服务器传文件格式

客户端如何向服务器传文件格式 内容精选换一换语音通话平台通过此接口向客户推送语音通话业务用户呼叫时的状态信息&#xff0c;如呼入、呼出、振铃、应答、挂机等状态的信息。语音通话平台(客户端) → 客户服务器(服务端)前提条件SP在开发应用时&#xff0c;若需订阅呼叫状态通…

MyBatis-Plus--解决逻辑删除与唯一索引的问题--方法/实例

文章目录简介问题复现依赖**建库建表**代码测试解决方案方案1&#xff1a;将字段设置为id&#xff08;推荐&#xff09;建库建表修改Entity测试方案2&#xff1a;将字段设置为当前时间&#xff08;不推荐&#xff09;建库建表修改Entity测试简介 说明 本文用示例介绍MyBatis-…

MybatisPlus 实体类与数据库表映射关系MybatisPlus:ORM思想

实体类与数据库表映射关系 使用mybatisPlus时&#xff0c;会确定实体类和数据的映射关系 具体的映射方法有两种 1、默认&#xff1a;采用驼峰映射规则 例如MyUserTable 对应的数据库表为 my_user_table ; TEMyUserTable 对应表名为t_e_my_user_table; 2、注解TableName 在…

Spring Boot——maven项目常用打包配置

文章目录一、简介二、pom.xml三、效果图3.1 所有的资源打包到指定的目录maven3.2 所有的配置文件都放到config目录3.3 所有的配置文件都不在jar里&#xff0c;防止敏感信息泄露结语一、简介 maven项目打包是我们程序员经常遇到的事&#xff0c;今天就来弄一个常用的打包方式&a…