Skip to content

[java] Enforce commas between JSON elements; accept trailing commas#17738

Open
shs96c wants to merge 4 commits into
SeleniumHQ:trunkfrom
shs96c:shs-json-hasnext-separator
Open

[java] Enforce commas between JSON elements; accept trailing commas#17738
shs96c wants to merge 4 commits into
SeleniumHQ:trunkfrom
shs96c:shs-json-hasnext-separator

Conversation

@shs96c

@shs96c shs96c commented Jul 2, 2026

Copy link
Copy Markdown
Member

JsonInput.hasNext() had two spec-compliance gaps and one usability gap:

  1. It never required a comma between elements — [1 2 3] and {\"a\":1 \"b\":2} both parsed successfully.
  2. It silently consumed a leading comma — [,1] parsed as [1].
  3. It rejected trailing commas like [1,2,3,] even though we want to be lenient about that.

Handle these by:

  • Adding a parallel containerHasElement deque kept in sync with the container stack.
  • Mark it in expect() when reading a value (or completing a name/value pair).
  • Use it in hasNext() to require a separator between elements while allowing a single trailing comma before ]/}, and to reject a leading comma.

@selenium-ci selenium-ci added the C-java Java Bindings label Jul 2, 2026
@shs96c shs96c force-pushed the shs-json-hasnext-separator branch from 283346f to 82c7465 Compare July 2, 2026 12:47
@shs96c shs96c marked this pull request as ready for review July 2, 2026 13:08
@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

JsonInput: require commas between elements and allow trailing commas

🐞 Bug fix 🧪 Tests ✨ Enhancement 🕐 40+ Minutes

Grey Divider

AI Description

• Enforce comma separators between JSON array/object elements in JsonInput.hasNext().
• Reject leading commas while remaining lenient about a single trailing comma.
• Add regression tests for missing/leading/trailing comma behavior.
Diagram

graph TD
  T["JsonInputTest"] --> J["JsonInput"] --> H["hasNext()"] --> R["Input reader"]
  J --> E["expect()"] --> C["containerHasElement deque"]
  E --> S["container stack"]
  H --> C
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Encode element-seen state into Container enum/state machine
  • ➕ Keeps all container-related state in one stack (no parallel deque to keep in sync).
  • ➕ Makes illegal transitions explicit (e.g., AFTER_ELEMENT, AFTER_COMMA).
  • ➖ More invasive refactor touching more parsing paths.
  • ➖ Harder to keep backwards behavior stable without broader test expansion.
2. Tokenize and validate separators in a dedicated lexer layer
  • ➕ Clear separation between lexing (commas/brackets) and higher-level coercion.
  • ➕ Could simplify hasNext() and centralize comma handling.
  • ➖ Bigger architectural change and higher risk for a targeted compliance fix.
  • ➖ Likely requires wider API/behavior changes and more tests.

Recommendation: The chosen approach (a small parallel deque tracking element presence) is an appropriate low-risk, localized fix for hasNext() semantics. It addresses missing/leading/trailing comma behavior without refactoring the broader container-state model; just ensure the two stacks remain tightly coupled (push/pop in begin/end methods) and rely on the added tests to prevent regressions.

Files changed (2) +86 / -3

Bug fix (1) +41 / -3
JsonInput.javaTrack per-container elements to enforce separators and allow trailing commas +41/-3

Track per-container elements to enforce separators and allow trailing commas

• Adds a parallel per-container boolean stack to track whether a container has already produced an element. Updates hasNext() to reject leading commas, require commas between elements, and accept a single trailing comma before closing brackets/braces. Updates expect() to mark elements as read for arrays and map entries while avoiding marking on container close.

java/src/org/openqa/selenium/json/JsonInput.java

Tests (1) +45 / -0
JsonInputTest.javaAdd tests for trailing commas and separator enforcement +45/-0

Add tests for trailing commas and separator enforcement

• Introduces regression tests asserting that trailing commas in arrays/objects are accepted, while missing commas between array elements and leading commas are rejected with JsonException.

java/test/org/openqa/selenium/json/JsonInputTest.java

@qodo-code-review

qodo-code-review Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 18 rules

Grey Divider


Action required

1. hasNext non-idempotent ✓ Resolved 🐞 Bug ≡ Correctness
Description
After hasNext() consumes a comma separator, a subsequent hasNext() call (before the next element
is read) will throw Expected ',' or end... because containerHasElement is never reset and
remains true for the rest of the container. This can break callers that probe hasNext() multiple
times per element (a common iterator-style usage) even on valid JSON like [1,2].
Code

