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.
2.8 KiB
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 has one dependency, no
jackson-datatype-jdk8, no jackson-module-parameter-names, and no -parameters
compiler argument.
C01 — records
{"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
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
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.
C04 — sealed auto-discovery
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.