Skip to content

Conversation

@javier-godoy
Copy link
Member

@javier-godoy javier-godoy commented Dec 18, 2025

Close #26

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced support for array-based JSON parameters in method conversion and handling.
  • Tests

    • Improved test coverage for array-type JSON parameters and standardized assertion patterns across test suite.

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

@coderabbitai
Copy link

coderabbitai bot commented Dec 18, 2025

Walkthrough

Implements support for JsonValue[] array parameters in bytecode-instrumented methods by: detecting array-of-JsonValue parameters, generating appropriate bytecode stack operations to allocate destination arrays, and invoking a new batch conversion method to populate arrays element-by-element.

Changes

Cohort / File(s) Summary
Instrumentation Core
src/main/java/.../ClassInstrumentationUtil.java
Adds bytecode generation logic to handle JsonValue[] array parameters, including array allocation, stack rearrangement, and delegation to new batch conversion method.
Conversion Utilities
src/main/java/.../JsonMigration.java
Adds public overload convertToJsonValue(Object[] source, JsonValue[] target) that validates array lengths and iterates through elements, converting each via existing scalar conversion logic.
Test Classes - Updated Assertions
src/test/java/.../ClientCallable_ArrayOfJsonObject__V.java, src/test/java/.../ClientCallable_JsonObjectVarargs__V.java, src/test/java/.../LegacyClientCallable_ArrayOfJsonObject__V.java, src/test/java/.../LegacyClientCallable_JsonObjectVarargs__V.java
Replace JUnit assertions with Hamcrest-based assertions (assertThat, notNullValue, instanceOf); method signature in varargs-related files updated from array to varargs parameter.
New Test Class
src/test/java/.../LegacyClientCallable_ArrayOfJsonString__V.java
New test class extending BaseClientCallable with test(JsonString[] arg) method decorated with @LegacyClientCallable and Hamcrest-based assertions for null, empty, and type checks.
Test Infrastructure
src/test/java/.../LegacyClientCallablesTest.java, src/test/java/.../LegacyClientCallablesTest24.java, src/test/java/.../LegacyClientCallablesTest25.java
Add abstract method createArrayOfJsonString() in base test class; implement concrete versions in subclasses returning JsonString[] arrays; add new test method test_ArrayOfJsonString__V() exercising array parameter conversion.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • ClassInstrumentationUtil.java: Bytecode stack manipulation for array allocation and type conversions requires careful verification of stack frame consistency and correct parameter index tracking.
  • JsonMigration.java: Array length validation and iteration logic should be reviewed for correctness and consistency with scalar conversion behavior.
  • Test infrastructure changes: Verify that new abstract method contract is properly implemented across all concrete test subclasses and that array instantiation logic matches expected component types (e.g., JsonString[] vs. StringNode[]).

Possibly related PRs

  • PR #24: Modifies JSON-instrumentation code to add proper handling for JsonValue[] parameters, updating both ClassInstrumentationUtil and conversion paths with array conversion and test coverage.
  • PR #18: Modifies ClassInstrumentationUtil parameter-conversion logic by adding support for JsonValue array parameters and introducing the new JsonMigration.convertToJsonValue(Object[], JsonValue[]) overload.
  • PR #10: Implements array/varargs conversion for JsonValue by adding array-aware conversion logic and wiring it into instrumentation.

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 8.70% 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 'fix: convert JsonValue[] arguments' clearly summarizes the main change: adding support for converting JsonValue[] array parameters in method instrumentation.
Linked Issues check ✅ Passed The PR successfully implements all four objectives from issue #26: detects JsonValue[] arrays, allocates destination arrays with correct component types, converts each element via existing scalar logic, and maintains stack integrity through the new convertToJsonValue(Object[], JsonValue[]) method.
Out of Scope Changes check ✅ Passed All changes are directly related to issue #26: core conversion logic, helper method overload, and test classes covering array scenarios. No unrelated modifications detected.
✨ 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 20251217-03

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

🧹 Nitpick comments (2)
src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigration.java (1)

108-118: Consider explicit null checks for clearer error messages.

The documentation states that NullPointerException is thrown if source or target is null, but relying on implicit NPEs (e.g., from source.length) can result in less descriptive error messages. Explicitly validating nulls upfront would improve debuggability.

🔎 Apply this diff to add explicit null validation:
 public static void convertToJsonValue(Object[] source, JsonValue[] target) {
+  if (source == null) {
+    throw new NullPointerException("source array cannot be null");
+  }
+  if (target == null) {
+    throw new NullPointerException("target array cannot be null");
+  }
   if (source.length != target.length) {
     throw new IllegalArgumentException(
         String.format("Array length mismatch: source.length=%d, target.length=%d",
             source.length, target.length));
   }

   for (int i = 0; i < target.length; i++) {
     target[i] = convertToJsonValue(source[i]);
   }
 }
src/test/java/com/flowingcode/vaadin/jsonmigration/ClientCallable_ArrayOfJsonObject__V.java (1)

22-28: Consider static import for instanceOf matcher.

The code uses static imports for most Hamcrest matchers (assertThat, notNullValue, emptyArray, not) but accesses instanceOf via the Matchers prefix on line 36. For consistency with the existing import style, consider adding a static import.

🔎 View suggested change:
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.emptyArray;
+import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.notNullValue;
 import com.vaadin.flow.component.ClientCallable;
 import elemental.json.JsonObject;
-import org.hamcrest.Matchers;

Then update line 36:

-    assertThat(arg, Matchers.instanceOf(JsonObject[].class));
+    assertThat(arg, instanceOf(JsonObject[].class));
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bcb7201 and 255b826.

📒 Files selected for processing (10)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ClassInstrumentationUtil.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigration.java (1 hunks)
  • src/test/java/com/flowingcode/vaadin/jsonmigration/ClientCallable_ArrayOfJsonObject__V.java (1 hunks)
  • src/test/java/com/flowingcode/vaadin/jsonmigration/ClientCallable_JsonObjectVarargs__V.java (1 hunks)
  • src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallable_ArrayOfJsonObject__V.java (1 hunks)
  • src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallable_ArrayOfJsonString__V.java (1 hunks)
  • src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallable_JsonObjectVarargs__V.java (1 hunks)
  • src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallablesTest.java (2 hunks)
  • src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallablesTest24.java (3 hunks)
  • src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallablesTest25.java (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 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/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallable_ArrayOfJsonObject__V.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/ClassInstrumentationUtil.java
  • src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallablesTest25.java
  • src/test/java/com/flowingcode/vaadin/jsonmigration/ClientCallable_ArrayOfJsonObject__V.java
  • src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigration.java
  • src/test/java/com/flowingcode/vaadin/jsonmigration/ClientCallable_JsonObjectVarargs__V.java
  • src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallablesTest24.java
  • src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallable_ArrayOfJsonString__V.java
  • src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallablesTest.java
🔇 Additional comments (14)
src/main/java/com/flowingcode/vaadin/jsonmigration/ClassInstrumentationUtil.java (1)

470-489: LGTM! Bytecode generation correctly handles JsonValue[] parameters.

The stack manipulation using DUP_X1 properly rearranges the operands so that after calling convertToJsonValue(Object[], JsonValue[]), the target array remains on the stack for passing to the super method. The component type is correctly extracted and the local variable index is appropriately incremented.

src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallable_ArrayOfJsonObject__V.java (1)

22-37: LGTM! Test assertions improved with Hamcrest matchers.

The migration to Hamcrest assertions and the addition of runtime type verification strengthen the test validation. The changes are consistent with the broader test suite updates.

src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallable_ArrayOfJsonString__V.java (1)

1-38: LGTM! Well-structured test for JsonString[] array handling.

This new test class provides coverage for the JsonString[] array conversion path, complementing the JsonObject[] tests. The assertions are consistent with the project's testing patterns.

src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallablesTest24.java (2)

50-52: LGTM! Return type made more specific.

Changing the return type from Object to JsonString improves type safety without breaking compatibility, since JsonString is assignable to the abstract method's Object return type.


69-72: LGTM! Array factory method correctly implemented.

The createArrayOfJsonString() implementation properly creates a JsonString[] array with two elements, matching the pattern used for createArrayOfJsonObject().

src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallablesTest.java (2)

82-82: LGTM! Abstract factory method enables version-specific array creation.

The abstract method allows test subclasses to provide appropriate JsonString[] implementations for their respective Vaadin versions.


320-327: LGTM! Test correctly exercises JsonString[] parameter conversion.

The test properly validates that the instrumented class can handle JsonString[] parameters and that the trace method is invoked, confirming the conversion path works as expected.

src/test/java/com/flowingcode/vaadin/jsonmigration/ClientCallable_JsonObjectVarargs__V.java (1)

33-37: LGTM! Varargs parameter correctly handled as array.

The change from JsonObject[] arg to JsonObject... arg tests that varargs work correctly with the instrumentation, since varargs compile to arrays at the bytecode level. The runtime type assertion confirms the parameter is received as JsonObject[].class.

src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallable_JsonObjectVarargs__V.java (3)

22-27: LGTM: Clean Hamcrest migration.

The import additions properly support the Hamcrest-based assertions while maintaining minimal dependencies.


33-36: LGTM: Comprehensive assertions with runtime type validation.

The Hamcrest assertions are clear and expressive. The instanceOf check on line 35 is particularly valuable—it confirms the instrumentation produces the correct Elemental JsonObject[] type rather than leaving a Jackson-backed array.


32-32: Varargs parameter handling is incomplete at the bytecode level.

The ACC_VARARGS flag (0x0080) at bytecode level indicates a variable arity (varargs) method. However, the instrumentation code at lines 420-422 of ClassInstrumentationUtil.java masks modifiers to only preserve visibility flags (ACC_PUBLIC | ACC_PROTECTED | ACC_PRIVATE), which strips the ACC_VARARGS flag from generated method overrides. While the code functions correctly because JsonMigrationHelper25.java detects varargs via Method.isVarArgs() on the original method rather than the override, the generated bytecode does not properly preserve the varargs metadata on instrumented methods. Consider adding Opcodes.ACC_VARARGS to the modifier mask when the original method has varargs to maintain complete bytecode fidelity.

src/test/java/com/flowingcode/vaadin/jsonmigration/LegacyClientCallablesTest25.java (2)

55-57: LGTM: Return type narrowing improves type safety.

Changing from Object to StringNode makes the contract explicit and provides better compile-time type checking.


74-77: LGTM: Array factory method follows established pattern.

The createArrayOfJsonString() implementation mirrors the existing createArrayOfJsonObject() pattern at lines 70-72, providing consistent test data generation for array-of-json scenarios.

src/test/java/com/flowingcode/vaadin/jsonmigration/ClientCallable_ArrayOfJsonObject__V.java (1)

34-36: Excellent runtime type validation.

The assertions correctly validate the array parameter after bytecode transformation. The addition of the instanceOf check on line 36 is particularly important—it verifies that the instrumented bytecode properly converted the Jackson array to an Elemental JsonObject[] at runtime, which is the core fix for issue #26.

@paodb paodb merged commit 3685f60 into master Dec 18, 2025
3 checks passed
@github-project-automation github-project-automation bot moved this from To Do to Pending release in Flowing Code Addons Dec 18, 2025
@paodb paodb deleted the 20251217-03 branch December 18, 2025 13:03
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.

Parameter Conversion Bypass for JsonValue[] Array Types

3 participants