java/src/org/openqa/selenium/json/JsonInput.java[R324-344]

    skipWhitespace(input);
+    boolean seenElement = Boolean.TRUE.equals(containerHasElement.peekFirst());
+
    if (input.peek() == ',') {
+      if (!seenElement) {
+        throw new JsonException("Unexpected ',' before first element of container. " + input);
+      }
      input.read();
-      return true;
+      skipWhitespace(input);
+      JsonType afterComma = peek();
+      // Trailing comma leniency: '[1,]' and '{"a":1,}' are accepted.
+      return afterComma != JsonType.END_COLLECTION && afterComma != JsonType.END_MAP;
    }

    JsonType type = peek();
-    return type != JsonType.END_COLLECTION && type != JsonType.END_MAP;
+    if (type == JsonType.END_COLLECTION || type == JsonType.END_MAP) {
+      return false;
+    }
+    if (seenElement) {
+      throw new JsonException("Expected ',' or end of container but saw " + type + ". " + input);
+    }
Evidence
hasNext() consumes commas but does not update containerHasElement, while expect() permanently
flips the flag to true when a value is read. This means after the comma is consumed, a second
hasNext() sees a value token with seenElement==true and throws as if a comma were missing, even
though we are already positioned after the comma.

java/src/org/openqa/selenium/json/JsonInput.java[318-346]
java/src/org/openqa/selenium/json/JsonInput.java[534-574]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`JsonInput.hasNext()` now uses `containerHasElement` as a proxy for “a comma is required before the next element”. However, `markElementRead()` only ever sets the flag to `true`, and `hasNext()` never clears it after consuming a comma. This makes `hasNext()` non-idempotent: for valid input like `[1,2]`, after reading `1`, the first `hasNext()` consumes the comma and returns `true`, but a second `hasNext()` (before reading `2`) sees a value token with `seenElement==true` and throws.

### Issue Context
- `markElementRead()` sets the current container flag to `true` and never sets it back to `false`.
- `hasNext()` consumes the comma but does not update `containerHasElement`, so the subsequent non-comma path treats the next value token as a missing-comma violation.

### Fix Focus Areas
- java/src/org/openqa/selenium/json/JsonInput.java[318-346]
- java/src/org/openqa/selenium/json/JsonInput.java[534-574]
- java/test/org/openqa/selenium/json/JsonInputTest.java[312-356]

### How to fix
1. Treat the per-container boolean as “needsSeparator” (or add a separate boolean/stack for that state).
2. In `hasNext()` when a comma is successfully consumed, clear the flag for the current container (set it to `false`) so repeated `hasNext()` calls remain valid until an element is actually read.
  - e.g., add a helper like `markSeparatorRead()` that sets the top boolean to `false`.
3. Add a regression test demonstrating idempotency:
  - Parse `[1,2]`, read `1`, call `hasNext()` twice (both should be `true`), then read `2`.
  - Same idea for objects: `{"a":1,"b":2}` after reading `a:1`, call `hasNext()` twice before reading `b`.
4. Update the field comment/name if its semantics change (e.g., from “has seen an element” to “separator required / element just read”).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Premature stack pop ✓ Resolved 🐞 Bug ☼ Reliability
Description
endArray()/endObject() pop both stack and containerHasElement before validating the container
type, so a mismatch exception leaves the parser state mutated and makes subsequent error
handling/recovery unreliable.
Code

java/src/org/openqa/selenium/json/JsonInput.java[R404-407]

    expect(JsonType.END_COLLECTION);
    Container expectation = stack.removeFirst();
