在 Spring Boot 中使用 Gson 替换 Jackson
GSON 是由谷歌开源的一款 Java JSON 库。特点是轻量,只有一个 JAR,无任何其他依赖。高性能,支持以流式进行序列化/反序列化。并且抽象了基本的 JsonElement
、JsonObject
、JsonArray
、JsonPrimitive
和 JsonNull
,可以在无自定义 Java 对象的情况下构建、解析 JSON 对象。
本文将会指导你如何在 Spring Boot 中使用 Gson 代替默认的 Jackson 作为 JSON 序列化/反序列化框架。
添加依赖
在 pom.xml
中添加依赖。 gson
的版本已经被 Spring Boot 管理,所以不需要声明版本号。
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
由于 Spring Boot 默认使用 Jackson,所以很多 Spring Boot 的组件、框架默认也会选择用 Jackson 作为 JSON 库。如果你确认项目中,没有其他地方使用到了 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 })
配置属性
在 application.properties
中添加如下配置,指定 Spirng MVC 使用 Gson 的 HttpMessageConverter
实现,GsonHttpMessageConverter
:
spring.mvc.converters.preferred-json-mapper=gson
Spring Boot 为 Gson 预定义了很多配置属性,你可以通过它们来自定义 Gson 的特性:
# Date 对象序列化时使用的格式。
spring.gson.date-format=
# 是否禁止转义 HTML 字符,如 "<"、">" 等。
spring.gson.disable-html-escaping=
# 序列化时是否排除内部类。
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=
# 是否对不符合 RFC 4627 的 JSON 进行宽松解析。
spring.gson.lenient=
# Long 和 long 类型的序列化策略。
spring.gson.long-serialization-policy=
# 是否输出格式化后的 JSON 字符串。
spring.gson.pretty-printing=
# 是否序列化 null 字段。
spring.gson.serialize-nulls=
具体的属性说明,请参考 官方文档。
配置类
如果配置属性不满足需求,那么也可以通过在配置类中自定义 GsonBuilder
Bean 来对 Gson 进行自定义配置。
例如,自定义 Gson 对 LocalDateTime
类型的格式化:
package cn.springdoc.demo.config;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import org.springframework.boot.autoconfigure.gson.GsonBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
@Configuration
public class GsonConfiguration {
@Bean
public GsonBuilder gsonBuilder(List<GsonBuilderCustomizer> customizers) { // customizers 是读取到的配置文件中关于 Gson 的配置
// 创建 GsonBuilder
GsonBuilder builder = new GsonBuilder();
// 加载配置文件中的配置属性
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;
}
}
测试
整合成功后,你可以在任意地方注入 Gson
对象使用。
创建测试类,进行测试:
import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;
import com.google.gson.Gson;
import cn.springdoc.demo.DemoApplication;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
public class DemoApplicationTest {
static final Logger logger = LoggerFactory.getLogger(DemoApplicationTest.class);
@Autowired
private Gson gson; // 注入 Gson
@Test
public void test() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("title", "spring 中文网");
map.put("url", "https://springdoc.cn/");
map.put("creatAt", LocalDateTime.now());
String json = this.gson.toJson(map);
logger.info(json);
}
}
输出日志如下:
INFO 13020 --- [ main] cn.springdoc.test.DemoApplicationTest : {"title":"spring 中文网","url":"https://springdoc.cn/","creatAt":"2023-09-19 09:21:23"}
如你所见,注入成功,配置生效,一切OK。