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。

  1. <dependency>

  2. <groupId>org.springframework.boot</groupId>

  3. <artifactId>spring-boot-starter-web</artifactId>

  4. </dependency>

ObjectMapper

ObjectMapper是jackson-databind包中的一个类,提供读写JSON的功能,可以方便的进行对象和JSON转换:

  1. import com.fasterxml.jackson.core.JsonProcessingException;

  2. import com.fasterxml.jackson.databind.ObjectMapper;

  3. import java.io.IOException;

  4. public final class JsonUtil {

  5. private static ObjectMapper mapper = new ObjectMapper();

  6. private JsonUtil() {

  7. }

  8. /**

  9. * Serialize any Java value as a String.

  10. */

  11. public static String generate(Object object) throws JsonProcessingException {

  12. return mapper.writeValueAsString(object);

  13. }

  14. /**

  15. * Deserialize JSON content from given JSON content String.

  16. */

  17. public static <T> T parse(String content, Class<T> valueType) throws IOException {

  18. return mapper.readValue(content, valueType);

  19. }

  20. }

编写一简单POJO测试类:

  1. import java.util.Date;

  2. public class Hero {

  3. public static void main(String[] args) throws Exception {

  4. System.out.println(JsonUtil.generate(new Hero("Jason", new Date())));

  5. }

  6. private String name;

  7. private Date birthday;

  8. public Hero() {

  9. }

  10. public Hero(String name, Date birthday) {

  11. this.name = name;

  12. this.birthday = birthday;

  13. }

  14. public String getName() {

  15. return name;

  16. }

  17. public Date getBirthday() {

  18. return birthday;

  19. }

  20. }

运行后输出结果如下:

{"name":"Jason","birthday":1540909420353}

可以看到日期转换为长整型。

ObjectMapper默认序列化配置启用了SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,日期将转换为Timestamp。可查看如下源码:

  1. public ObjectMapper(JsonFactory jf, DefaultSerializerProvider sp, DefaultDeserializationContext dc) {

  2. ...

  3. BaseSettings base = DEFAULT_BASE.withClassIntrospector(defaultClassIntrospector());

  4. _configOverrides = new ConfigOverrides();

  5. _serializationConfig = new SerializationConfig(base, _subtypeResolver, mixins, rootNames, _configOverrides);

  6. ...

  7. }

  1. public SerializationConfig(BaseSettings base, SubtypeResolver str, SimpleMixInResolver mixins, RootNameLookup rootNames,

  2. ConfigOverrides configOverrides)

  3. {

  4. super(base, str, mixins, rootNames, configOverrides);

  5. _serFeatures = collectFeatureDefaults(SerializationFeature.class);

  6. _filterProvider = null;

  7. _defaultPrettyPrinter = DEFAULT_PRETTY_PRINTER;

  8. _generatorFeatures = 0;

  9. _generatorFeaturesToChange = 0;

  10. _formatWriteFeatures = 0;

  11. _formatWriteFeaturesToChange = 0;

  12. }

默认情况下,Date类型序列化将调用DateSerializer的_timestamp 方法:

  1. /**

  2. * For efficiency, we will serialize Dates as longs, instead of

  3. * potentially more readable Strings.

  4. */

  5. @JacksonStdImpl

  6. @SuppressWarnings("serial")

  7. public class DateSerializer extends DateTimeSerializerBase<Date> {

  8. ...

  9. @Override

  10. protected long _timestamp(Date value) {

  11. return (value == null) ? 0L : value.getTime();

  12. }

  13. @Override

  14. public void serialize(Date value, JsonGenerator g, SerializerProvider provider) throws IOException {

  15. if (_asTimestamp(provider)) {

  16. g.writeNumber(_timestamp(value));

  17. return;

  18. }

  19. _serializeAsString(value, g, provider);

  20. }

  21. }

DateTimeSerializerBase的_asTimestamp方法:

  1. protected boolean _asTimestamp(SerializerProvider serializers)

  2. {

  3. if (_useTimestamp != null) {

  4. return _useTimestamp.booleanValue();

  5. }

  6. if (_customFormat == null) {

  7. if (serializers != null) {

  8. return serializers.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

  9. }

  10. // 12-Jun-2014, tatu: Is it legal not to have provider? Was NPE:ing earlier so leave a check

  11. throw new IllegalArgumentException("Null SerializerProvider passed for "+handledType().getName());

  12. }

  13. return false;

  14. }

