FasterXML / FasterXML/jackson-databind

Spring Boot 4 / Jackson 3 ignores field default value during @RequestBody deserialization

Open
#6,100 2 comments 0 reactions 0 assignees View on GitHub
lombok spring to-evaluate
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.