+    containerHasElement.removeFirst();
    if (expectation != Container.COLLECTION) {
Evidence
Both endArray() and endObject() remove from the internal stacks before the type check that may
throw, meaning error paths happen after state mutation.

java/src/org/openqa/selenium/json/JsonInput.java[403-441]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`endArray()` and `endObject()` remove entries from `stack` and `containerHasElement` before checking whether the removed `Container` matches the expected container type. If the expectation check fails, a `JsonException` is thrown after internal state has already been mutated.

## Issue Context
This is especially relevant now that there are *two* parallel stacks to keep consistent; throwing after mutation makes debugging/recovery harder and can cause follow-on failures if callers catch exceptions.

## Fix Focus Areas
- java/src/org/openqa/selenium/json/JsonInput.java[403-441]

## Suggested fix
Change `endArray()`/`endObject()` to validate using `peekFirst()` (or store the peeked value) and only `removeFirst()` from both deques after the validation passes. For example:

```java
public void endArray() {
 expect(JsonType.END_COLLECTION);
 Container expectation = stack.peekFirst();
 if (expectation != Container.COLLECTION) {
   throw new JsonException(
     "Attempt to close a JSON List, but a JSON Object was expected. " + input);
 }
 stack.removeFirst();
 containerHasElement.removeFirst();
 input.read();
}
```

Apply the same pattern to `endObject()`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Comma enforcement bypassable ✓ Resolved 🐞 Bug ≡ Correctness
Description
Comma validation is implemented only in hasNext(), so callers that read multiple elements or object
members via next*()/nextName() without calling hasNext() can still successfully parse invalid JSON
like "[1 2]" or "{\"a\":1 \"b\":2}". This leaves a spec-compliance gap depending on call pattern,
despite the PR’s intent to enforce separators.
Code

java/src/org/openqa/selenium/json/JsonInput.java[R555-566]

+    // Handle the case where we're reading a value.
+    if (type == JsonType.END_COLLECTION || type == JsonType.END_MAP) {
+      // Closing the container - don't treat as a new element in it.
+      return;
+    }
    if (top == Container.MAP_VALUE) {
      stack.removeFirst();
      stack.addFirst(Container.MAP_NAME);
+      markElementRead();
+    } else if (top == Container.COLLECTION) {
+      markElementRead();
+    }
Evidence
peek() skips whitespace, so after reading the first element in [1 2] the next nextNumber() can
see 2 directly and succeed because expect() only checks the token type and then marks the
element as read; it does not enforce a required comma. The only place that enforces commas is
hasNext(), so callers who don’t call hasNext() between reads bypass the new separator rule. The
existing tests also show that reading without calling hasNext() is an expected usage pattern for
some cases (single-element arrays).

java/src/org/openqa/selenium/json/JsonInput.java[128-175]
java/src/org/openqa/selenium/json/JsonInput.java[228-286]
java/src/org/openqa/selenium/json/JsonInput.java[318-346]
java/src/org/openqa/selenium/json/JsonInput.java[534-567]
java/test/org/openqa/selenium/json/JsonInputTest.java[127-146]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`JsonInput` enforces commas only in `hasNext()`. If a caller reads successive elements (arrays) or successive name/value pairs (objects) by calling `nextNumber()`/`nextString()`/`nextName()` directly without an intervening `hasNext()`, the parser can still accept inputs that are missing commas (e.g. `[1 2]`, `{"a":1 "b":2}`).

## Issue Context
- `peek()` skips whitespace and can therefore see the next token immediately after a prior value.
- `expect()` validates token types and updates container state, but does not require or consume a comma separator between elements.
- The new separator logic is only in `hasNext()`, so it is easy to bypass by not calling `hasNext()`.

## Fix Focus Areas
- java/src/org/openqa/selenium/json/JsonInput.java[318-346]
- java/src/org/openqa/selenium/json/JsonInput.java[534-574]

### Suggested fix approach
Centralize separator validation/consumption in a helper that is invoked when starting to read a new element/property (e.g., from `expect()` for values and for `NAME` in objects). This should:
1) If the current container has already seen an element/pair, require a comma before the next element/pair.
2) Consume exactly one comma (if present) and then continue.
3) Keep `hasNext()` consistent with this logic (e.g., call the same helper or ensure separators aren’t double-consumed).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

4. Object comma cases untested ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The new tests cover array missing/leading commas but do not add equivalent malformed-object cases,
leaving object-specific comma enforcement behavior unprotected against regressions.
Code

java/test/org/openqa/selenium/json/JsonInputTest.java[R414-430]

+  @Test
+  void shouldRejectMissingCommaBetweenArrayElements() {
+    try (JsonInput input = newInput("[1 2]")) {
+      input.beginArray();
+      assertThat(input.hasNext()).isTrue();
+      assertThat(input.nextNumber()).isEqualTo(1L);
+      assertThatExceptionOfType(JsonException.class).isThrownBy(input::hasNext);
+    }
+  }
+
+  @Test
+  void shouldRejectLeadingCommaInArray() {
+    try (JsonInput input = newInput("[,1]")) {
+      input.beginArray();
+      assertThatExceptionOfType(JsonException.class).isThrownBy(input::hasNext);
+    }
+  }
Evidence
The test additions include malformed array cases but no malformed object comma cases; object parsing
also has distinct tokenization behavior (NAME vs STRING) based on isReadingName(), so
object-specific tests add real protection.

