Spring Boot 4 用的是 Jackson 3,包名和很多 API 都变了。哪些代码编译不过?默认行为有什么不同?spring.jackson.* 的配置还有效吗?这篇用 Jackson 2.21.5 与 3.1.5 同一份代码逐项实测。
Jackson 2 的 classpath:jackson-annotations-2.21、jackson-core-2.21.5、jackson-databind-2.21.5、jackson-datatype-jdk8-2.21.5、jackson-datatype-jsr310-2.21.5 Jackson 3 的 classpath:jackson-annotations-2.21、jackson-core-3.1.5、jackson-databind-3.1.5 jackson-databind-3.1.5.jar 里是否含 java.time 支持(tools.jackson.databind.ext.javatime):True jackson-annotations 里的包:com.fasterxml.jackson.annotation
core 与 databind 搬到 tools.jackson,注解包不变,java.time 内置。
Jackson 2:通过 19 / 20;Jackson 3(只换包名):通过 8 / 20
new ObjectMapper():2→通过;3→通过
mapper.configure(feature, boolean):2→通过;3→失败(cannot find symbol)
mapper.enable(SerializationFeature.…):2→通过;3→失败(cannot find symbol)
mapper.disable(DeserializationFeature.…):2→通过;3→失败(cannot find symbol)
catch (JsonProcessingException e):2→通过;3→失败(cannot find symbol)
catch (IOException e):2→通过;3→失败(exception IOException is never thrown in body of correspondi)
不写 try/catch 调用 writeValueAsString:2→失败(unreported exception JsonProcessingException; must);3→通过
registerModule(new JavaTimeModule()):2→通过;3→失败(package tools.jackson.datatype.jsr310 does not exist)
mapper.setSerializationInclusion(NON_NULL):2→通过;3→失败(cannot find symbol)
mapper.setPropertyNamingStrategy(…):2→通过;3→失败(cannot find symbol)
JsonNode.fields():2→通过;3→失败(cannot find symbol)
JsonNode.isTextual() / asText():2→通过;3→通过
JsonSerializer 子类:2→通过;3→失败(cannot find symbol)
JsonDeserializer 子类:2→通过;3→失败(cannot find symbol)
@JsonProperty 注解(annotation 包):2→通过;3→通过
mapper.writerWithDefaultPrettyPrinter():2→通过;3→通过
JsonMapper.builder().build():2→通过;3→通过
TypeReference(core.type):2→通过;3→通过
mapper.getFactory().createGenerator(Writer):2→通过;3→失败(cannot find symbol)
mapper.convertValue / valueToTree:2→通过;3→通过
再用 Jackson 3 自己的写法验证 8 段:通过 7 段
JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build():通过
catch (JacksonException e):通过
JsonNode.properties():通过
ValueSerializer 子类:通过
ValueDeserializer 子类:通过
builder().propertyNamingStrategy(SNAKE_CASE):通过
DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS:通过
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS:失败(cannot find symbol)只换包名只有 8 / 20 能编译:configure、异常类、JsonNode.fields、序列化器基类等要改写。
[Jackson 2.21.5,new ObjectMapper()]
LocalDate.of(2026,10,23) → 异常 InvalidDefinitionException
new java.util.Date(0) → 0
Duration.ofSeconds(90) → 异常 InvalidDefinitionException
Optional.of(1) / Optional.empty() → 异常 InvalidDefinitionException / 异常 InvalidDefinitionException
字段声明顺序 b、a、c → {"b":"1","a":"2","c":3}
LinkedHashMap 插入顺序 z、a、m → {"z":1,"a":2,"m":3}
空对象 new Empty() → 异常 InvalidDefinitionException
{"n":1,"zzz":2} 读进只有 n 的类 → 异常 UnrecognizedPropertyException
{"n":null} 读进 int 字段 → 0
{"n":1.9} 读进 int 字段 → 1
{"n":"7"} 读进 int 字段 → 7
[Jackson 2.21.5,再注册 JavaTimeModule 与 Jdk8Module]
LocalDate.of(2026,10,23) → [2026,10,23]
new java.util.Date(0) → 0
Duration.ofSeconds(90) → 90.000000000
Optional.of(1) / Optional.empty() → 1 / null
字段声明顺序 b、a、c → {"b":"1","a":"2","c":3}
LinkedHashMap 插入顺序 z、a、m → {"z":1,"a":2,"m":3}
空对象 new Empty() → 异常 InvalidDefinitionException
{"n":1,"zzz":2} 读进只有 n 的类 → 异常 UnrecognizedPropertyException
{"n":null} 读进 int 字段 → 0
{"n":1.9} 读进 int 字段 → 1
{"n":"7"} 读进 int 字段 → 7
[Jackson 3.1.5,JsonMapper.builder().build()]
LocalDate.of(2026,10,23) → "2026-10-23"
new java.util.Date(0) → "1970-01-01T00:00:00.000Z"
Duration.ofSeconds(90) → "PT1M30S"
Optional.of(1) / Optional.empty() → 1 / null
字段声明顺序 b、a、c → {"a":"2","b":"1","c":3}
LinkedHashMap 插入顺序 z、a、m → {"z":1,"a":2,"m":3}
空对象 new Empty() → {}
{"n":1,"zzz":2} 读进只有 n 的类 → 1
{"n":null} 读进 int 字段 → 异常 MismatchedInputException
{"n":1.9} 读进 int 字段 → 1
{"n":"7"} 读进 int 字段 → 7Jackson 3 的默认:ISO 日期、字母序、未知属性不失败、null 读 int 失败。
starter-web 带进来的 Jackson jar:jackson-annotations-2.21、jackson-core-3.1.5、jackson-databind-3.1.5、spring-boot-jackson-4.0.8、spring-boot-starter-jackson-4.0.8
加上 spring-boot-jackson2 与 Jackson 2 databind 之后多出的 Jackson jar:jackson-core-2.21.5、jackson-databind-2.21.5、jackson-datatype-jdk8-2.21.5、jackson-datatype-jsr310-2.21.5、jackson-module-parameter-names-2.21.5、spring-boot-jackson2-4.0.8
[默认]
GET /d → 200 {"day":"2026-10-23","name":"x","nothing":null,"camelCase":1}
POST /p {"n":1,"zzz":2} → 200 ok n=1;POST /p {"n":null} → 400 {"timestamp":"2026-10-23T07:11:44.029Z","status":4
bean tools.jackson.databind.ObjectMapper → [jacksonJsonMapper]
bean tools.jackson.databind.json.JsonMapper → [jacksonJsonMapper]
bean com.fasterxml.jackson.databind.ObjectMapper → (类不在 classpath 上)
[spring.jackson.serialization.indent-output=true]
GET /d → 200 {↵ "day" : "2026-10-23",↵ "name" : "x",↵ "nothing" : null,↵ "camelCase" : 1↵}
POST /p {"n":1,"zzz":2} → 200 ok n=1;POST /p {"n":null} → 400 {
"timestamp" : "2026-10-23T07:11:45.444Z",
"s
[spring.jackson.default-property-inclusion=non_null]
GET /d → 200 {"day":"2026-10-23","name":"x","camelCase":1}
POST /p {"n":1,"zzz":2} → 200 ok n=1;POST /p {"n":null} → 400 {"timestamp":"2026-10-23T07:11:46.862Z","status":4
[spring.jackson.property-naming-strategy=SNAKE_CASE]
GET /d → 200 {"day":"2026-10-23","name":"x","nothing":null,"camel_case":1}
POST /p {"n":1,"zzz":2} → 200 ok n=1;POST /p {"n":null} → 400 {"timestamp":"2026-10-23T07:11:48.263Z","status":4
[spring.jackson.serialization.write-dates-as-timestamps=true] 启动失败:Reason: failed to convert java.lang.String to tools.jackson.databind.SerializationFeature (caused by java.lang.IllegalArgumentException: No enum constant tools.jackson.databind.SerializationFeature.write-dates-as-timestamps)
[spring.jackson.datatype.datetime.write-dates-as-timestamps=true]
GET /d → 200 {"day":[2026,10,23],"name":"x","nothing":null,"camelCase":1}
POST /p {"n":1,"zzz":2} → 200 ok n=1;POST /p {"n":null} → 400 {"timestamp":1792739511101,"status":400,"error":"B
[spring.jackson.use-jackson2-defaults=true]
GET /d → 200 {"day":"2026-10-23","name":"x","nothing":null,"camelCase":1}
POST /p {"n":1,"zzz":2} → 200 ok n=1;POST /p {"n":null} → 200 ok n=0
[spring.jackson.deserialization.fail-on-unknown-properties=true]
GET /d → 200 {"day":"2026-10-23","name":"x","nothing":null,"camelCase":1}
POST /p {"n":1,"zzz":2} → 400 {"timestamp":"2026-10-23T07:11:55.451Z","status":400,"error";POST /p {"n":null} → 400 {"timestamp":"2026-10-23T07:11:55.463Z","status":4
[加了 spring-boot-jackson2 与 Jackson 2]
GET /d → 200 {"day":"2026-10-23","name":"x","nothing":null,"camelCase":1}
POST /p {"n":1,"zzz":2} → 200 ok n=1;POST /p {"n":null} → 400 {"timestamp":"2026-10-23T07:11:57.979Z","status":4
bean tools.jackson.databind.ObjectMapper → [jacksonJsonMapper]
bean tools.jackson.databind.json.JsonMapper → [jacksonJsonMapper]
bean com.fasterxml.jackson.databind.ObjectMapper → [jackson2ObjectMapper]容器里只有 JsonMapper;大多数 spring.jackson.* 仍有效,write-dates-as-timestamps 要换位置;可用 use-jackson2-defaults 或 spring-boot-jackson2 过渡。