禁用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注解,代替全局设置,是一种更灵活的方法:

  1. @JsonFormat(shape = JsonFormat.Shape.STRING)

  2. private Date birthday;

还可以定义pattern:

  1. @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")

  2. private Date birthday;

当自定义pattern后,将创建新的SimpleDateFormat实例来序列化日期,参见DateTimeSerializerBase的createContextual()方法:

  1. public JsonSerializer<?> createContextual(SerializerProvider serializers, BeanProperty property) throws JsonMappingException

  2. {

  3. ...

  4. if (format.hasPattern()) {

  5. final Locale loc = format.hasLocale() ? format.getLocale() : serializers.getLocale();

  6. SimpleDateFormat df = new SimpleDateFormat(format.getPattern(), loc);

  7. TimeZone tz = format.hasTimeZone() ? format.getTimeZone() : serializers.getTimeZone();

  8. df.setTimeZone(tz);

  9. return withFormat(Boolean.FALSE, df);

  10. }

  11. ...

  12. }

Spring Boot与Jackson ObjectMapper

Spring Boot使用HttpMessageConverters处理HTTP交换中的内容转换。当classpath中存在Jackson时,Jackson2ObjectMapperBuilder将是默认的Converter,源码请查看HttpMessageConverters和WebMvcConfigurationSupport:
HttpMessageConverters

  1. private List<HttpMessageConverter<?>> getDefaultConverters() {

  2. List<HttpMessageConverter<?>> converters = new ArrayList<>();

  3. if (ClassUtils.isPresent("org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport", null)) {

  4. converters.addAll(new WebMvcConfigurationSupport() {

  5. public List<HttpMessageConverter<?>> defaultMessageConverters() {

  6. return super.getMessageConverters();

  7. }

  8. }.defaultMessageConverters());

  9. }

  10. else {

  11. converters.addAll(new RestTemplate().getMessageConverters());

  12. }

  13. reorderXmlConvertersToEnd(converters);

  14. return converters;

  15. }

WebMvcConfigurationSupport

  1. protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {

  2. StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();

  3. stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316

  4. messageConverters.add(new ByteArrayHttpMessageConverter());

  5. messageConverters.add(stringHttpMessageConverter);

  6. messageConverters.add(new ResourceHttpMessageConverter());

  7. messageConverters.add(new ResourceRegionHttpMessageConverter());

  8. messageConverters.add(new SourceHttpMessageConverter<>());

  9. messageConverters.add(new AllEncompassingFormHttpMessageConverter());

  10. ...

  11. if (jackson2Present) {

  12. Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();

  13. if (this.applicationContext != null) {

  14. builder.applicationContext(this.applicationContext);

  15. }

  16. messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));

  17. }

  18. ...

  19. }

默认,Jackson2ObjectMapperBuilder将创建ObjectMapper实例:
Jackson2ObjectMapperBuilder

  1. public <T extends ObjectMapper> T build() {

  2. ObjectMapper mapper;

  3. if (this.createXmlMapper) {

  4. mapper = (this.defaultUseWrapper != null ?

  5. new XmlObjectMapperInitializer().create(this.defaultUseWrapper) :

  6. new XmlObjectMapperInitializer().create());

  7. }

  8. else {

  9. mapper = (this.factory != null ? new ObjectMapper(this.factory) : new ObjectMapper());

  10. }

  11. configure(mapper);

  12. return (T) mapper;

  13. }

ObjectMapper以下属性被禁用:

  • MapperFeature.DEFAULT_VIEW_INCLUSION
  • DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
  • SerializationFeature.WRITE_DATES_AS_TIMESTAMPS

