Skip to content

feat(framework,actuator,common): replace fastjson with jackson#6701

Merged
lvs0075 merged 17 commits into
tronprotocol:developfrom
halibobo1205:feat/jackjson
May 8, 2026
Merged

feat(framework,actuator,common): replace fastjson with jackson#6701
lvs0075 merged 17 commits into
tronprotocol:developfrom
halibobo1205:feat/jackjson

Conversation

@halibobo1205
Copy link
Copy Markdown
Collaborator

@halibobo1205 halibobo1205 commented Apr 23, 2026

Summary

Replace com.alibaba:fastjson with Jackson-backed drop-in wrappers (org.tron.json.{JSON, JSONObject, JSONArray, JSONException}). No external API changes — all HTTP and JSON-RPC responses remain identical.

Motivation

  • Fastjson 1.2.83 is EOL with 20+ CVEs including critical RCE
  • Upgrade jackson-databind 2.18.3 → 2.18.6 (GHSA-72hv-8253-57qq)
  • Unify JSON handling (previously split between Jackson and Fastjson)

Core changes

(common):

  • Add org.tron.json wrappers backed by a shared ObjectMapper
  • Remove fastjson from common/build.gradle
  • Expose maxNestingDepth / maxTokenCount on CommonParameter and NodeConfig.HttpConfig, with defaults 100 / 100_000 in reference.conf

(framework): HTTP & servlet changes

  • Swap imports from com.alibaba.fastjsonorg.tron.json across all HTTP servlets, JSON-RPC layer, and event/log parsers

Compatibility

Area Fastjson default behavior Jackson behavior in this PR Compatibility
Unquoted field names Accepts {a:1} ALLOW_UNQUOTED_FIELD_NAMES 🟢 Compatible
Single quotes Accepts {'a':'1'} ALLOW_SINGLE_QUOTES 🟢 Compatible
Single trailing comma Accepts {"a":1,} and [1,2,] ALLOW_TRAILING_COMMA 🟢 Compatible
Repeated / arbitrary commas Accepts cases like {"a":1,,,,} and [1,,2] Rejects 🔴 Not supported
NaN Accepts and treats as null Rejects 🔴 Not supported
Infinity / -Infinity Rejects Rejects 🟢 Compatible
Leading plus sign Accepts +123, +0.5 ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS 🟢 Compatible
Signed leading decimal Accepts +.5 ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS 🟢 Compatible
Unsigned leading decimal Rejects .5 ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS 🔴 More permissive than Fastjson. Jackson cannot accept +.5 without also accepting .5.
Trailing decimal point Accepts 5. ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS 🟢 Compatible
Leading zeros Accepts 007 as 7 ALLOW_LEADING_ZEROS_FOR_NUMBERS 🟢 Compatible
Unescaped control chars in strings Accepts raw control chars such as newline/tab in strings Accepts via ALLOW_UNESCAPED_CONTROL_CHARS 🟢 Compatible
Non-standard backslash escapes Rejects "\q" Rejects 🟢 Compatible
Java-style comments Accepts // ... and /* ... */ ALLOW_JAVA_COMMENTS 🟢 Compatible
Uppercase NULL token Accepts bare NULL as null Rejects 🔴 Not supported
Uppercase boolean tokens Rejects TRUE / FALSE Rejects 🟢 Compatible
Floating point numeric type Uses BigDecimal by default USE_BIG_DECIMAL_FOR_FLOATS 🟢 Compatible
Unknown POJO fields Ignores unknown fields by default FAIL_ON_UNKNOWN_PROPERTIES = false 🟢 Compatible
Empty bean serialization Serializes empty beans as {} FAIL_ON_EMPTY_BEANS = false 🟢 Compatible
Null-valued fields serialization Omits null fields by default unless WriteMapNullValue is enabled JsonInclude.Include.NON_NULL 🟢 Compatible

Caution

The table above covers only the currently known differences in Fastjson/Jackson behavior verified during this migration. There may still be other unknown edge-case differences. New code and clients are strongly encouraged to use strict standard JSON instead of relying on Fastjson-specific lenient parsing behavior.

Configuration

Two new node.http keys (defaults shown):

node {
  http {
    maxNestingDepth = 100      # Jackson default 1000
    maxTokenCount   = 100000   # Jackson default Long.MAX_VALUE
  }
}

Beyond either ceiling, parsing fails with StreamConstraintsException before any business logic runs. Defaults are sized to accommodate every legitimate java-tron HTTP payload comfortably.

Build:

  • Update Jackson to 2.18.6
  • Remove fastjson

close #6607

Comment thread common/src/main/java/org/tron/json/JSON.java
Comment thread actuator/src/main/java/org/tron/core/vm/trace/ProgramTrace.java Outdated
Comment thread common/src/main/java/org/tron/json/JSON.java Outdated
Comment thread framework/src/main/java/org/tron/core/services/http/Util.java
Comment thread common/src/main/java/org/tron/common/utils/JsonUtil.java
@yanghang8612
Copy link
Copy Markdown
Collaborator

Direction is right — fastjson 1.2.83 has been a long-standing security overhang, and consolidating on Jackson + a thin wrapper is the obvious move. Waiting on the MUST items @lxcmyf and @waynercheung raised before LGTM.

One additional question worth pinning down in the PR description: after this change, are there any remaining com.alibaba.fastjson imports reachable anywhere in the tree — or does this fully retire the dependency? The diff summary doesn't show the build.gradle side, and a grep -r 'com.alibaba.fastjson' --include='*.java' result in the PR body would make the "no more fastjson" claim explicit and let dependency scanners (GHSA, Snyk) close the finding cleanly.