java/test/org/openqa/selenium/json/JsonInputTest.java[387-463]
java/src/org/openqa/selenium/json/JsonInput.java[128-166]
java/src/org/openqa/selenium/json/JsonInput.java[561-563]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
There are new regression tests for array comma rules, but no tests asserting the same behavior for objects (missing comma between entries and leading comma in an object).

## Issue Context
`JsonInput.peek()` returns `JsonType.NAME` vs `JsonType.STRING` depending on whether the parser is currently expecting a property name (`isReadingName()`), so object paths are sufficiently distinct to warrant direct coverage.

## Fix Focus Areas
- java/test/org/openqa/selenium/json/JsonInputTest.java[387-463]
- java/src/org/openqa/selenium/json/JsonInput.java[128-166]
- java/src/org/openqa/selenium/json/JsonInput.java[561-563]

## Suggested fix
Add tests similar to the array ones, e.g.:
- Reject missing comma between object entries: `{"a":1 "b":2}` should throw from `hasNext()` after reading the first value.
- Reject leading comma in object: `{,"a":1}` should throw from `hasNext()` immediately after `beginObject()`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Previous review results

Review updated until commit b91099f

Results up to commit 42e746e


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Action required
1. hasNext non-idempotent ✓ Resolved 🐞 Bug ≡ Correctness
Description
After hasNext() consumes a comma separator, a subsequent hasNext() call (before the next element
is read) will throw Expected ',' or end... because containerHasElement is never reset and
remains true for the rest of the container. This can break callers that probe hasNext() multiple
times per element (a common iterator-style usage) even on valid JSON like [1,2].
Code

java/src/org/openqa/selenium/json/JsonInput.java[R324-344]

    skipWhitespace(input);
+    boolean seenElement = Boolean.TRUE.equals(containerHasElement.peekFirst());
+
    if (input.peek() == ',') {
+      if (!seenElement) {
+        throw new JsonException("Unexpected ',' before first element of container. " + input);
+      }
      input.read();
-      return true;
+      skipWhitespace(input);
+      JsonType afterComma = peek();
+      // Trailing comma leniency: '[1,]' and '{"a":1,}' are accepted.
+      return afterComma != JsonType.END_COLLECTION && afterComma != JsonType.END_MAP;
    }

    JsonType type = peek();
-    return type != JsonType.END_COLLECTION && type != JsonType.END_MAP;
+    if (type == JsonType.END_COLLECTION || type == JsonType.END_MAP) {
+      return false;
+    }
+    if (seenElement) {
+      throw new JsonException("Expected ',' or end of container but saw " + type + ". " + input);
+    }
Evidence
hasNext() consumes commas but does not update containerHasElement, while expect() permanently
flips the flag to true when a value is read. This means after the comma is consumed, a second
hasNext() sees a value token with seenElement==true and throws as if a comma were missing, even
though we are already positioned after the comma.

java/src/org/openqa/selenium/json/JsonInput.java[318-346]
java/src/org/openqa/selenium/json/JsonInput.java[534-574]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`JsonInput.hasNext()` now uses `containerHasElement` as a proxy for “a comma is required before the next element”. However, `markElementRead()` only ever sets the flag to `true`, and `hasNext()` never clears it after consuming a comma. This makes `hasNext()` non-idempotent: for valid input like `[1,2]`, after reading `1`, the first `hasNext()` consumes the comma and returns `true`, but a second `hasNext()` (before reading `2`) sees a value token with `seenElement==true` and throws.

### Issue Context
- `markElementRead()` sets the current container flag to `true` and never sets it back to `false`.
- `hasNext()` consumes the comma but does not update `containerHasElement`, so the subsequent non-comma path treats the next value token as a missing-comma violation.

### Fix Focus Areas
- java/src/org/openqa/selenium/json/JsonInput.java[318-346]
- java/src/org/openqa/selenium/json/JsonInput.java[534-574]
- java/test/org/openqa/selenium/json/JsonInputTest.java[312-356]

### How to fix
1. Treat the per-container boolean as “needsSeparator” (or add a separate boolean/stack for that state).
2. In `hasNext()` when a comma is successfully consumed, clear the flag for the current container (set it to `false`) so repeated `hasNext()` calls remain valid until an element is actually read.
  - e.g., add a helper like `markSeparatorRead()` that sets the top boolean to `false`.
3. Add a regression test demonstrating idempotency:
  - Parse `[1,2]`, read `1`, call `hasNext()` twice (both should be `true`), then read `2`.
  - Same idea for objects: `{"a":1,"b":2}` after reading `a:1`, call `hasNext()` twice before reading `b`.
4. Update the field comment/name if its semantics change (e.g., from “has seen an element” to “separator required / element just read”).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Results up to commit 1f44b29


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Remediation recommended
1. Comma enforcement bypassable ✓ Resolved 🐞 Bug ≡ Correctness
Description
Comma validation is implemented only in hasNext(), so callers that read multiple elements or object
members via next*()/nextName() without calling hasNext() can still successfully parse invalid JSON
like "[1 2]" or "{\"a\":1 \"b\":2}". This leaves a spec-compliance gap depending on call pattern,
despite the PR’s intent to enforce separators.
Code

java/src/org/openqa/selenium/json/JsonInput.java[R555-566]

+    // Handle the case where we're reading a value.
+    if (type == JsonType.END_COLLECTION || type == JsonType.END_MAP) {
+      // Closing the container - don't treat as a new element in it.
+      return;
+    }
    if (top == Container.MAP_VALUE) {
      stack.removeFirst();
      stack.addFirst(Container.MAP_NAME);
+      markElementRead();
+    } else if (top == Container.COLLECTION) {
+      markElementRead();
+    }
Evidence
peek() skips whitespace, so after reading the first element in [1 2] the next nextNumber() can
see 2 directly and succeed because expect() only checks the token type and then marks the
element as read; it does not enforce a required comma. The only place that enforces commas is
hasNext(), so callers who don’t call hasNext() between reads bypass the new separator rule. The
existing tests also show that reading without calling hasNext() is an expected usage pattern for
some cases (single-element arrays).

java/src/org/openqa/selenium/json/JsonInput.java[128-175]
java/src/org/openqa/selenium/json/JsonInput.java[228-286]
java/src/org/openqa/selenium/json/JsonInput.java[318-346]
java/src/org/openqa/selenium/json/JsonInput.java[534-567]
java/test/org/openqa/selenium/json/JsonInputTest.java[127-146]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`JsonInput` enforces commas only in `hasNext()`. If a caller reads successive elements (arrays) or successive name/value pairs (objects) by calling `nextNumber()`/`nextString()`/`nextName()` directly without an intervening `hasNext()`, the parser can still accept inputs that are missing commas (e.g. `[1 2]`, `{"a":1 "b":2}`).

## Issue Context
- `peek()` skips whitespace and can therefore see the next token immediately after a prior value.
- `expect()` validates token types and updates container state, but does not require or consume a comma separator between elements.
- The new separator logic is only in `hasNext()`, so it is easy to bypass by not calling `hasNext()`.

## Fix Focus Areas
- java/src/org/openqa/selenium/json/JsonInput.java[318-346]
- java/src/org/openqa/selenium/json/JsonInput.java[534-574]

### Suggested fix approach
Centralize separator validation/consumption in a helper that is invoked when starting to read a new element/property (e.g., from `expect()` for values and for `NAME` in objects). This should:
1) If the current container has already seen an element/pair, require a comma before the next element/pair.
2) Consume exactly one comma (if present) and then continue.
3) Keep `hasNext()` consistent with this logic (e.g., call the same helper or ensure separators aren’t double-consumed).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Results up to commit 73987ab


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Remediation recommended
1. Premature stack pop ✓ Resolved 🐞 Bug ☼ Reliability
Description
endArray()/endObject() pop both stack and containerHasElement before validating the container
type, so a mismatch exception leaves the parser state mutated and makes subsequent error
handling/recovery unreliable.
Code

java/src/org/openqa/selenium/json/JsonInput.java[R404-407]

    expect(JsonType.END_COLLECTION);
    Container expectation = stack.removeFirst();
