Skip to content

Migrate from Jackson 2.x to Jackson 3 (tools.jackson) (#430)#431

Merged
wnm3 merged 9 commits into
masterfrom
jackson-3-migration
Jul 7, 2026
Merged

Migrate from Jackson 2.x to Jackson 3 (tools.jackson) (#430)#431
wnm3 merged 9 commits into
masterfrom
jackson-3-migration

Conversation

@wnm3

@wnm3 wnm3 commented Jul 7, 2026

Copy link
Copy Markdown
Member

Summary

Migrates JSONata4Java from com.fasterxml.jackson 2.x to tools.jackson 3.2.0 and cuts the major version to 3.0.0. Closes #430.

  • Dependencies (pom.xml): switch to tools.jackson.core:jackson-databind and tools.jackson.dataformat:jackson-dataformat-xml 3.2.0; remove the Jackson 2.x jackson-databind and jackson-dataformat-xml blocks (woodstox-core retained); bump project version 2.6.43.0.0.
  • Package/API renames across main + test: com.fasterxml.jackson.*tools.jackson.*, TextNodeStringNode, JsonFactorytools.jackson.core.json.JsonFactory, JsonProcessingExceptionJacksonException, JsonMappingExceptionDatabindException, immutable JsonMapper/XmlMapper builders.
  • Version string bumped in README.md (×3) and the launch scripts tester.sh, testerui.sh, testerui.cmd.

Behavior-preserving fixes for Jackson 3 default/API changes

No test assertion or expected value was changed — every fix restores the Jackson 2 behavior at its source:

  • MatchFunction/ReplaceFunction: guard the pattern emptiness checks so a POJONode-wrapped RegularExpression never reaches the now-throwing asText(); the boolean logic is identical to Jackson 2.
  • ArrayUtils.compare: pass "" as the asText() default so container operands coerce to "" (Jackson 2 behavior) instead of throwing.
  • AgnosticTestSuite: normalize whole-number doubles with (long) d, replicating Jackson 2's silent narrowing (Jackson 3's asLong() throws on out-of-long-range values).
  • Utils test mapper: disable FAIL_ON_TRAILING_TOKENS to restore the Jackson 2 default so existing test inputs parse identically.
  • catch (IOException)catch (JacksonException) where Jackson 3 methods no longer throw checked IOException.

Documentation

  • Added a "Retained Jackson 2 behaviors (as-built)" section to docs/specs/Jackson-3-Migration-Design.md recording each compatibility decision above (with how to reverse it if the project later adopts the stricter Jackson 3 semantics), plus the pre-existing Tester EOF NPE, the intentionally-tolerated "[\"h11\", \"h21\"]]" trailing-] test-data typo, and the acceptable transitive jackson-annotations dependency.
  • Added explanatory comments at the MatchFunction/ReplaceFunction guard sites so the isTextual()-guarded emptiness checks are self-documenting.

Maven build-warning cleanup (unrelated to Jackson)

Fixed three pre-existing pom.xml warnings that appeared on every build:

  • bnd private-reference (×2): added com.api.jsonata4java.expressions.regex to Export-Package — the exported com.api.jsonata4java / com.api.jsonata4java.expressions packages expose regex types (RegexEngine, RegexPattern, …) in their public API, so that sub-package must be exported too.
  • additionalClasspathElements unknown (×2): removed the empty element from maven-compiler-plugin (not a valid parameter).
  • excludes unknown: removed from the maven-assembly-plugin single goal (not a valid parameter; silently ignored — no effect on the produced jar).

A separate gpg.passphrase deprecation warning originates from the developer’s local ~/.m2/settings.xml, not this repo, and is resolved locally via gpg-agent.

Verification

  • mvn clean testBUILD SUCCESS, 1223 tests, 0 failures, 93 skipped.
  • mvn package → builds JSONata4Java-3.0.0.jar; OSGi Import-Package header references only tools.jackson.* [3.2,4) (no com.fasterxml.jackson.*).
  • dependency:tree shows only tools.jackson.*:3.2.0 plus the acceptable transitive jackson-annotations.
  • Tester CLI evaluates end-to-end ($sort([3,1,2])[1,2,3]); XML round-trip smoke-tested via XmlMapper.builder().

