Skip to content

Conversation

@javier-godoy
Copy link
Member

@javier-godoy javier-godoy commented Nov 26, 2025

Close #12

In Vaadin 24: convertToClientCallableResult returns the same JsonValue object that it received

In Vaadin 25: convertToClientCallableResult returns a Jackson node that implements JsonValue. The interface is implemented just for satisfying the method return type (which must be JsonValue). These little monsters do not support any operation from JsonValue (which isn't a problem since Vaadin 25 would only use the Jackson part).

Summary by CodeRabbit

  • Improvements

    • Enhanced type-safety for JSON value conversion during migration operations.
    • Improved error handling for unsupported JSON value types, yielding clearer failures.
  • New Features

    • Added internal JSON value wrappers to better represent different JSON kinds during migration, improving consistency and reliability.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 26, 2025

Walkthrough

Adds package-private Elemental*Node wrappers and an UnsupportedJsonValueImpl interface; updates convertToClientCallableResult to a generic signature across JsonMigration, JsonMigrationHelper, JsonMigrationHelper25, and LegacyJsonMigrationHelper; adjusts JsonMigrationHelper25 to map elemental JsonValue types to the new wrapper nodes and makes convertToJsonNode package-visible.

Changes

Cohort / File(s) Summary
Elemental node wrapper types
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalArrayNode.java, src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalBooleanNode.java, src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNullNode.java, src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNumberNode.java, src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalObjectNode.java, src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalStringNode.java
New package-private classes extending Jackson node types (ArrayNode, BooleanNode, NullNode, DoubleNode, ObjectNode, StringNode) and implementing UnsupportedJsonValueImpl. Array/Object nodes include helpers that convert elemental JsonArray/JsonObject contents to Jackson nodes; scalar nodes delegate to superclass constructors.
Unsupported-json-value helper
src/main/java/com/flowingcode/vaadin/jsonmigration/UnsupportedJsonValueImpl.java
New package-private interface (in the same package) that extends JsonValue and provides default implementations of JsonValue methods which throw UnsupportedOperationException.
Generic conversion signature updates
src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigration.java, src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper.java, src/main/java/com/flowingcode/vaadin/jsonmigration/LegacyJsonMigrationHelper.java
Changed convertToClientCallableResult signature from raw Object to generic <T extends JsonValue> T, preserving JsonValue subtype through parameter and return.
JsonValue → JsonNode mapping logic
src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper25.java
convertToClientCallableResult now accepts and returns JsonValue, uses a switch on JsonValue.getType() to wrap values into Elemental*Node instances, and throws IllegalArgumentException for unknown types. convertToJsonNode visibility changed from private to package-private to support the wrappers.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review ElementalArrayNode list initialization and use of pre-sized list + set() to ensure no IndexOutOfBoundsException.
  • Verify ElementalObjectNode preserves insertion/order semantics and correctly converts all JsonValue property types.
  • Ensure generic signature changes () are consistent across interfaces/implementations and do not break callers.
  • Confirm UnsupportedJsonValueImpl default methods throwing UnsupportedOperationException are intended and that wrappers relying on them behave correctly.

Possibly related PRs

Suggested reviewers

  • mlopezFC
  • paodb

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.17% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 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: creating classes that implement both JsonNode and JsonValue interfaces to address the Vaadin version compatibility issue.
Linked Issues check ✅ Passed The PR implements the required solution by creating Elemental*Node classes implementing both JsonNode and JsonValue, and updating method signatures to return JsonValue while supporting both Vaadin 24 and 25 requirements.
Out of Scope Changes check ✅ Passed All changes are directly related to solving the linked issue: creating wrapper classes and updating method signatures for JSON migration compatibility.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-json

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 59c7555 and 77f97fe.

📒 Files selected for processing (11)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalArrayNode.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalBooleanNode.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNullNode.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNumberNode.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalObjectNode.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalStringNode.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigration.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper25.java (2 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/LegacyJsonMigrationHelper.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/UnsupportedJsonValueImpl.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalObjectNode.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalArrayNode.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalBooleanNode.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNumberNode.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigration.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalStringNode.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/UnsupportedJsonValueImpl.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/LegacyJsonMigrationHelper.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper25.java
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: javier-godoy
Repo: FlowingCode/JsonMigrationHelper PR: 11
File: src/main/java/com/flowingcode/vaadin/jsonmigration/JsonSerializer.java:281-301
Timestamp: 2025-11-25T16:35:42.544Z
Learning: In the JsonMigrationHelper project, code copied from the Vaadin codebase should be kept consistent with the original source unless there's a specific reason to deviate.
📚 Learning: 2025-11-25T16:35:42.544Z
Learnt from: javier-godoy
Repo: FlowingCode/JsonMigrationHelper PR: 11
File: src/main/java/com/flowingcode/vaadin/jsonmigration/JsonSerializer.java:281-301
Timestamp: 2025-11-25T16:35:42.544Z
Learning: In the JsonMigrationHelper project, code copied from the Vaadin codebase should be kept consistent with the original source unless there's a specific reason to deviate.

Applied to files:

  • src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNullNode.java
🔇 Additional comments (2)
src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper.java (1)

32-32: LGTM — Generic signature provides type-safe propagation.

The bounded type parameter <T extends JsonValue> correctly preserves the specific subtype through the call, allowing wrappers like ElementalNullNode (which implement both JsonNode and JsonValue) to be returned with their full type information intact.

src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNullNode.java (1)

22-29: Jackson package structure verified—all imports are correct and consistent.

The codebase uses Jackson 3.0.0 (groupId tools.jackson.core) and all files uniformly use the tools.jackson.databind.node.* package structure. ElementalNullNode.java's import at line 22 (import tools.jackson.databind.node.NullNode;) matches the project's dependency and aligns with other Elemental*Node classes (ArrayNode, StringNode, NumberNode, ObjectNode, BooleanNode).

No issues found; the class design and package usage are sound and consistent throughout the codebase.


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: 3

🧹 Nitpick comments (3)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalBooleanNode.java (1)

32-38: Consider removing trailing blank lines.

There are multiple trailing blank lines at the end of the file that could be cleaned up.

src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigration.java (1)

67-77: Javadoc is outdated after signature change.

The @return documentation still mentions returning "an Object" but the method now returns T extends JsonValue. Consider updating the Javadoc to reflect the generic return type.

   * Converts a given Java object into the return type of a {@link ClientCallable method}.
   *
   * In Vaadin 25, this method converts {@code JsonValue} into {@code JsonNode}.
   *
   * @param object the object to convert
-  * @return an {@code Object} suitable to use as the result of a {@code ClientCallable} method.
+  * @return the converted value suitable to use as the result of a {@code ClientCallable} method
   */
  public static <T extends JsonValue> T convertToClientCallableResult(T object) {
src/main/java/com/flowingcode/vaadin/jsonmigration/UnsupportedJsonValueImpl.java (1)

25-61: Consider adding descriptive exception messages for debugging.

The design correctly satisfies the JsonValue interface contract while preventing usage of elemental JSON operations in Vaadin 25 contexts. However, adding messages to the exceptions would help developers understand why these operations fail.

Example:

   @Override
   default boolean asBoolean() {
-    throw new UnsupportedOperationException();
+    throw new UnsupportedOperationException("JsonValue operations not supported on Jackson-backed nodes");
   }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae395fb and 59c7555.

📒 Files selected for processing (11)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalArrayNode.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalBooleanNode.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNullNode.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNumberNode.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalObjectNode.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalStringNode.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigration.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper25.java (2 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/LegacyJsonMigrationHelper.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/UnsupportedJsonValueImpl.java (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: javier-godoy
Repo: FlowingCode/JsonMigrationHelper PR: 11
File: src/main/java/com/flowingcode/vaadin/jsonmigration/JsonSerializer.java:281-301
Timestamp: 2025-11-25T16:35:42.544Z
Learning: In the JsonMigrationHelper project, code copied from the Vaadin codebase should be kept consistent with the original source unless there's a specific reason to deviate.
📚 Learning: 2025-11-25T16:35:42.544Z
Learnt from: javier-godoy
Repo: FlowingCode/JsonMigrationHelper PR: 11
File: src/main/java/com/flowingcode/vaadin/jsonmigration/JsonSerializer.java:281-301
Timestamp: 2025-11-25T16:35:42.544Z
Learning: In the JsonMigrationHelper project, code copied from the Vaadin codebase should be kept consistent with the original source unless there's a specific reason to deviate.

Applied to files:

  • src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNullNode.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigration.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalArrayNode.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper25.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalObjectNode.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalStringNode.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/LegacyJsonMigrationHelper.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/UnsupportedJsonValueImpl.java
🧬 Code graph analysis (5)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNullNode.java (5)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalArrayNode.java (1)
  • SuppressWarnings (30-52)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalBooleanNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNumberNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalObjectNode.java (1)
  • SuppressWarnings (31-54)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalStringNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalArrayNode.java (6)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalBooleanNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNullNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNumberNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalObjectNode.java (1)
  • SuppressWarnings (31-54)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalStringNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper25.java (1)
  • SuppressWarnings (216-261)
src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper25.java (7)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalArrayNode.java (1)
  • SuppressWarnings (30-52)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalBooleanNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNullNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNumberNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalObjectNode.java (1)
  • SuppressWarnings (31-54)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalStringNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/LegacyJsonMigrationHelper.java (1)
  • SuppressWarnings (60-66)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNumberNode.java (6)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalArrayNode.java (1)
  • SuppressWarnings (30-52)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalBooleanNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNullNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalObjectNode.java (1)
  • SuppressWarnings (31-54)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalStringNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper25.java (1)
  • SuppressWarnings (216-261)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalBooleanNode.java (7)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalArrayNode.java (1)
  • SuppressWarnings (30-52)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNullNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNumberNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalObjectNode.java (1)
  • SuppressWarnings (31-54)
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalStringNode.java (1)
  • SuppressWarnings (24-31)
src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper25.java (1)
  • SuppressWarnings (216-261)
src/main/java/com/flowingcode/vaadin/jsonmigration/LegacyJsonMigrationHelper.java (1)
  • SuppressWarnings (60-66)
🔇 Additional comments (8)
src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper.java (1)

32-32: Generic signature aligns well with PR objectives.

The change from Object return type to <T extends JsonValue> T provides type safety while ensuring the returned value satisfies Vaadin 24's requirement for JsonValue-assignable return types. This is a clean solution for the cross-version compatibility issue.

src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalBooleanNode.java (1)

24-29: Implementation is consistent with sibling wrapper classes.

The class correctly extends Jackson's BooleanNode and implements UnsupportedJsonValueImpl to satisfy both the Jackson serialization requirements (Vaadin 25) and the JsonValue interface requirement (Vaadin 24).

src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNumberNode.java (1)

24-31: Clean wrapper implementation.

Using DoubleNode as the base class is appropriate since elemental.json.JsonNumber internally represents numeric values as double. The implementation is consistent with the other Elemental*Node wrappers.

src/main/java/com/flowingcode/vaadin/jsonmigration/LegacyJsonMigrationHelper.java (1)

43-46: LGTM!

The generic signature <T extends JsonValue> T convertToClientCallableResult(T object) correctly provides type-safe propagation for Vaadin 24, where the method simply returns the input JsonValue unchanged. This aligns with the PR objective of maintaining compatibility across Vaadin versions.

src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalStringNode.java (1)

24-30: LGTM!

Clean implementation following the established wrapper pattern. The class correctly bridges StringNode with JsonValue via UnsupportedJsonValueImpl.

src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalObjectNode.java (1)

31-54: LGTM!

The implementation correctly:

  • Uses LinkedHashMap to preserve key ordering
  • Optimizes for empty and single-key cases with immutable collections
  • Recursively converts nested values via convertToJsonNode
src/main/java/com/flowingcode/vaadin/jsonmigration/ElementalNullNode.java (1)

24-31: No serialization concerns with ElementalNullNode — verification confirms safe implementation.

The original concern about Jackson's NullNode singleton pattern and readResolve() does not apply in this context. Investigation shows:

  • All Elemental*Node classes are intentionally annotated with @SuppressWarnings("serial"), indicating serialization is not intended
  • No Java serialization infrastructure exists in the codebase (no ObjectOutputStream, ObjectInputStream, or custom serialization methods)
  • ElementalNullNode instances are temporary wrapper objects created in convertToClientCallableResult() for Vaadin client callbacks and are never persisted or serialized
  • The pattern is consistent across all node types and safe for its intended purpose

The implementation is correct and follows the established pattern.

src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper25.java (1)

174-207: Visibility change for convertToJsonNode is appropriate; conversion logic looks correct

Making static BaseJsonNode convertToJsonNode(JsonValue jsonValue) package‑private so that ElementalArrayNode/ElementalObjectNode can reuse it is reasonable, and the mapping of each JsonValue type to Jackson nodes (ObjectNode, ArrayNode, textNode, numberNode, booleanNode, nullNode) is consistent and exhaustive for the known elemental JsonType values.

No functional issues spotted here; this method now forms the common backbone for both argument conversion in invoke/convertArray and the new Elemental*Node wrappers.

Copy link
Member

@paodb paodb left a comment

Choose a reason for hiding this comment

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

LGTM

@paodb paodb merged commit 0df4eae into master Nov 26, 2025
3 checks passed
@paodb paodb deleted the fix-json branch November 26, 2025 14:20
@github-project-automation github-project-automation bot moved this from To Do to Pending release in Flowing Code Addons Nov 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Pending release

Development

Successfully merging this pull request may close these issues.

Vaadin 24: has method annotated with ClientCallable whose return type is Object

3 participants