Skip to content

Conversation

@ikhoon
Copy link
Contributor

@ikhoon ikhoon commented Oct 31, 2025

Motivation:

We observed an unexpected deserialization outcome with malformed JSON. Jackson does not fail on that data but silently drops part of the data.

For example, we expected Jackson to fail to parse the data.

{
  "a" : {},
  "b" : {},
  "c" : {
    },
    "c1" : true
  }  // a malformed tailing JSON token
  "d" : {},
  "e": {}
}

But Jackson just drops d and e fields and parses the JSON into:

{
  "a":{},
  "b":{},
  "c":{},
  "c1":true
}

The maintainer of Jackson said it is an expected behavior but not a bug. FasterXML/jackson-core#808 (comment)

But this is intended behavior, not a bug: Jackson only reads as much
content as it needs for a valid JSON Value. It does not try to consume
everything there might be available, given that the white-space-separated
content streams are commonly used.

He suggested enabling DeserializationFeature.FAIL_ON_TRAILING_TOKENS to fail on the malformed data added after the end of the top-level JSON.

Modifications:

  • Enable DeserializationFeature.FAIL_ON_TRAILING_TOKENS to the default Jackson ObjectMapper in Central Dogma

Result:

Central Dogma now correctly rejects malformed JSON when parsing JSON data.

Summary by CodeRabbit

  • Bug Fixes

    • JSON deserialization now strictly rejects input with trailing tokens, improving detection of malformed JSON.
  • Tests

    • Added a unit test and test data to verify invalid JSON (trailing-comma/extra-content) is correctly rejected with an error.
  • Chores

    • Removed a legacy build override that enforced Java 8 compilation for certain projects.

Motivation:

We observed an unexpected deserialization outcome with malformed JSON.
Jackson does not fail on that data but silently drops part of the data.

For example, we expected Jackson to fail to parse the data.
```json5
{
  "a" : {},
  "b" : {},
  "c" : {
    },
    "c1" : true
  }  // a malformed JSON
  "d" : {},
  "e": {}
}
```
But Jackson just drops `d` and `e` fields and parses the JSON into:
```
{
  "a":{},
  "b":{},
  "c":{},
  "c1":true
}
```

The maintainer of Jackson said it is an expected behavior but not a bug.
FasterXML/jackson-core#808 (comment)
> But this is intended behavior, not a bug: Jackson only reads as much
> content as it needs for a valid JSON Value. It does not try to consume
> everything there might be available, given that the white-space-separated
> content streams are commonly used.

He suggested enabling `DeserializationFeature.FAIL_ON_TRAILING_TOKENS`
to fail on the malformed data added after the end of the top-level JSON.

Modifications:

- Enable `DeserializationFeature.FAIL_ON_TRAILING_TOKENS` to the default
  Jackson `ObjectMapper` in Central Dogma
- Breaking) Central Dogma no longer allow tailing commas in JSON

Result:

Central Dogma now correctly rejects malformed JSON when parsing JSON
data.
@ikhoon ikhoon added this to the 0.78.0 milestone Oct 31, 2025
@ikhoon ikhoon added the defect label Oct 31, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 31, 2025

Walkthrough

Enables strict JSON deserialization by turning on FAIL_ON_TRAILING_TOKENS in Jackson mappers, adds a unit test and a malformed JSON resource to verify parsing fails on trailing/extra tokens, and removes a Java-8 compile.release override from build.gradle.

Changes

