Spring Boot中Jackson ObjectMapper应用详解
Spring Boot支持与三种JSON mapping库集成:Gson、Jackson和JSON-B。Jackson是首选和默认的。
Jackson是spring-boot-starter-json的一部分,spring-boot-starter-web中包含spring-boot-starter-json。也就是说,当项目中引入spring-boot-starter-web后会自动引入spring-boot-starter-json。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
ObjectMapper
ObjectMapper是jackson-databind包中的一个类,提供读写JSON的功能,可以方便的进行对象和JSON转换:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public final class JsonUtil {
private static ObjectMapper mapper = new ObjectMapper();
private JsonUtil() {
}
/**
* Serialize any Java value as a String.
*/
public static String generate(Object object) throws JsonProcessingException {
return mapper.writeValueAsString(object);
}
/**
* Deserialize JSON content from given JSON content String.
*/
public static <T> T parse(String content, Class<T> valueType) throws IOException {
return mapper.readValue(content, valueType);
}
}
编写一简单POJO测试类:
import java.util.Date;
public class Hero {
public static void main(String[] args) throws Exception {
System.out.println(JsonUtil.generate(new Hero("Jason", new Date())));
}
private String name;
private Date birthday;
public Hero() {
}
public Hero(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
}
public String getName() {
return name;
}
public Date getBirthday() {
return birthday;
}
}
运行后输出结果如下:
{"name":"Jason","birthday":1540909420353}
可以看到日期转换为长整型。
ObjectMapper默认序列化配置启用了SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,日期将转换为Timestamp。可查看如下源码:
public ObjectMapper(JsonFactory jf, DefaultSerializerProvider sp, DefaultDeserializationContext dc) {
...
BaseSettings base = DEFAULT_BASE.withClassIntrospector(defaultClassIntrospector());
_configOverrides = new ConfigOverrides();
_serializationConfig = new SerializationConfig(base, _subtypeResolver, mixins, rootNames, _configOverrides);
...
}
public SerializationConfig(BaseSettings base, SubtypeResolver str, SimpleMixInResolver mixins, RootNameLookup rootNames,
ConfigOverrides configOverrides)
{
super(base, str, mixins, rootNames, configOverrides);
_serFeatures = collectFeatureDefaults(SerializationFeature.class);
_filterProvider = null;
_defaultPrettyPrinter = DEFAULT_PRETTY_PRINTER;
_generatorFeatures = 0;
_generatorFeaturesToChange = 0;
_formatWriteFeatures = 0;
_formatWriteFeaturesToChange = 0;
}
默认情况下,Date类型序列化将调用DateSerializer的_timestamp 方法:
/**
* For efficiency, we will serialize Dates as longs, instead of
* potentially more readable Strings.
*/
@JacksonStdImpl
@SuppressWarnings("serial")
public class DateSerializer extends DateTimeSerializerBase<Date> {
...
@Override
protected long _timestamp(Date value) {
return (value == null) ? 0L : value.getTime();
}
@Override
public void serialize(Date value, JsonGenerator g, SerializerProvider provider) throws IOException {
if (_asTimestamp(provider)) {
g.writeNumber(_timestamp(value));
return;
}
_serializeAsString(value, g, provider);
}
}
DateTimeSerializerBase的_asTimestamp方法:
protected boolean _asTimestamp(SerializerProvider serializers)
{
if (_useTimestamp != null) {
return _useTimestamp.booleanValue();
}
if (_customFormat == null) {
if (serializers != null) {
return serializers.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
// 12-Jun-2014, tatu: Is it legal not to have provider? Was NPE:ing earlier so leave a check
throw new IllegalArgumentException("Null SerializerProvider passed for "+handledType().getName());
}
return false;
}
禁用WRITE_DATES_AS_TIMESTAMPS
若要将日期序列化为字符串,可禁用SerializationFeature.WRITE_DATES_AS_TIMESTAMPS:
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
这时序列化将调用StdDateFormat的format()方法,使用ISO-8601兼容格式"yyyy-MM-dd'T'HH:mm:ss.SSSZ",输出内容如下:
{"name":"Jason","birthday":"2018-10-31T03:07:34.485+0000"}
StdDateFormat反序列化支持ISO-8601兼容格式和RFC-1123("EEE, dd MMM yyyy HH:mm:ss zzz")格式。
@JsonFormat
使用@JsonFormat注解,代替全局设置,是一种更灵活的方法:
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Date birthday;
还可以定义pattern:
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date birthday;
当自定义pattern后,将创建新的SimpleDateFormat实例来序列化日期,参见DateTimeSerializerBase的createContextual()方法:
public JsonSerializer<?> createContextual(SerializerProvider serializers, BeanProperty property) throws JsonMappingException
{
...
if (format.hasPattern()) {
final Locale loc = format.hasLocale() ? format.getLocale() : serializers.getLocale();
SimpleDateFormat df = new SimpleDateFormat(format.getPattern(), loc);
TimeZone tz = format.hasTimeZone() ? format.getTimeZone() : serializers.getTimeZone();
df.setTimeZone(tz);
return withFormat(Boolean.FALSE, df);
}
...
}
Spring Boot与Jackson ObjectMapper
Spring Boot使用HttpMessageConverters处理HTTP交换中的内容转换。当classpath中存在Jackson时,Jackson2ObjectMapperBuilder将是默认的Converter,源码请查看HttpMessageConverters和WebMvcConfigurationSupport:
HttpMessageConverters
private List<HttpMessageConverter<?>> getDefaultConverters() {
List<HttpMessageConverter<?>> converters = new ArrayList<>();
if (ClassUtils.isPresent("org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport", null)) {
converters.addAll(new WebMvcConfigurationSupport() {
public List<HttpMessageConverter<?>> defaultMessageConverters() {
return super.getMessageConverters();
}
}.defaultMessageConverters());
}
else {
converters.addAll(new RestTemplate().getMessageConverters());
}
reorderXmlConvertersToEnd(converters);
return converters;
}
WebMvcConfigurationSupport
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316
messageConverters.add(new ByteArrayHttpMessageConverter());
messageConverters.add(stringHttpMessageConverter);
messageConverters.add(new ResourceHttpMessageConverter());
messageConverters.add(new ResourceRegionHttpMessageConverter());
messageConverters.add(new SourceHttpMessageConverter<>());
messageConverters.add(new AllEncompassingFormHttpMessageConverter());
...
if (jackson2Present) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
...
}
默认,Jackson2ObjectMapperBuilder将创建ObjectMapper实例:
Jackson2ObjectMapperBuilder
public <T extends ObjectMapper> T build() {
ObjectMapper mapper;
if (this.createXmlMapper) {
mapper = (this.defaultUseWrapper != null ?
new XmlObjectMapperInitializer().create(this.defaultUseWrapper) :
new XmlObjectMapperInitializer().create());
}
else {
mapper = (this.factory != null ? new ObjectMapper(this.factory) : new ObjectMapper());
}
configure(mapper);
return (T) mapper;
}
ObjectMapper以下属性被禁用:
- MapperFeature.DEFAULT_VIEW_INCLUSION
- DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
- SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
Jackson2ObjectMapperBuilder
private void customizeDefaultFeatures(ObjectMapper objectMapper) {
if (!this.features.containsKey(MapperFeature.DEFAULT_VIEW_INCLUSION)) {
configureFeature(objectMapper, MapperFeature.DEFAULT_VIEW_INCLUSION, false);
}
if (!this.features.containsKey(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
configureFeature(objectMapper, DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
}
JacksonAutoConfiguration
static {
Map<Object, Boolean> featureDefaults = new HashMap<>();
featureDefaults.put(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
FEATURE_DEFAULTS = Collections.unmodifiableMap(featureDefaults);
}
自定义Jackson ObjectMapper配置
针对ObjectMapper的六种Feature,Spring Boot都提供了相应的配置,列表如下:
Feature(Enum) | Spring Boot Property | Values |
---|---|---|
com.fasterxml.jackson.databind.DeserializationFeature | spring.jackson.deserialization.feature_name | true, false |
com.fasterxml.jackson.core.JsonGenerator.Feature | spring.jackson.generator.feature_name | true, false |
com.fasterxml.jackson.databind.MapperFeature | spring.jackson.mapper.feature_name | true, false |
com.fasterxml.jackson.core.JsonParser.Feature | spring.jackson.parser.feature_name | true, false |
com.fasterxml.jackson.databind.SerializationFeature | spring.jackson.serialization.feature_name | true, false |
com.fasterxml.jackson.annotation.JsonInclude.Include | spring.jackson.default-property-inclusion | always, non_null, non_absent, non_default, non_empty |
例如,为启用美化打印,设置spring.jackson.serialization.indent_output=true,相当于启用SerializationFeature.INDENT_OUTPUT,配置中忽略feature_name大小写。
其他的Jackson配置属性:
- spring.jackson.date-format= # Date format string or a fully-qualified date format class name. For instance,
yyyy-MM-dd HH:mm:ss
. - spring.jackson.joda-date-time-format= # Joda date time format string. If not configured, "date-format" is used as a fallback if it is configured with a format string.
- spring.jackson.locale= # Locale used for formatting.
- spring.jackson.property-naming-strategy= # One of the constants on Jackson's PropertyNamingStrategy. Can also be a fully-qualified class name of a PropertyNamingStrategy subclass.
- spring.jackson.time-zone= # Time zone used when formatting dates. For instance, "America/Los_Angeles" or "GMT+10".
其中spring.jackson.date-format默认值为com.fasterxml.jackson.databind.util.StdDateFormat。
@DateTimeFormat和@JsonFormat
在REST编程中,当提交application/json的POST/PUT请求时,JSON会通过Jackson进行转换。当提交GET请求时,如参数中包含日期,后台代码需要使用注解@DateTimeFormat:
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date startDate;
两者可以同时使用:
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date startDate;
参考:
https://blog.csdn.net/weixin_44048532/article/details/86647880
Spring Boot中Jackson ObjectMapper应用详解相关推荐
- spring boot模板引擎thymleaf用法详解
spring boot模板引擎thymleaf用法详解 Spring-boot支持FreeMarker.Thymeleaf.jsp.veocity 但是对freemarker和thymeleaf的支持 ...
- spring boot(四):thymeleaf使用详解
spring boot(四):thymeleaf使用详解 在上篇文章springboot(二):web综合开发中简单介绍了一下thymeleaf,这篇文章将更加全面详细的介绍thymeleaf的使用. ...
- Spring Boot 使用 Druid 连接池详解
Spring Boot 使用 Druid 连接池详解 Alibaba Druid 是一个 JDBC 组件库,包含数据库连接池.SQL Parser 等组件,被大量业务和技术产品使用或集成,经历过严苛的 ...
- Spring Boot 2.0 的配置详解(图文教程)
本文来自作者 泥瓦匠 @ bysocket.com 在 GitChat 上分享 「Spring Boot 2.0 的配置详解(图文教程)」 编辑 | 哈比 Spring Boot 配置,包括自动配置和 ...
- Spring Boot的每个模块包详解
Spring Boot的每个模块包详解,具体如下: 1.spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置.日志和YAML. 2.spring-boot-s ...
- spring boot 源码解析43-JmxMetricWriter详解
前言 本文我们来介绍JmxMetricWriter, JmxMetricWriter是依赖于spring jmx 来实现的. 因此本文的开头先介绍一下spring boot 与jmx的集成,然后分析J ...
- Spring Boot 配置加载顺序详解
使用 Spring Boot 会涉及到各种各样的配置,如开发.测试.线上就至少 3 套配置信息了.Spring Boot 可以轻松的帮助我们使用相同的代码就能使开发.测试.线上环境使用不同的配置. 在 ...
- Spring AOP中定义切点PointCut详解
1.AOP是什么? 软件工程有一个基本原则叫做"关注点分离"(Concern Separation),通俗的理解就是不同的问题交给不同的部分去解决,每部分专注于解决自己的问题.这年 ...
- (转)Spring Boot(四):Thymeleaf 使用详解
http://www.ityouknow.com/springboot/2016/05/01/spring-boot-thymeleaf.html 在上篇文章Spring Boot (二):Web 综 ...
最新文章
- 谷歌扔下芯片核弹:开源全球首个可制造的PDK,免费帮有缘人实现造芯梦想
- 麦肯锡:物联网九大应用潜力无限 2025年经济价值高达11.1万亿美元
- Mac系统修改root用户密码,mac切换root用户登录实例演示
- 给网页穿上Word马甲
- 数据--第49课 - 线性索引查找
- SQL order by的用法
- quartus支持linux系统,在64位Linux下把Quartus II设置成64位的方法
- 杀毒软件误删文件了怎么办?如何恢复被杀毒软件删除的文件
- 三星gsat笔试容不容易通过
- 2019年网络工程师考试大纲
- 阿里云云计算工程师认证(ACP)分享
- 今日头条2019春季暑期实习笔试题(非自己做)4-14
- C标准库-va_list
- python超级简单爬虫
- 请客人(客户)吃饭谈点什么好?
- python输出乘法式子(HLOJ)(完整解析)
- python week 获取 星期 第几周 开始日期 结束日期 星期几
- (转)IST:Iterative Shrinkage/Thresholding和Iterative Soft Thresholding
- 神经网络与深度学习笔记(二)正向传播与反向传播
- IPv6和IPv4的区别