Jackson2ObjectMapperBuilder

  1. private void customizeDefaultFeatures(ObjectMapper objectMapper) {

  2. if (!this.features.containsKey(MapperFeature.DEFAULT_VIEW_INCLUSION)) {

  3. configureFeature(objectMapper, MapperFeature.DEFAULT_VIEW_INCLUSION, false);

  4. }

  5. if (!this.features.containsKey(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {

  6. configureFeature(objectMapper, DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

  7. }

  8. }

JacksonAutoConfiguration

  1. static {

  2. Map<Object, Boolean> featureDefaults = new HashMap<>();

  3. featureDefaults.put(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

  4. FEATURE_DEFAULTS = Collections.unmodifiableMap(featureDefaults);

  5. }

自定义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:

  1. @DateTimeFormat(pattern = "yyyy-MM-dd")

  2. private Date startDate;

两者可以同时使用:

  1. @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")

  2. @DateTimeFormat(pattern = "yyyy-MM-dd")

  3. private Date startDate;

  4. 参考:

  5. https://blog.csdn.net/weixin_44048532/article/details/86647880

Spring Boot中Jackson ObjectMapper应用详解相关推荐

  1. spring boot模板引擎thymleaf用法详解

    spring boot模板引擎thymleaf用法详解 Spring-boot支持FreeMarker.Thymeleaf.jsp.veocity 但是对freemarker和thymeleaf的支持 ...

  2. spring boot(四):thymeleaf使用详解

    spring boot(四):thymeleaf使用详解 在上篇文章springboot(二):web综合开发中简单介绍了一下thymeleaf,这篇文章将更加全面详细的介绍thymeleaf的使用. ...

  3. Spring Boot 使用 Druid 连接池详解

    Spring Boot 使用 Druid 连接池详解 Alibaba Druid 是一个 JDBC 组件库,包含数据库连接池.SQL Parser 等组件,被大量业务和技术产品使用或集成,经历过严苛的 ...

  4. Spring Boot 2.0 的配置详解(图文教程)

    本文来自作者 泥瓦匠 @ bysocket.com 在 GitChat 上分享 「Spring Boot 2.0 的配置详解(图文教程)」 编辑 | 哈比 Spring Boot 配置,包括自动配置和 ...

  5. Spring Boot的每个模块包详解

    Spring Boot的每个模块包详解,具体如下: 1.spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置.日志和YAML. 2.spring-boot-s ...

  6. spring boot 源码解析43-JmxMetricWriter详解

    前言 本文我们来介绍JmxMetricWriter, JmxMetricWriter是依赖于spring jmx 来实现的. 因此本文的开头先介绍一下spring boot 与jmx的集成,然后分析J ...

  7. Spring Boot 配置加载顺序详解

    使用 Spring Boot 会涉及到各种各样的配置,如开发.测试.线上就至少 3 套配置信息了.Spring Boot 可以轻松的帮助我们使用相同的代码就能使开发.测试.线上环境使用不同的配置. 在 ...

  8. Spring AOP中定义切点PointCut详解

    1.AOP是什么? 软件工程有一个基本原则叫做"关注点分离"(Concern Separation),通俗的理解就是不同的问题交给不同的部分去解决,每部分专注于解决自己的问题.这年 ...

  9. (转)Spring Boot(四):Thymeleaf 使用详解

    http://www.ityouknow.com/springboot/2016/05/01/spring-boot-thymeleaf.html 在上篇文章Spring Boot (二):Web 综 ...

最新文章

  1. 谷歌扔下芯片核弹:开源全球首个可制造的PDK,免费帮有缘人实现造芯梦想
  2. 麦肯锡:物联网九大应用潜力无限 2025年经济价值高达11.1万亿美元
  3. Mac系统修改root用户密码,mac切换root用户登录实例演示
  4. 给网页穿上Word马甲
  5. 数据--第49课 - 线性索引查找
  6. SQL order by的用法
  7. quartus支持linux系统,在64位Linux下把Quartus II设置成64位的方法
  8. 杀毒软件误删文件了怎么办?如何恢复被杀毒软件删除的文件
  9. 三星gsat笔试容不容易通过
  10. 2019年网络工程师考试大纲
  11. 阿里云云计算工程师认证(ACP)分享
  12. 今日头条2019春季暑期实习笔试题(非自己做)4-14
  13. C标准库-va_list
  14. python超级简单爬虫
  15. 请客人(客户)吃饭谈点什么好?
  16. python输出乘法式子(HLOJ)(完整解析)
  17. python week 获取 星期 第几周 开始日期 结束日期 星期几
  18. (转)IST:Iterative Shrinkage/Thresholding和Iterative Soft Thresholding
  19. 神经网络与深度学习笔记(二)正向传播与反向传播
  20. IPv6和IPv4的区别

热门文章

  1. 基于Servlet+Jsp实现的酒店客房预定管理系统分前后台
  2. 俞敏洪成功语录15条
  3. umi(3.0.5)版本之二 约定式路由
  4. 异常处理和UDP协议
  5. 基于PHP的在线交友网站管理系统
  6. 《计算机网络》---简答题(二)
  7. 拉勾创始人许单单离职 公司由大股东前程无忧接管继续运营
  8. 第07节:端到端测试的优化策略
  9. 已知男程序员穿格子衫,那么女程序员会穿格子裙吗?
  10. iOS自动化--Spaceship使用实践