37 runnable examples covering the eight feature posts on ankurm.com, verified against Jackson 3.2.1 on Temurin 21.0.5. Every output committed under docs/ was produced by run-all.sh. Also documents 11 places where the published snippets do not compile or do not behave as printed against a real Jackson 3 build - most notably that writeValueAsString(List<Base>) silently drops the polymorphic type discriminator, so the post's serialised output cannot be read back.
71 lines
2.8 KiB
Markdown
71 lines
2.8 KiB
Markdown
# Part 2 — Records, Optionals and sealed types
|
|
|
|
Post: <https://ankurm.com/jackson-java-records-optionals/>
|
|
|
|
The single biggest simplification in Jackson 3 lands here. All three features are in
|
|
core: the project's [`pom.xml`](../pom.xml) has one dependency, no
|
|
`jackson-datatype-jdk8`, no `jackson-module-parameter-names`, and no `-parameters`
|
|
compiler argument.
|
|
|
|
## C01 — records
|
|
|
|
[`C01RecordRoundTrip.java`](../src/main/java/com/ankurm/jackson3/part2modernjava/C01RecordRoundTrip.java)
|
|
|
|
```
|
|
{"productId":101,"productName":"Wireless Keyboard","unitPrice":49.99}
|
|
Wireless Keyboard
|
|
round-trip equal: true
|
|
```
|
|
|
|
The post's own dependency block here is wrong twice over: it suggests
|
|
`com.fasterxml.jackson.module:jackson-module-parameter-names:3.1.2`, which is both an
|
|
artifact Jackson 3 does not need and a version that does not exist at that coordinate.
|
|
|
|
## C02 — Optional
|
|
|
|
[`C02OptionalFields.java`](../src/main/java/com/ankurm/jackson3/part2modernjava/C02OptionalFields.java)
|
|
|
|
```
|
|
present : {"customerName":"Alice","middleName":"Marie"}
|
|
empty : {"customerName":"Bob","middleName":null}
|
|
absent : {"customerName":"Bob"}
|
|
isPresent: true
|
|
missing -> Optional.empty (null? false)
|
|
```
|
|
|
|
Two behaviours worth committing to memory: an empty `Optional` serialises as `null`
|
|
unless you ask for `NON_ABSENT`, and a *missing* property deserialises to
|
|
`Optional.empty()` rather than to `null`, so the field is never null.
|
|
|
|
## C03 — sealed types with an explicit registry
|
|
|
|
[`C03SealedWithSubTypes.java`](../src/main/java/com/ankurm/jackson3/part2modernjava/C03SealedWithSubTypes.java)
|
|
|
|
```
|
|
Circle with radius: 5.0
|
|
Rectangle 10.0 x 4.0
|
|
lossy : [{"radius":5.0},{"width":10.0,"height":4.0}]
|
|
correct : [{"shapeType":"circle","radius":5.0},{"shapeType":"rectangle","width":10.0,"height":4.0}]
|
|
```
|
|
|
|
Note the `lossy` line. Serialising a `List<Shape>` drops the `shapeType` discriminator,
|
|
because a `List` gives Jackson no element type to dispatch on. This is the same defect
|
|
covered at length in [Part 5](part5-polymorphic.md).
|
|
|
|
## C04 — sealed auto-discovery
|
|
|
|
[`C04SealedAutoDiscovery.java`](../src/main/java/com/ankurm/jackson3/part2modernjava/C04SealedAutoDiscovery.java)
|
|
|
|
Beyond the post: Jackson 3 reads the `permits` clause, so `@JsonSubTypes` can be dropped
|
|
entirely when each permitted type carries `@JsonTypeName`. There is no `@JsonSubTypes`
|
|
anywhere in that file, and a third subtype added later just works.
|
|
|
|
```
|
|
Circle -> {"shapeType":"circle","radius":5.0} -> Circle[radius=5.0]
|
|
Rectangle -> {"shapeType":"rectangle","width":10.0,"height":4.0} -> Rectangle[width=10.0, height=4.0]
|
|
Triangle -> {"shapeType":"triangle","base":3.0,"height":6.0} -> Triangle[base=3.0, height=6.0]
|
|
```
|
|
|
|
In Jackson 2 the `@JsonSubTypes` registry had to be maintained in parallel with
|
|
`permits`, and drifted whenever someone added a case.
|