Skip to content

fix: add serialVersionUID to JSONArray in fastjson1-compatible for Java serialization compatibility - #7698

Merged
wenshao merged 1 commit into
mainfrom
fix/issue-7687-serialversionuid
Aug 2, 2026
Merged

fix: add serialVersionUID to JSONArray in fastjson1-compatible for Java serialization compatibility#7698
wenshao merged 1 commit into
mainfrom
fix/issue-7687-serialversionuid

Conversation

@wenshao

@wenshao wenshao commented Jul 26, 2026

Copy link
Copy Markdown
Member

Issue

Fixes #7687

Problem

com.alibaba.fastjson.JSONArray in the fastjson1-compatible module implements Serializable but was missing an explicit serialVersionUID. Java auto-computes a UID from the class structure, which doesn't match the original fastjson 1.x value (1L). This causes InvalidClassException when deserializing objects previously serialized with fastjson 1.x:

java.io.InvalidClassException: com.alibaba.fastjson.JSONArray; local class incompatible:
  stream classdesc serialVersionUID = 3642856726642946224,
  local class serialVersionUID = 1

Fix

Added private static final long serialVersionUID = 1L; to JSONArray, matching:

  • The original fastjson 1.x JSONArray value
  • The sibling JSONObject class in the same module (which already declares serialVersionUID = 1L)

Test

Added JSONArrayTest_readObject verifying:

  • serialVersionUID equals 1L (via ObjectStreamClass.lookup)
  • Round-trip Java serialization/deserialization works correctly

@wenshao wenshao left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Reviewed. Suggestions are inline.

— qwen3.8-max-preview via Qwen Code /review

Comment thread core/src/main/java/com/alibaba/fastjson2/JSONReaderJSONB.java
Comment thread core/src/test/java/com/alibaba/fastjson2/issues/Issue7669.java
Comment thread core/src/test/java/com/alibaba/fastjson2/issues/Issue7669.java
Comment thread core/src/main/java/com/alibaba/fastjson2/JSONReaderJSONB.java
@mujPhoto

Copy link
Copy Markdown

awesome

@wenshao wenshao left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Reviewed. 1 Suggestion-level finding(s) could not be anchored to a changed line and were dropped; nothing further to act on here.

— qwen3.7-max via Qwen Code /review

@wenshao
wenshao force-pushed the fix/issue-7687-serialversionuid branch from 46efe2f to 2c995ce Compare July 28, 2026 16:29

@wenshao wenshao left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

⚠️ Downgraded from Approve to Comment: self-PR. Reviewed.

— qwen3.8-max-preview via Qwen Code /review

@wenshao

wenshao commented Aug 2, 2026

Copy link
Copy Markdown
Member Author

Code Review

Overview

Adds private static final long serialVersionUID = 1L; to com.alibaba.fastjson.JSONArray in fastjson1-compatible, so that Java-serialized payloads produced by fastjson 1.x can be read back by the compat module (#7687). Plus a new test class with 3 tests.

Verdict: correct and minimal — LGTM. Notes below are mostly about test strength and a residual (pre-existing) interop gap.

Correctness — verified end-to-end

I checked the actual interop scenario rather than relying on the round-trip tests:

  • Serialized JSON.parseArray("[1,\"hello\",{\"id\":123}]") with real fastjson 1.2.83, then deserialized with this PR's fastjson1-compatible classes → succeeds ([1,"hello",{"id":123}], size 3). Without the patch this is the reported InvalidClassException (auto-computed UID 3642856726642946224).
  • The serialized field shape matches 1.x exactly: field name list, erased type Ljava/util/List;, and relatedArray / componentType are transient in both versions. So field-level compatibility is genuinely restored, not just the UID check.
  • JSON (the superclass) is not Serializable and has only static fields, so nothing is silently dropped, and its implicit no-arg constructor satisfies the deserialization requirement.
  • JSONArray was the only Serializable class in fastjson1-compatible/src/main/java still missing an explicit UID — this closes the gap. 1L matches both fastjson 1.x and the sibling JSONObject.

Test coverage — the main suggestion

test_0 and test_1 are same-JVM round trips, so they pass with or without the fix (I confirmed: reverting the one-line change leaves only test_serialVersionUID failing). They're fine as smoke tests, but the actual regression is guarded by a single ObjectStreamClass.lookup assertion.

A stronger guard is a golden byte stream captured from real fastjson 1.x — it pins the whole serialized form (field names/types), not just the UID, so a future refactor that renames list or changes its declared type is caught too. Bytes below were produced by fastjson 1.2.83 for [1,"hello",{"id":123}]:

@Test
public void test_readFastjson1Bytes() throws Exception {
    // produced by fastjson 1.2.83: JSON.parseArray("[1,\"hello\",{\"id\":123}]")
    String base64 = "rO0ABXNyAB5jb20uYWxpYmFiYS5mYXN0anNvbi5KU09OQXJyYXkAAAAAAAAAAQIAAUwABGxpc3R0"
            + "ABBMamF2YS91dGlsL0xpc3Q7eHBzcgATamF2YS51dGlsLkFycmF5TGlzdHiB0h2Zx2GdAwABSQAE"
            + "c2l6ZXhwAAAAA3cEAAAAA3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4"
            + "cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABdAAFaGVsbG9zcgAfY29tLmFsaWJh"
            + "YmEuZmFzdGpzb24uSlNPTk9iamVjdAAAAAAAAAABAgABTAADbWFwdAAPTGphdmEvdXRpbC9NYXA7"
            + "eHBzcgARamF2YS51dGlsLkhhc2hNYXAFB9rBwxZg0QMAAkYACmxvYWRGYWN0b3JJAAl0aHJlc2hv"
            + "bGR4cD9AAAAAAAAMdwgAAAAQAAAAAXQAAmlkc3EAfgAFAAAAe3h4";
    byte[] bytes = java.util.Base64.getDecoder().decode(base64);
    ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));
    JSONArray array = (JSONArray) in.readObject();
    assertEquals(JSON.parseArray("[1,\"hello\",{\"id\":123}]"), array);
}

I ran this against the PR branch — it passes, and fails with InvalidClassException without the fix.

Residual limitation (pre-existing, out of scope but worth knowing)

The reverse direction is still broken for arrays built via the default constructor:

JSONArray a = new JSONArray();   // list = com.alibaba.fastjson2.JSONArray
a.add(123);
// deserialize in real fastjson 1.2.83:
// java.lang.ClassNotFoundException: com.alibaba.fastjson2.JSONArray

Because list is initialized to new com.alibaba.fastjson2.JSONArray(), that fastjson2 class name lands in the stream and 1.x can't resolve it. (Arrays from JSON.parseArray(...) happen to be fine, and JSONObject's map defaults to HashMap, so it's unaffected.) If bidirectional compat is a goal, a writeObject that normalizes list to an ArrayList would close it — but that's a separate change; this PR fixes the direction the issue reports.

Style / minor

  • Placement after the two static ObjectReader fields mirrors JSONObject exactly — consistent with the module. (Conventionally serialVersionUID goes first, but matching the sibling class is the better call here.)
  • Test class name JSONArrayTest_readObject follows the module's existing JSONArrayTest_hashCode convention. Good.
  • Optional: the three tests contain duplicated serialize/deserialize boilerplate — a small private helper would tighten it.

Performance / security

  • Performance: zero impact — a compile-time constant.
  • Security: no new attack surface. The class was already Serializable; a fixed UID doesn't create a gadget that didn't exist. Worth noting that JSONArray has no readObject validation, so a hostile stream can install an arbitrary List into list — but that's inherent to the class being Serializable and unchanged by this PR.

@wenshao
wenshao merged commit 120789b into main Aug 2, 2026
61 of 63 checks passed
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.

[BUG] 升级fastjson 2.0.62 兼容版本后需要清理相关缓存

2 participants