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:
47
docs/s02-exception-hierarchy.md
Normal file
47
docs/s02-exception-hierarchy.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# S02 — The exception hierarchy
|
||||
|
||||
Guide: <https://ankurm.com/jackson-3-vs-jackson-2/> ("JacksonException Is Now Unchecked")
|
||||
|
||||
[`before/S02ExceptionHierarchy.java`](../jackson2-before/src/main/java/com/ankurm/migration/before/S02ExceptionHierarchy.java) ·
|
||||
[`after/S02ExceptionHierarchy.java`](../jackson3-after/src/main/java/com/ankurm/migration/after/S02ExceptionHierarchy.java)
|
||||
|
||||
The guide calls this the most dangerous change and it is right. But the failure mode is
|
||||
narrower than "every `catch (IOException)` silently stops catching", and the difference
|
||||
decides how much of your codebase you actually have to audit.
|
||||
|
||||
**Case A — the try block contains only Jackson calls.** `catch (IOException)` becomes a
|
||||
*compile error*: "exception java.io.IOException is never thrown in body of corresponding
|
||||
try statement". The compiler finds these for you. No audit needed.
|
||||
|
||||
**Case B — the try block also does real I/O.** `IOException` is still reachable from the
|
||||
I/O, so the catch block compiles, and it silently stops covering the Jackson call.
|
||||
Nothing warns you. This is the shape that reaches production, and it is what the
|
||||
example runs.
|
||||
|
||||
## Output
|
||||
|
||||
**Jackson 2 — `jackson2-before`**
|
||||
|
||||
```
|
||||
JsonProcessingException extends IOException : true
|
||||
caught by catch (IOException) : JsonParseException
|
||||
writeValueAsString declares : [class com.fasterxml.jackson.core.JsonProcessingException]
|
||||
```
|
||||
|
||||
**Jackson 3 — `jackson3-after`**
|
||||
|
||||
```
|
||||
JacksonException extends RuntimeException : true
|
||||
JacksonException extends IOException : false
|
||||
ESCAPED catch (IOException) : StreamReadException
|
||||
caught by catch (Jackson...) : StreamReadException
|
||||
writeValueAsString declares : [class tools.jackson.core.JacksonException] <- nothing checked
|
||||
```
|
||||
|
||||
So the audit target is narrower and more specific than "grep for `catch (IOException)`":
|
||||
it is `catch (IOException)` blocks that contain **both** I/O and a Jackson call. Those
|
||||
are the ones the compiler cannot help with.
|
||||
|
||||
Note the last line of each. Jackson 3 still *declares* `JacksonException` on
|
||||
`writeValueAsString`, but since it is unchecked, callers are not forced to handle it —
|
||||
which is what lets Jackson calls sit inside lambdas without a wrapper.
|
||||
Reference in New Issue
Block a user