Notes

  • Pre-existing (unrelated to this migration) Tester REPL NullPointerException on stdin EOF at Tester.java:156 was left as-is (now recorded in the design spec's known-items section).

🤖 Generated with Claude Code

@wnm3

wnm3 commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

Resolves Dependabot alert #7 (CVE-2026-54515 / GHSA-5jmj-h7xm-6q6v, jackson-databind, medium / CVSS 5.3).

The default branch's pom.xml is in a half-migrated state and still declares the vulnerable com.fasterxml.jackson.core:jackson-databind:2.22.0 (vulnerable range >= 2.22.0, < 2.22.1; patched in 2.22.1), which is what triggers the alert.

This PR removes the legacy com.fasterxml.jackson.core/dataformat databind entries entirely, leaving only tools.jackson:3.2.0. Since 3.2.0 > 3.1.4 (the 3.x patched version), the resolved dependency is beyond the fix and not in any vulnerable range — dependency:tree shows only tools.jackson.core:jackson-databind:3.2.0 / jackson-core:3.2.0. The one remaining com.fasterxml artifact is the transitive jackson-annotations:2.22, which is not affected by this advisory (it's a jackson-databind bug).

Merging this PR therefore clears alert #7. (Real-world exposure was already negligible: JSONata4Java parses JSON into a tree via readTree/JsonNode rather than doing POJO bean deserialization with @JsonIgnoreProperties + ACCEPT_CASE_INSENSITIVE_PROPERTIES, so the vulnerable code path isn't reachable through its API.)

wnm3 and others added 9 commits July 7, 2026 17:29
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: wnm3 <wnm3@us.ibm.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: wnm3 <wnm3@us.ibm.com>
…cedure.txt (#430)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: wnm3 <wnm3@us.ibm.com>
Move the codebase from com.fasterxml.jackson 2.x to tools.jackson 3.2.0.

- pom.xml: use tools.jackson.core:jackson-databind and
  tools.jackson.dataformat:jackson-dataformat-xml 3.2.0; remove the
  Jackson 2.x databind and dataformat-xml deps (woodstox-core retained);
  bump project version 2.6.4 -> 3.0.0.
- Package/class/method renames across main and test sources:
  com.fasterxml.jackson.* -> tools.jackson.*, TextNode -> StringNode,
  JsonFactory -> tools.jackson.core.json.JsonFactory,
  JsonProcessingException -> JacksonException,
  JsonMappingException -> DatabindException, immutable mapper builders.

Behavior-preserving fixes for Jackson 3 default/API changes (no test
assertion or expected value was changed):
- MatchFunction/ReplaceFunction: guard the pattern emptiness checks so a
  POJONode-wrapped RegularExpression never reaches the now-throwing
  asText(); logic is identical to Jackson 2.
- ArrayUtils.compare: pass "" default to asText() so container operands
  coerce to "" as they did under Jackson 2 instead of throwing.
- AgnosticTestSuite: normalize whole-number doubles with (long) d,
  replicating Jackson 2's silent narrowing (Jackson 3's asLong() throws
  on out-of-long-range values).
- Utils test mapper: disable FAIL_ON_TRAILING_TOKENS to restore the
  Jackson 2 default so existing test inputs parse identically.
- catch (IOException) -> catch (JacksonException) where Jackson 3 methods
  no longer throw checked IOException.
- README and launch scripts (tester.sh, testerui.sh, testerui.cmd):
  version 2.6.4 -> 3.0.0.

Verified: mvn clean test green (1223 tests, 0 failures, 93 skipped);
mvn package builds JSONata4Java-3.0.0.jar with an OSGi Import-Package
header referencing only tools.jackson.* [3.2,4); Tester CLI evaluation
and XML round-trip smoke-tested.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: wnm3 <wnm3@us.ibm.com>
- Add a "Retained Jackson 2 behaviors (as-built)" section to the design
  spec listing each compatibility decision (container asText(""),
  POJONode emptiness guards, (long) d narrowing, FAIL_ON_TRAILING_TOKENS,
  unchecked-exception catches), plus the pre-existing Tester EOF NPE and
  the acceptable transitive jackson-annotations dependency.
- Add explanatory comments at the MatchFunction/ReplaceFunction guard
  sites so the isTextual()-guarded emptiness checks are self-documenting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: wnm3 <wnm3@us.ibm.com>
…shes (#433)

Jackson 3 makes asInt()/asLong()/textValue()/asBoolean() fail-fast: they
throw JsonNodeException for out-of-range or wrong-type nodes where Jackson 2
silently narrowed/coerced. Several unchanged call sites therefore flipped from
"return a value" to "crash with a raw Jackson exception". Fix them to use the
widest-safe representation (BigInteger/double) or a controlled JSONata error,
matching jsonata.org 2.2.1 where known.

#433 numeric coercion:
- ExpressionsVisitor.isWholeNumber(JsonNode): use the double overload instead
  of asInt()==asDouble() (threw for integral doubles > int range, e.g. 1e19).
- Array index: only select when canConvertToInt(); out-of-int-range indices are
  out of bounds and select nothing (e.g. ["a","b"][3000000000] -> undefined).
- Range visitSeq: compute bounds and size with BigInteger, raising the controlled
  "sequence too big" error for [1..1e19]/[1..3000000000] (also fixes a latent int
  count overflow).
- Unary minus: negate an out-of-long-range BigIntegerNode exactly.
- Equality (=) and ordering (< > <= >=): compare integral operands via exact
  bigIntegerValue(), hardening the same crash class on BigInteger operands.
- SumFunction: oversized integral elements fall back to the double-sum path.
- FromMillis/FromMillisZoned: convert an out-of-range magnitude to a controlled
  "Number out of range" error while preserving fractional-millis truncation.
- FormatBase: use the full long value + Long.toString instead of a 32-bit int
  ($formatBase(5890840712243076) -> "5890840712243076", was "1008002948").

Related migration compatibility fixes swept in:
- JoinFunction (#434): every element must be a string; error on any non-string
  (including nested arrays) instead of flattening, matching the reference and
  avoiding textValue() throwing.
- BooleanUtils: return false for a BinaryNode (JSON/reference has no binary type;
  Jackson 3's no-arg asBoolean() throws) consistent with prior behavior.
- Ordering operators: array/object operands raise "must evaluate to numeric or
  string values" rather than returning null.

Adds BasicExpressionsTests.testOutOfRangeNumericCoercion documenting the fixed
behavior. Full suite: 1223 run, 0 failures, 0 errors, 93 skipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: wnm3 <wnm3@us.ibm.com>
- Export com.api.jsonata4java.expressions.regex so bnd no longer flags
  it as a private reference leaked through the public API of the
  com.api.jsonata4java and com.api.jsonata4java.expressions exports.
- Remove empty <additionalClasspathElements/> from maven-compiler-plugin
  (not a valid parameter for that plugin).
- Remove <excludes> from maven-assembly-plugin single goal (not a valid
  parameter; exclusions belong in an assembly descriptor).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: wnm3 <wnm3@us.ibm.com>
Record the pom.xml build-warning fixes (bnd private-reference exports,
invalid maven-compiler-plugin/maven-assembly-plugin parameters) and note
that the gpg.passphrase deprecation originates from local settings.xml,
not the project pom.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: wnm3 <wnm3@us.ibm.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: wnm3 <wnm3@us.ibm.com>
@wnm3 wnm3 force-pushed the jackson-3-migration branch from 9831c86 to a563a76 Compare July 7, 2026 21:29
@wnm3 wnm3 merged commit 01f1157 into master Jul 7, 2026
4 checks passed
@wnm3 wnm3 mentioned this pull request Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate code from com.fasterxml.jackson.core to tools.jackson.core

1 participant