目录
Spring Boot 使用 Gson 替换 Jackson
Gson 概述与下载
1、Java 解析 Json 最常用的类库有:google 的 Gson、阿里巴巴的 FastJson、以及 Jackson。这些都是非常优秀而且常用的库。
2、GSON 是 Google 提供的用来在 Java 对象和 JSON 数据之间进行映射的 Java 类库,可以快速的将一个 Json 字符转成一个 Java 对象,或者将一个 Java 对象转化为 Json 字符串。
3、gson 在 github 上开源地址:https://github.com/google/gson
4、注意事项:Gson 将 Map 序列化为 Json 字符串时,默认原本的整型会加上 .0 而变成浮点型,比如 0 -> 0.0,1 -> 1.0 。
二进制开发包下载:gson 二进制开发包下载地址:Maven Central Repository Search
gson-2.8.4.jar下载、gson-2.8.5.jar下载
Maven 依赖:gson 在 Maven 仓库地址:https://mvnrepository.com/artifact/com.google.code.gson/gson
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
Gson (反)序列化 Java 对象
1、com.google.gson.Gson 提供 toJson() 和 fromJson() 方法用于序列化与反序列化 Java 对象。
2、Gson 对象的 toJson 方法可以将 Java 基本数据类型、数组、以及 POJO 对象、List、Map 、JsonElement 等转为 json 格式的字符串,
3、Gson 对象的 fromJson 方法做与 toJson 相反的操作,将 json 格式的字符串转为基本数据类型、 POJO 对象、List、Map 、JsonElement 等
对象序列化 | |
T fromJson(String json, Class<T> classOfT) | 将指定的 Json 反序列化为指定类的对象,如果指定的类是泛型类型,则使用 fromJson(String, Type)方法。 |
T fromJson(String json, Type typeOfT) | 将指定的 Json 反序列化为指定类型的对象,如果指定的对象是泛型类型,则此方法很有用,对于非泛型对象,请改用 fromJson(String json, Class<T> classOfT) |
T fromJson(JsonElement json, Class<T> classOfT) | 将指定的 json 元素反序列化为指定类型的对象,如果指定的类是泛型类型,则使用 fromJson(JsonElement, Type) 方法。 |
T fromJson(JsonElement json, Type typeOfT) | |
T fromJson(Reader json, Class<T> classOfT) T fromJson(Reader json, Type typeOfT) | 将从指定字符输入流读取的Json反序列化为指定类的对象,如果指定的类是泛型类型,则调用 {@link#fromJson(Reader,type)} |
序列化为对象 | |
String toJson(Object src) | 将指定的对象序列化为其等效的Json表示形式,当指定的对象不是泛型类型时,应使用此方法,如果对象是泛型类型,请改用 toJson(object,type). |
String toJson(Object src, Type typeOfSrc) | 将指定的对象(包括泛型类型的对象)序列化为其等效的Json表示形式,对于非泛型对象,请改用{@link#toJson(Object)} |
String toJson(JsonElement jsonElement) | 将 JsonElement 转换为其等效的JSON表示形式。 |
JsonElement toJsonTree(Object src) | 将指定的对象序列化为 JsonElement 的等效表示形式,当指定的对象不是泛型类型时,应使用此方法;如果对象是泛型类型,请改用{@link#toJsonTree(object,type)} |
JsonElement toJsonTree(Object src, Type typeOfSrc) |
API 演示源码:src/main/java/com/wmx/gson/GsonTest.java · 汪少棠/apache-study - Gitee.com
JsonElement Json 元素
1、JsonObject、JsonArray、JsonPrimitive、JsonNull 都是 JsonElement 的子类,JsonElement 常用方法:
JsonElement deepCopy() | 返回此元素的深层副本,克隆。 |
BigDecimal getAsBigDecimal() | 将此元素作为 BigDecimal 类型获取,如果元素不是 JsonPrimitive,则引发 ClassCastException, 如果元素不是有效的 BigDecimate,则 @throws NumberFormatException。 如果元素属于 JsonArray 类型,但包含多个元素,则引发 IllegalStateException。 |
BigInteger getAsBigInteger() | 将此元素作为 BigInteger 类型获取,如果元素不是 JsonPrimitive,则引发 ClassCastException, 如果元素不是有效的 BigInteger ,则 @throws NumberFormatException。 如果元素属于 JsonArray 类型,但包含多个元素,则引发 IllegalStateException。 |
boolean getAsBoolean() | 将此元素作为原始布尔值获取,如果元素不是 JsonPrimitive 并且不是有效的布尔值,则引发 ClassCastException, 如果元素属于 JsonArray 类型,但包含多个元素,则引发IllegalStateException |
byte getAsByte() | 将此元素作为原始 byte 值获取,如果元素不是 JsonPrimitive 并且不是有效的布尔值,则引发 ClassCastException, 如果元素属于 JsonArray 类型,但包含多个元素,则引发IllegalStateException |
其它 Java 基本数据类型也是同理: double getAsDouble()、char getAsCharacter()、float getAsFloat()、int getAsInt()、long getAsLong()、short getAsShort() | |
JsonArray getAsJsonArray() | 将此元素作为 JsonArray 获取,如果元素是其他类型的元素,则会生成 IlleglastateException 异常, 因此最好先调用 isJsonArray() 方法确保该元素是所需的类型,然后再使用此方法。 |
JsonObject getAsJsonObject() | 将此元素作为 JsonObject 获取,如果元素是其他类型的元素,则会引发 IlleglastateException 异常, 因此最好先通过调用 isJsonObject() 方法来确保该元素是所需类型之后使用此方法。 |
JsonPrimitive getAsJsonPrimitive() | 将此元素作为 JsonPrimitive 获取,如果元素是其他类型的元素,则会引发 IlleglastateException 异常, JsonPrimitive 值可以是 Java 字符串、Java 基本数据类型及其包装器类型。 |
boolean isJsonArray() | 验证此元素是否为数组,如果此元素属于 JsonArray 类型,则返回 true,否则返回 false。 |
boolean isJsonNull() | 验证此元素是否表示 null 值,如果此元素的类型为 JsonNull,则返回 true,否则返回 false。 |
boolean isJsonObject() | 验证此元素是否为 JsonObject 对象。 |
boolean isJsonPrimitive() | 以验证此元素是否为 Java 数据类型。 |
/**
* JsonPrimitive getAsJsonPrimitive():
* 将此元素作为 JsonPrimitive 获取,如果元素是其他类型的元素,则会引发 IlleglastateException 异常,
* 因此最好先通过调用 isJsonPrimitive() 方法来确保该元素是所需的类型之后再使用此方法。JsonPrimitive 值可以是 Java 字符串、Java 基本数据类型及其包装器类型。
*/
@Test
public void test12() {
String json = "[\"本级小计\",368.00,328.00,]";
JsonElement sourceJsonElement = new JsonParser().parse(json);
JsonArray jsonArray = sourceJsonElement.getAsJsonArray();
for (int i = 0; i < jsonArray.size(); i++) {
JsonElement jsonElement = jsonArray.get(i);
if (jsonElement.isJsonPrimitive()) {
JsonPrimitive jsonPrimitive = jsonElement.getAsJsonPrimitive();
if (jsonPrimitive.isString()) {
System.out.println(jsonPrimitive.getAsString());
} else if (jsonPrimitive.isNumber()) {
System.out.println(jsonPrimitive.getAsDouble());
}
}
}
}
API 演示源码:src/main/java/com/wmx/gson/JsonObjectTest.java · 汪少棠/apache-study - Gitee.com
src/main/java/com/wmx/gson/JsonArrayTest.java · 汪少棠/apache-study - Gitee.com
JsonObject Json 对象
add(String property, JsonElement value) | 添加一个健-值对的成员,名称必须是字符串,但值可以是任意的 JsonElement 类型。 |
addProperty(String property, Boolean value) | 添加布尔成员的便利方法,指定的值将转换为布尔值的 JsonPrimitive。 |
addProperty(String property, Character value) | 添加 char 成员的便利方法,指定的值将转换为字符的 JsonPrimitive。 |
addProperty(String property, Number value) | 添加 Number 成员的便利方法,指定的值将转换为数字的 JsonPrimitive。 |
addProperty(String property, String value) | 添加 String 成员的便利方法,指定的值将转换为数字的 JsonPrimitive。 |
Set<Map.Entry<String, JsonElement>> entrySet() | 返回此对象的所有成员,集合是有序的,与元素的添加顺序相同。 |
JsonElement get(String memberName) | 返回具有指定名称的成员。 |
JsonArray getAsJsonArray(String memberName) | 获取指定成员作为 JsonArray 的便利方法。 |
JsonObject getAsJsonObject(String memberName) | 获取指定成员作为 JsonObject 的便利方法。 |
JsonPrimitive getAsJsonPrimitive(String memberName) | 获取指定成员作为 JsonPrimitive 的便利方法。 |
boolean has(String memberName) | 检查此对象中是否存在具有指定名称的成员的便利方法。 |
Set<String> keySet() | 返回所有成员的 key 值。 |
JsonElement remove(String property) | 从此 JsonObject 中删除指定的属性,返回被删除的属性。 |
int size() | 返回对象中键/值对的数目。 |
/**
* int size():返回对象中键/值对的数目。
* Set<String> keySet():返回所有成员的键值
*/
@Test
public void jsonObject7() {
String json = "{\"pId\":9527,\"pName\":\"华安\",\"isMarry\":true}";
JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();
System.out.println(jsonObject.size());
Set<String> keySet = jsonObject.keySet();//3
System.out.println(keySet);//[pId, pName, isMarry]
}
API 演示源码:src/main/java/com/wmx/gson/JsonObjectTest.java · 汪少棠/apache-study - Gitee.com
JsonArray Json 数组
JsonArray() JsonArray(int capacity) | 两个构造器,一个是创建空的 Json 数组,一个是指定初始容量。 |
add( Boolean value) | 将指定的布尔值添加到 json 数组,如 value 为 null,则添加 JsonNull。 |
add(Character value) | 将指定的 Character 值添加到 json 数组,如 value 为 null,则添加 JsonNull。 |
add(Number value) | 将指定的 Number 值添加到 json 数组,如 value 为 null,则添加 JsonNull。 |
add(String value) | 将指定的 String 值添加到 json 数组,如 value 为 null,则添加 JsonNull。 |
add(JsonElement value) | 将指定的 JsonElement 值添加到 json 数组,如 value 为 null,则添加 JsonNull。 |
addAll(JsonArray array) | 将指定数组中的所有元素添加到此 json 数组。 |
boolean contains(JsonElement element) | 如果此数组包含指定的元素,则返回true。 |
JsonElement get(int i) | 返回数组的第 i 个元素,如果下标越界,则抛异常 |
Iterator<JsonElement> iterator() | 返回一个迭代器来导航数组的元,由于数组是一个有序列表,迭代器按照元素插入的顺序导航元素。 |
JsonElement remove(int index) | 删除此数组中指定位置的元素,向左移动任何后续元素(从其索引中减去一个),返回从数组中删除的元素。 |
boolean remove(JsonElement element) | 从该数组中删除第一个出现的指定元素(如果存在)。如果数组不包含元素,则它将保持不变。 |
JsonElement set(int index, JsonElement element) | 将此数组中指定位置的元素替换为指定元素,元素不能为null。 |
int size() | 返回数组的大小。 |
@Test
public void test4() {
JsonArray jsonArray = new JsonParser().parse("[{\"code\":200,\"msg\":\"成功\"}]").getAsJsonArray();
JsonArray deepCopy = jsonArray.deepCopy();
deepCopy.add("Yes");
System.out.println(jsonArray);//[{"code":200,"msg":"成功"}]
System.out.println(deepCopy);//[{"code":200,"msg":"成功"},"Yes"]
}
API 演示源码:src/main/java/com/wmx/gson/JsonArrayTest.java · 汪少棠/apache-study - Gitee.com
JsonParser Json 解析
1、JsonParser 用于将 Json 字符内容解析为 json 元素 JsonElement。
JsonElement parse(Reader json) | 将指定的 JSON 字符串字符输入流解析为 Json 元素,如果指定的文本不是有效的 JSON 字符串,则抛出 JsonParseException 异常。 |
JsonElement parse(String json) | 将指定的 JSON 字符串解析为 Json 元素,如果指定的文本不是有效的 JSON 字符串,则抛出 JsonParseException 异常。 |
@Test
public void test1() {
String json = "{\"id\":1000,\"name\":\"华安\",\"birthday\":\"Jul 13, 2020 8:46:42 PM\",\"marry\":true}";
JsonParser jsonParser = new JsonParser();
JsonElement jsonElement = jsonParser.parse(json);
JsonObject jsonObject = jsonElement.getAsJsonObject();
System.out.println(jsonObject);//{"id":1000,"name":"华安","birthday":"Jul 13, 2020 8:46:42 PM","marry":true}
}
API 演示源码:src/main/java/com/wmx/gson/JsonParserTest.java · 汪少棠/apache-study - Gitee.com
GsonBuilder 构建 Gson
1、对于默认配置的 Gson,直接使用 new Gson 更简单,当需要设置默认值以外的配置选项时,使用 GsonBuilder 构建器,调用它的各种配置方法,最后调用 create 方法创建 Gson 对象。
GsonBuilder serializeNulls() | 序列化空字段,默认情况下,Gson 序列化期间会忽略所有为 null 的字段 |
GsonBuilder setDateFormat(String pattern) | 根据提供的模式序列化 Date 日期对象,可以多次调用,但只有最后一次调用将用于决定序列化格式。 |
GsonBuilder setFieldNamingPolicy(FieldNamingPolicy namingConvention) 1、配置为在序列化和反序列化期间将特定命名策略应用于对象的字段。 2、namingConvention:用于序列化和反序列化的 JSON 字段命名约定/策略,可选值如下: IDENTITY:使用对象默认的字段名称 |
@Test
public void test1() {
Gson gson = new GsonBuilder()
.serializeNulls()
.setDateFormat("yyyy-MM-dd HH:mm:ss")
.setFieldNamingPolicy(FieldNamingPolicy.IDENTITY)
.create();
Person person = new Person();
person.setId(100);
person.setBirthday(new Date());
String toJson = gson.toJson(person);
//{"id":100,"name":null,"birthday":"2020-07-19 11:37:35","marry":null}
System.out.println(toJson);
Person person1 = gson.fromJson(toJson, Person.class);
//Person{id=100, name='null', birthday=Sun Jul 19 11:37:35 CST 2020, marry=null}
System.out.println(person1);
}
API 演示源码:src/main/java/com/wmx/gson/GsonBuilderTest.java · 汪少棠/apache-study - Gitee.com
Spring Boot 使用 Gson 替换 Jackson
1、Spring Boot 提供了三个 JSON 库的集成:Gson、Jackson、JSON-B, 默认使用 jackson。
第一步:排除 jackson 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</exclusion>
</exclusions>
</dependency>
在启动类 @SpringBootApplication 注解中,排除掉 Jackson 的自动装配:
@SpringBootApplication(exclude = { JacksonAutoConfiguration.class })
第二步:添加 Gson 依赖
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
第三步:配置属性
1、在全局配置文件中添加如下配置,指定 Spirng MVC 使用 Gson 的 HttpMessageConverter 实现,GsonHttpMessageConverter:
spring.mvc.converters.preferred-json-mapper=gson
2、Spring Boot 为 Gson 预定义了很多配置属性,可以通过它们来自定义 Gson 的特性:
完整配置:https://springdoc.cn/spring-boot/application-properties.html#appendix.application-properties.json/
spring.gson.date-format= # Date 对象序列化时使用的格式。
spring.gson.disable-html-escaping= # 是否禁止转义 HTML 字符,如 "<"、">" 等。
spring.gson.disable-inner-class-serialization= # 序列化时是否排除内部类。
# 是否启用复杂 map key(即非基础类型)的序列化。
spring.gson.enable-complex-map-key-serialization=
# 是否将所有没有 @Expose 注解的字段排除在序列化或反序列化之外。
spring.gson.exclude-fields-without-expose-annotation=
spring.gson.field-naming-policy= # 在序列化和反序列化时应用于对象字段的命名策略。
# 是否通过在输出前添加一些特殊文本来生成不可执行的 JSON。
spring.gson.generate-non-executable-json=
spring.gson.lenient= # 是否对不符合 RFC 4627 的 JSON 进行宽松解析。
spring.gson.long-serialization-policy= # Long 和 long 类型的序列化策略。
spring.gson.pretty-printing= # 是否输出格式化后的 JSON 字符串。
spring.gson.serialize-nulls= # 是否输出格式化后的 JSON 字符串。
自定义配置
1、如果全局配置属性不满足需求,那么也可以通过在配置类中自定义 GsonBuilder
Bean 来对 Gson 进行自定义配置。
2、例如,自定义 Gson 对 LocalDateTime
类型的格式化:
@Configuration
public class GsonConfig {
@Bean
public GsonBuilder gsonBuilder(List<GsonBuilderCustomizer> customizers) {
// 创建 GsonBuilder
GsonBuilder builder = new GsonBuilder();
// 序列化空字段,默认情况下,Gson 序列化期间会忽略所有为 null 的字段
builder.serializeNulls();
// 加载配置文件中的配置属性。customizers 是读取到的配置文件中关于 Gson 的配置
customizers.forEach((c) -> c.customize(builder));
// 编程式自定义
DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// LocalDateTime 类型的格式化
builder.registerTypeHierarchyAdapter(LocalDateTime.class, new JsonSerializer<LocalDateTime>() {
@Override
public JsonElement serialize(LocalDateTime src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(DATE_TIME_FORMATTER.format(src));
}
});
return builder;
}
}
3、然后可以在任意地方注入 com.google.gson.Gson 对象使用。
@Autowired
private Gson gson;