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.
This commit is contained in:
58
docs/s01-mapper-construction.md
Normal file
58
docs/s01-mapper-construction.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# 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`).
|
||||
Reference in New Issue
Block a user