# S04 — Modules, records, Optional and dates
Guide: (Step 5) and the "Dependency Footprint" table
[`before/S04ModulesAndRecords.java`](../jackson2-before/src/main/java/com/ankurm/migration/before/S04ModulesAndRecords.java) ·
[`after/S04ModulesAndRecords.java`](../jackson3-after/src/main/java/com/ankurm/migration/after/S04ModulesAndRecords.java)
The clearest win in the whole migration. Compare the two poms:
**[`jackson2-before/pom.xml`](../jackson2-before/pom.xml)** — four artifacts plus a compiler flag:
```xml
com.fasterxml.jackson.core:jackson-databind
com.fasterxml.jackson.datatype:jackson-datatype-jsr310
com.fasterxml.jackson.datatype:jackson-datatype-jdk8
com.fasterxml.jackson.module:jackson-module-parameter-names
...
-parameters
```
**[`jackson3-after/pom.xml`](../jackson3-after/pom.xml)** — one artifact, no compiler args:
```xml
tools.jackson.core:jackson-databind
```
The three module classes have no `tools.jackson` equivalent, so leaving the
`registerModule` calls in place is a compile error, not a no-op. Delete them.
## Output
**Jackson 2 — `jackson2-before`**
```
with modules : {"id":1,"departure":"2026-09-15","seat":"12A"}
round-trip : TravelPlan[id=1, departure=2026-09-15, seat=Optional[12A]]
bare mapper : FAILS -> InvalidDefinitionException
bare, dates only: FAILS -> InvalidDefinitionException
```
**Jackson 3 — `jackson3-after`**
```
no modules : {"id":1,"departure":"2026-09-15","seat":"12A"}
round-trip : TravelPlan[id=1, departure=2026-09-15, seat=Optional[12A]]
dates : {"d":"2026-09-15"}
empty Optional : {"id":2,"departure":"2026-09-16","seat":null}
```
The first two lines are byte-identical across versions. The difference is everything
that had to be set up to get there.
The `bare mapper` lines in the Jackson 2 output are the point: without the modules, a
Jackson 2 mapper cannot serialise `Optional` or `LocalDate` at all — it throws
`InvalidDefinitionException`. The Jackson 3 mapper in the "after" file has no modules
registered because there are none to register.