Cohort / File(s) Summary
Jackson configuration
common/src/main/java/com/linecorp/centraldogma/internal/Jackson.java
Import DeserializationFeature and enable FAIL_ON_TRAILING_TOKENS on both compactMapper and prettyMapper.
Tests & resources
server/src/test/java/com/linecorp/centraldogma/server/InvalidJsonParsingTest.java, server/src/test/resources/invalid-content-after-trailing-comma.json
Add test verifying parsing invalid JSON (trailing/extra tokens) triggers an IOError whose cause is MismatchedInputException; include malformed JSON fixture.
Build configuration
build.gradle
Remove conditional logic that set JavaCompile.release = 8 for non-spring-boot3 projects when running on JDK ≥ 9.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Test as Unit Test
  participant JacksonUtil as Jackson.readTree
  participant Mapper as ObjectMapper (compact/pretty)
  participant Err as MismatchedInputException

  Test->>JacksonUtil: readTree(bytes from fixture)
  JacksonUtil->>Mapper: parse JSON (FAIL_ON_TRAILING_TOKENS enabled)
  alt trailing/extra tokens present
    Mapper-->>Err: throw MismatchedInputException
    Err-->>Test: observed as cause of IOError
  else valid JSON
    Mapper-->>Test: return JsonNode
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify that enabling FAIL_ON_TRAILING_TOKENS is applied to both mappers and doesn't affect other behaviors.
  • Confirm the unit test asserts the expected exception wrapping and the fixture exercises intended edge cases.
  • Check build.gradle change for CI/build implications across modules.

Possibly related PRs

Suggested labels

breaking change

Suggested reviewers

  • trustin
  • jrhee17

Poem

🐰✨ I hop through tokens, nose so keen,
No stray commas sneak where I have been.
I sniff the JSON, tidy the lair,
Trailing crumbs? I'll find them there. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: enabling FAIL_ON_TRAILING_TOKENS in Jackson's ObjectMapper to disallow trailing tokens in JSON files.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 06b91cc and 6324c2c.

📒 Files selected for processing (3)
  • common/src/main/java/com/linecorp/centraldogma/internal/Jackson.java (2 hunks)
  • server/src/test/java/com/linecorp/centraldogma/server/InvalidJsonParsingTest.java (1 hunks)
  • server/src/test/resources/invalid-content-after-trailing-comma.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
server/src/test/java/com/linecorp/centraldogma/server/InvalidJsonParsingTest.java (1)
common/src/main/java/com/linecorp/centraldogma/internal/Jackson.java (1)
  • Jackson (69-393)
🪛 Biome (2.1.2)
server/src/test/resources/invalid-content-after-trailing-comma.json

[error] 10-10: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 10-10: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 10-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: flaky-tests
  • GitHub Check: build-ubuntu-latest-jdk-17-min-java-11
  • GitHub Check: build-macos-latest-jdk-21
  • GitHub Check: docker-build
  • GitHub Check: build-windows-latest-jdk-21
  • GitHub Check: build-ubuntu-latest-jdk-21-snapshot
  • GitHub Check: build-ubuntu-latest-jdk-17-coverage
  • GitHub Check: build-ubuntu-latest-jdk-11
  • GitHub Check: lint
🔇 Additional comments (4)
common/src/main/java/com/linecorp/centraldogma/internal/Jackson.java (2)

42-42: LGTM!

The import is correctly added to support the new deserialization feature.


81-82: LGTM!

Enabling FAIL_ON_TRAILING_TOKENS on both mappers ensures consistent validation of JSON content. This addresses the issue where Jackson could silently drop fields when malformed JSON contains trailing content.

server/src/test/java/com/linecorp/centraldogma/server/InvalidJsonParsingTest.java (1)

38-40: LGTM!

The assertion correctly verifies that malformed JSON with trailing content triggers an IOError with MismatchedInputException as the cause, which aligns with the enabled FAIL_ON_TRAILING_TOKENS feature.

server/src/test/resources/invalid-content-after-trailing-comma.json (1)

1-14: LGTM!

This test resource is intentionally invalid JSON to verify that the FAIL_ON_TRAILING_TOKENS feature correctly rejects malformed content. The missing comma after line 9's closing brace creates the exact scenario the feature is designed to catch.

@ikhoon ikhoon changed the title Disallow trailing comma in JSON files Disallow trailing tokens in JSON files Oct 31, 2025
Copy link
Contributor

@minwoox minwoox left a comment

Choose a reason for hiding this comment

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

👍

Comment on lines -111 to -119
// Target Java 8 except for spring-boot3
if (!project.name.startsWith("java-spring-boot3")) {
tasks.withType(JavaCompile) {
if (JavaVersion.current() >= JavaVersion.VERSION_1_9) {
options.release = 8
}
}
}

Copy link
Contributor Author

