bigywater.tech
Spring · 42

HttpMessageConverter 与 Jackson:日期、null、未知字段的坑

返回对象时日期、大整数、null 到底写成什么?前端传各种写法的日期会发生什么,哪些会悄悄出错?XML 请求怎么办?Boot 4 换成 Jackson 3 之后哪些配置要改?这篇在 Spring Boot 4.0.8 上逐项验证。

+58768 年
Instant 字段收到毫秒数 1792391405000(当成秒)后反序列化出的年份,没有报错
1.5 → 1
Long 字段收到 JSON 小数 1.5 时悄悄得到的值
启动失败
Boot 4 里沿用 Jackson 2 的 spring.jackson.serialization.write-dates-as-timestamps 属性时的表现

序列化

实测 · 本机执行输出
  day        → "2026-10-19"
  dt         → "2026-10-19T14:30:05"
  at         → "2026-10-19T06:30:05Z"
  zdt        → "2026-10-19T14:30:05+08:00"
  legacy     → "2026-10-19T06:30:05.000Z"
  big        → (JSON 数字) 9007199254740993
  dec        → (JSON 数字) 12345678901234567890.12
  d          → (JSON 数字) 0.30000000000000004
  color      → "GREEN"
  nul        → null
  opt        → null
  emptyList  → []
  响应头 Content-Type: application/json
  说明:Java 里 big=9007199254740993L,在 JSON 里写成了数字,JavaScript 的 JSON.parse 会把它读成 9007199254740992(超过 2^53 的整数丢精度)。下面用 Python 的 float 模拟:float(9007199254740993) = 9007199254740992

日期写成 ISO 字符串,大整数写成数字,null 和 Optional.empty 都写成 null。

反序列化

实测 · 本机执行输出
  正常 → 200 收到 In[day=2026-10-19, dt=2026-10-19T14:30:05, at=2026-10-19T06:30:05Z, legacy=Mon Oct 19 14:30:05 CST 2026, big=1, color=RED]
  day 写成 2026/10/19 → 400 HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.time.LocalDate` from String "2026/10/19": Failed to deserialize `java.time.Local
  day 写成时间戳数字 → 400 HttpMessageNotReadableException: JSON parse error: Failed to deserialize java.time.LocalDate from epoch day value 1792391405000: Invalid value for EpochDay (valid values 
  dt 带时区后缀 Z → 200 收到 In[day=null, dt=2026-10-19T14:30:05, at=null, legacy=null, big=null, color=null]
  at 写成秒级数字 → 200 收到 In[day=null, dt=null, at=2026-10-19T06:30:05Z, legacy=null, big=null, color=null]
  at 写成毫秒级数字 → 200 收到 In[day=null, dt=null, at=+58768-08-15T21:23:20Z, legacy=null, big=null, color=null]
  legacy 写成毫秒数字 → 200 收到 In[day=null, dt=null, at=null, legacy=Mon Oct 19 14:30:05 CST 2026, big=null, color=null]
  color 写小写 red → 400 HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `Color` from String "red": not one of the values accepted for Enum class: [RED, GREEN]
  color 写不存在的 BLUE → 400 HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `Color` from String "BLUE": not one of the values accepted for Enum class: [RED, GREEN
  未知字段 extra → 200 收到 In[day=null, dt=null, at=null, legacy=null, big=null, color=null]
  big 写成字符串 "123" → 200 收到 In[day=null, dt=null, at=null, legacy=null, big=123, color=null]
  big 写成小数 1.5 → 200 收到 In[day=null, dt=null, at=null, legacy=null, big=1, color=null]

有的写法明确 400,有的写法悄悄通过却丢了信息或值错了。

String 与协商

实测 · 本机执行输出
  GET /text → 200 中文 ok Content-Type: text/plain;charset=UTF-8
  GET /sample Accept: application/xml → 406
  GET /xml-only(produces application/xml,返回 String)→ 200 <a/> Content-Type: application/xml;charset=UTF-8

String 直接按文本写出,没有 XML 转换器时 Accept: application/xml 得 406。

配置

实测 · 本机执行输出
  spring.jackson.default-property-inclusion=non_null:字段 ['day', 'dt', 'at', 'zdt', 'legacy', 'big', 'dec', 'd', 'color', 'opt', 'emptyList'];day="2026-10-19",at="2026-10-19T06:30:05Z",legacy="2026-10-19T06:30:05.000Z"
  spring.jackson.datatype.datetime.write-dates-as-timestamps=true:字段 ['day', 'dt', 'at', 'zdt', 'legacy', 'big', 'dec', 'd', 'color', 'nul', 'opt', 'emptyList'];day=[2026, 10, 19],at=1792391405.0,legacy=1792391405000
  spring.jackson.serialization.write-dates-as-timestamps=true(Jackson 2 时代的写法)→ 启动失败:Failed to bind properties under 'spring.jackson.serialization' to java.util.Map<SerializationFeature, java.lang.Boolean>:;failed to convert java.lang.String to SerializationFeature (caused by java.lang.IllegalArgumentException: No enum constant SerializationFeature.write-dates-as-timestamps)

Jackson 3 把日期开关挪到了 datatype.datetime 下。

分步演示

HttpMessageConverter 与 Jackson
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动。用 Spring Boot 4.0.8 的 SpringApplication(spring-boot-starter-webmvc,内嵌 Tomcat 11,Jackson 3 即 tools.jackson 包);异常文本由继承 ResponseEntityExceptionHandler 的 @RestControllerAdvice 输出;请求用 Python http.client 发出;“JavaScript 读成 9007199254740992”用 Python 的 float 模拟,没有真的在浏览器里跑
    • 没有验证:Jackson 2 兼容模式(spring-boot-jackson2);@JsonFormat / @JsonInclude 注解层面的逐字段控制;自定义 ObjectMapper(JsonMapper)Bean 覆盖 Boot 的默认;Gson 和 JSON-B 转换器;XML 转换器(jackson-dataformat-xml)加入后的行为;请求体的大小限制与流式读取
    京ICP备2026067502号-1京公网安备11010502063487号