FasterXML / FasterXML/jackson-databind
Spring Boot 4 / Jackson 3 ignores field default value during @RequestBody deserialization
- Dominant language
- Java
- Stars
- 3.7k
- Forks
- 1.5k
- Avg merge
- 3d 6h
- Merged PRs (30d)
- 28
Description
### Describe your Issue
After upgrading from Spring Boot 3.x to Spring Boot 4, I noticed a change in Jackson deserialization behavior.
I have a DTO used as a @RequestBody:
```java
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MyClass{
@Builder.Default
private boolean historical = true;
}
```
When the request body does not contain the `historical` field:
```json
{}
```
with Spring Boot 3 / Jackson 2, the value of `historical` was `true`, because the field initializer was applied.
After upgrading to Spring Boot 4 (and Jackson 3), `historical` becomes `false`.
During debugging I noticed that:
- With the default configuration, Jackson invokes the Lombok-generated `@AllArgsConstructor`.
- With `spring.jackson.use-jackson2-defaults=true`, Jackson invokes the no-args constructor and the default field value (`true`) is preserved.
- Setting `spring.jackson.mapper.detect_parameter_names=false` also restores the previous behavior.
Looking at the generated code, the no-args constructor initializes the field correctly:
```java
public IssueFilterDto() {
this.historical = true;
}
```
while the all-args constructor receives a primitive `boolean historical`, which becomes `false` when the property is missing from the JSON.
My questions are:
1. Is this expected behavior in Jackson 3 / Spring Boot 4?
2. Is there a recommended way to keep DTO default values defined at the field level without relying on `spring.jackson.use-jackson2-defaults=true`?
3. Is constructor-based deserialization now the preferred approach, and if so, how should default values be handled when a property is absent from the JSON?
I would like to avoid relying on the Jackson 2 compatibility mode and follow the recommended approach going forward.
For additional context, switching the field from `boolean` to `Boolean` did not solve the issue in my case.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by reproducing the @RequestBody deserialization shown with Jackson 3, the Lombok DTO, and an absent historical property. Compare the default configuration with spring.jackson.use-jackson2-defaults=true and mapper.detect_parameter_names=false, then determine whether the constructor selection and field default behavior are expected. Done requires a documented recommendation or a confirmed change for preserving defaults.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 38/100