Also worth a sentence in the PR description on hot-path performance posture: fastjson 1.2.x has a historically-fast parse path, and Jackson has different characteristics under LargeJsonPayload + /wallet/* throughput. If there's even a rough benchmark for DeployContractServlet / TriggerSmartContractServlet JSON-decode latency pre/post, that closes the loop on "drop-in" covering both correctness and perf.

@halibobo1205
Copy link
Copy Markdown
Collaborator Author

@yanghang8612
Fastjson fully retired:
Yes. The fastjson dependency has been removed from build.gradle (diff). If any com.alibaba.fastjson import remained, the build would fail at compile time — so a passing CI already proves zero remaining references.

Performance:
The JSON parsing hot path for /wallet/* endpoints goes through JsonFormat.java (a custom protobuf-to-JSON serializer/parser with its own Tokenizer), not through the Jackson ObjectMapper. Jackson is only used for lightweight operations: extracting a few fields (visible, type, value, etc.) from the top-level request JSON. The actual heavy lifting — protobuf message construction and field-by-field parsing — is handled by JsonFormat.merge(), which is unchanged in this PR. So there is no meaningful parse-latency delta on the hot path. Performance benchmarks will be added as a follow-up.

Comment thread common/src/main/java/org/tron/json/JSONObject.java
Comment thread common/src/main/java/org/tron/json/TypeUtils.java
Comment thread common/src/main/java/org/tron/json/TypeUtils.java
Comment thread common/src/main/java/org/tron/json/TypeUtils.java
Comment thread common/src/main/java/org/tron/json/TypeUtils.java
Comment thread common/src/main/java/org/tron/json/TypeUtils.java
Copy link
Copy Markdown
Collaborator

@waynercheung waynercheung left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Copy Markdown
Collaborator

@yanghang8612 yanghang8612 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Replace `com.alibaba:fastjson` with Jackson-backed drop-in
wrappers (`org.tron.json.{JSON, JSONObject, JSONArray, JSONException}`).
No external API changes — all HTTP and JSON-RPC responses remain identical.

Motivation:
- Fastjson 1.2.83 is EOL with 20+ CVEs including critical RCE
- Upgrade jackson-databind 2.18.3 → 2.18.6 (GHSA-72hv-8253-57qq)
- Unify JSON handling (previously split between Jackson and Fastjson)

Core changes (common):
- Add org.tron.json wrappers backed by a shared ObjectMapper
- Remove fastjson from common/build.gradle

HTTP & servlet changes (framework):
- Swap imports from com.alibaba.fastjson → org.tron.json across
all HTTP servlets, JSON-RPC layer, and event/log parsers

Test changes:
- Add BaseHttpTest base class for servlet test lifecycle

Build:
- Update jackson to 2.18.6
- Remove fastjson

close tronprotocol#6607
@lvs0075 lvs0075 merged commit 9529fb8 into tronprotocol:develop May 8, 2026
12 checks passed
@github-project-automation github-project-automation Bot moved this to Done in java-tron May 8, 2026
halibobo1205 added a commit to halibobo1205/java-tron that referenced this pull request May 11, 2026
Pre-3.0.0(The previous event-plugin public release is 2.2.0)
event-plugin builds still link against com.alibaba.fastjson, which
was removed from java-tron in tronprotocol#6701. When such a plugin is loaded, the
NoClassDefFoundError surfaces inside the plugin's own worker thread and is
swallowed by its catch(Throwable) handler. The node keeps running while
silently dropping every trigger, leaving operators with no signal that the
event subscription is broken.

Enforce a minimum Plugin-Version at startup in EventPluginLoader.startPlugin
using pf4j's VersionManager (semver). When the descriptor version is below
3.0.0, log a clear upgrade hint and return false; the existing call chain in
Manager.startEventSubscribing wraps that into TronError(EVENT_SUBSCRIBE_INIT)
and aborts node startup instead of silently degrading.
halibobo1205 added a commit to halibobo1205/java-tron that referenced this pull request May 11, 2026
Pre-3.0.0(The previous event-plugin public release is 2.2.0)
event-plugin builds still link against com.alibaba.fastjson, which
was removed from java-tron in tronprotocol#6701. When such a plugin is loaded, the
NoClassDefFoundError surfaces inside the plugin's own worker thread and is
swallowed by its catch(Throwable) handler. The node keeps running while
silently dropping every trigger, leaving operators with no signal that the
event subscription is broken.

Enforce a minimum Plugin-Version at startup in EventPluginLoader.startPlugin
using pf4j's VersionManager (semver). When the descriptor version is below
3.0.0, log a clear upgrade hint and return false; the existing call chain in
Manager.startEventSubscribing wraps that into TronError(EVENT_SUBSCRIBE_INIT)
and aborts node startup instead of silently degrading.
lvs0075 pushed a commit that referenced this pull request May 11, 2026
)

Pre-3.0.0(The previous event-plugin public release is 2.2.0)
event-plugin builds still link against com.alibaba.fastjson, which
was removed from java-tron in #6701. When such a plugin is loaded, the
NoClassDefFoundError surfaces inside the plugin's own worker thread and is
swallowed by its catch(Throwable) handler. The node keeps running while
silently dropping every trigger, leaving operators with no signal that the
event subscription is broken.

Enforce a minimum Plugin-Version at startup in EventPluginLoader.startPlugin
using pf4j's VersionManager (semver). When the descriptor version is below
3.0.0, log a clear upgrade hint and return false; the existing call chain in
Manager.startEventSubscribing wraps that into TronError(EVENT_SUBSCRIBE_INIT)
and aborts node startup instead of silently degrading.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test:flaky topic:api rpc/http related issue

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Feature] Replace fastjson with Jackson

8 participants