+    containerHasElement.removeFirst();
    if (expectation != Container.COLLECTION) {
Evidence
Both endArray() and endObject() remove from the internal stacks before the type check that may
throw, meaning error paths happen after state mutation.

java/src/org/openqa/selenium/json/JsonInput.java[403-441]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`endArray()` and `endObject()` remove entries from `stack` and `containerHasElement` before checking whether the removed `Container` matches the expected container type. If the expectation check fails, a `JsonException` is thrown after internal state has already been mutated.

## Issue Context
This is especially relevant now that there are *two* parallel stacks to keep consistent; throwing after mutation makes debugging/recovery harder and can cause follow-on failures if callers catch exceptions.

## Fix Focus Areas
- java/src/org/openqa/selenium/json/JsonInput.java[403-441]

## Suggested fix
Change `endArray()`/`endObject()` to validate using `peekFirst()` (or store the peeked value) and only `removeFirst()` from both deques after the validation passes. For example:

```java
public void endArray() {
 expect(JsonType.END_COLLECTION);
 Container expectation = stack.peekFirst();
 if (expectation != Container.COLLECTION) {
   throw new JsonException(
     "Attempt to close a JSON List, but a JSON Object was expected. " + input);
 }
 stack.removeFirst();
 containerHasElement.removeFirst();
 input.read();
}
```

Apply the same pattern to `endObject()`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational
2. Object comma cases untested ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The new tests cover array missing/leading commas but do not add equivalent malformed-object cases,
leaving object-specific comma enforcement behavior unprotected against regressions.
Code

java/test/org/openqa/selenium/json/JsonInputTest.java[R414-430]

+  @Test
+  void shouldRejectMissingCommaBetweenArrayElements() {
+    try (JsonInput input = newInput("[1 2]")) {
+      input.beginArray();
+      assertThat(input.hasNext()).isTrue();
+      assertThat(input.nextNumber()).isEqualTo(1L);
+      assertThatExceptionOfType(JsonException.class).isThrownBy(input::hasNext);
+    }
+  }
+
+  @Test
+  void shouldRejectLeadingCommaInArray() {
+    try (JsonInput input = newInput("[,1]")) {
+      input.beginArray();
+      assertThatExceptionOfType(JsonException.class).isThrownBy(input::hasNext);
+    }
+  }
Evidence
The test additions include malformed array cases but no malformed object comma cases; object parsing
also has distinct tokenization behavior (NAME vs STRING) based on isReadingName(), so
object-specific tests add real protection.

java/test/org/openqa/selenium/json/JsonInputTest.java[387-463]
java/src/org/openqa/selenium/json/JsonInput.java[128-166]
java/src/org/openqa/selenium/json/JsonInput.java[561-563]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
There are new regression tests for array comma rules, but no tests asserting the same behavior for objects (missing comma between entries and leading comma in an object).

## Issue Context
`JsonInput.peek()` returns `JsonType.NAME` vs `JsonType.STRING` depending on whether the parser is currently expecting a property name (`isReadingName()`), so object paths are sufficiently distinct to warrant direct coverage.

## Fix Focus Areas
- java/test/org/openqa/selenium/json/JsonInputTest.java[387-463]
- java/src/org/openqa/selenium/json/JsonInput.java[128-166]
- java/src/org/openqa/selenium/json/JsonInput.java[561-563]

## Suggested fix
Add tests similar to the array ones, e.g.:
- Reject missing comma between object entries: `{"a":1 "b":2}` should throw from `hasNext()` after reading the first value.
- Reject leading comma in object: `{,"a":1}` should throw from `hasNext()` immediately after `beginObject()`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Qodo Logo

Comment thread java/src/org/openqa/selenium/json/JsonInput.java
@shs96c shs96c force-pushed the shs-json-hasnext-separator branch from 42e746e to 1f44b29 Compare July 3, 2026 10:25
Comment thread java/src/org/openqa/selenium/json/JsonInput.java
@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 1f44b29

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 6cb2aa0

shs96c added 3 commits July 3, 2026 15:45
hasNext() previously consumed a leading comma if present, but never
required one. That accepted spec-invalid inputs like '[1 2 3]' (missing
separator) and '[,1]' (leading comma). It also rejected trailing commas
like '[1,2,3,]' because it consumed the comma and then tried to read
another element.

Track whether the current container has seen an element (parallel deque
kept in sync with the container stack, marked in expect()) and use it
in hasNext() to require a comma between elements while allowing a
single trailing comma before the container's closer.
hasNext() consumed the comma between elements but did not clear the
'container has element' flag, so a second hasNext() before reading the
next value threw as if the comma were missing. Iterator-style callers
that probe multiple times per element saw spurious failures on valid
input like [1,2].
@shs96c shs96c force-pushed the shs-json-hasnext-separator branch from 6cb2aa0 to 73987ab Compare July 3, 2026 14:47
Comment thread java/src/org/openqa/selenium/json/JsonInput.java Outdated
Comment thread java/test/org/openqa/selenium/json/JsonInputTest.java
@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 73987ab

endArray()/endObject() popped the container stacks before checking the
container type, so a mismatched close corrupted parser state on top of
throwing. Check first, pop after. Also cover object-side comma
enforcement with tests to match the existing array cases.
@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit b91099f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C-java Java Bindings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants