1
0
Files
jackson2-to-3-migration/docs/s01-mapper-construction.md
Ankur f0a7053fc9 Jackson 2 to 3 migration companion code
Three Maven modules - jackson2-before (2.22.1), jackson3-after (3.2.1) and a
coexistence module with BOTH majors on one classpath - so every claim in the two
migration guides is executed rather than asserted. Paired class names make the
before/after outputs directly diffable via run-all.sh.

Confirms the guides on wire-format equivalence (10-case suite, zero mismatches),
classpath coexistence and the collapse of four artifacts into one. Corrects nine
points, including that enableDefaultTyping() is still present in Jackson 2.22.1
rather than removed in 2.16, and that the published "after" mapper snippet does
not compile.
2026-08-04 23:29:27 +05:30

59 lines
2.3 KiB
Markdown

# S01 — Mapper construction and immutability
Guide: <https://ankurm.com/jackson-3-migration-guide/> (Steps 2 and 3)
[`before/S01MapperConstruction.java`](../jackson2-before/src/main/java/com/ankurm/migration/before/S01MapperConstruction.java) ·
[`after/S01MapperConstruction.java`](../jackson3-after/src/main/java/com/ankurm/migration/after/S01MapperConstruction.java)
## The guide's "after" snippet does not compile
```java
JsonMapper mapper = JsonMapper.builder()
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) // no such constant
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.serializationInclusion(JsonInclude.Include.NON_NULL) // no such method
.build();
```
Two of those four lines are invalid against Jackson 3.2.1:
- `SerializationFeature.WRITE_DATES_AS_TIMESTAMPS` does not exist. The flag moved to
`tools.jackson.databind.cfg.DateTimeFeature` and now defaults to off, so ISO-8601
output needs no configuration and there is nothing to disable.
- `JsonMapper.Builder.serializationInclusion(...)` does not exist. The real API is
`changeDefaultPropertyInclusion(UnaryOperator<JsonInclude.Value>)`.
The third line is valid but redundant — `FAIL_ON_UNKNOWN_PROPERTIES` already defaults
to `false` in Jackson 3.
## Output
**Jackson 2 — `jackson2-before`**
```
output : {"id":1,"travelDate":"2026-09-15","seatPreference":"aisle"}
after mutation : { "id" : 1, "travelDate" : "2026-09-15", "seatPreference" : "aisle" }
mutation stuck : true
set*() mutators : 40
```
**Jackson 3 — `jackson3-after`**
```
output : {"id":1,"travelDate":"2026-09-15","seatPreference":"aisle"}
forked indented : { "id" : 1, "travelDate" : "2026-09-15", "seatPreference" : "aisle" }
original intact : false
set*() mutators : 0 <- mutation is impossible, not merely discouraged
```
Both produce the same JSON, which is the reassuring part. The interesting lines are the
last two of each.
In Jackson 2 the mapper stays mutable forever. `mapper.enable(INDENT_OUTPUT)` after the
mapper has been injected into a dozen components takes effect for all of them —
`mutation stuck : true`. Forty `set*` methods are available to do it with.
In Jackson 3 there are zero. To vary configuration you fork: `rebuild()` returns a
builder seeded from the existing mapper, and the original is untouched
(`original intact : false`).