@ikhoon ikhoon Nov 4, 2025

Choose a reason for hiding this comment

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

Removed this hard-coded logic. I believe options.release is properly set through java.gradle according to javaTargetCompatibility and javaN flags.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
server/src/test/java/com/linecorp/centraldogma/server/InvalidJsonParsingTest.java (1)

35-37: Consider adding null-check for better test diagnostics.

If the resource is not found, getResourceAsStream returns null, and calling readAllBytes() on null produces an NPE. While acceptable for a unit test, an explicit null-check or assertion would provide a clearer error message during test failures.

For example:

         try (InputStream is = InvalidJsonParsingTest.class.getResourceAsStream(
                 "/invalid-content-after-trailing-comma.json")) {
+            assertThat(is).isNotNull();
             final byte[] bytes = is.readAllBytes();
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 973a6f2 and 4bb9514.

📒 Files selected for processing (1)
  • server/src/test/java/com/linecorp/centraldogma/server/InvalidJsonParsingTest.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
server/src/test/java/com/linecorp/centraldogma/server/InvalidJsonParsingTest.java (1)
common/src/main/java/com/linecorp/centraldogma/internal/Jackson.java (1)
  • Jackson (69-393)
🔇 Additional comments (1)
server/src/test/java/com/linecorp/centraldogma/server/InvalidJsonParsingTest.java (1)

34-36: Past issues resolved correctly.

The typo in the method name has been fixed ("Trailing" instead of "Tailing"), and the resource leak has been properly addressed using try-with-resources.

Comment on lines +34 to +41
void shouldFailOnInvalidJsonAfterTrailingComma() throws IOException {
try (InputStream is = InvalidJsonParsingTest.class.getResourceAsStream(
"/invalid-content-after-trailing-comma.json")) {
final byte[] bytes = is.readAllBytes();
assertThatThrownBy(() -> Jackson.readTree(bytes))
.isInstanceOf(IOError.class)
.hasCauseInstanceOf(MismatchedInputException.class);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify test resource aligns with FAIL_ON_TRAILING_TOKENS feature.

The test name and resource name suggest testing "invalid JSON after trailing comma," but FAIL_ON_TRAILING_TOKENS specifically addresses cases where valid top-level JSON is followed by additional tokens that Jackson would otherwise silently ignore.

If the test resource contains already-malformed JSON (e.g., syntax errors like {"a":1,} with a trailing comma inside the object), it would fail parsing even without this feature enabled, which would not properly validate the PR's objective.

Please confirm the test resource contains a valid JSON value followed by additional content (e.g., {"a":1}{"b":2} or {"a":1}\n{"b":2}) to properly test the scenario described in the PR motivation.


🏁 Script executed:

#!/bin/bash
# Display the test resource content to verify it matches the intended scenario
cat server/src/test/resources/invalid-content-after-trailing-comma.json

Length of output: 98


Correct test resource to properly validate FAIL_ON_TRAILING_TOKENS feature.

The test resource contains malformed JSON with structural syntax errors (mismatched braces, missing commas, orphaned keys), which fails parsing regardless of whether FAIL_ON_TRAILING_TOKENS is enabled. This does not validate the feature's actual purpose: rejecting valid JSON values followed by additional tokens that would otherwise be silently ignored.

Replace the resource file content with valid JSON followed by trailing content. Example: {"a":1}{"b":2} or {"a":1}\nextra, which demonstrates the exact scenario the feature addresses.

🤖 Prompt for AI Agents
In
server/src/test/java/com/linecorp/centraldogma/server/InvalidJsonParsingTest.java
around lines 34 to 41, the test currently uses a resource containing
structurally invalid JSON which causes parsing to fail irrespective of
FAIL_ON_TRAILING_TOKENS; replace the test resource file
(/invalid-content-after-trailing-comma.json) with content that is syntactically
valid JSON followed by extra tokens (for example: {"a":1}{"b":2} or
{"a":1}\nextra) so the test exercises rejection of trailing tokens specifically,
then keep the assertion expecting an IOError caused by MismatchedInputException.

@ikhoon ikhoon modified the milestones: 0.78.0, 0.79.0 Nov 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants