Skip to content

JsonPath AST implementation#123

Closed
simbo1905 wants to merge 4 commits intomainfrom
cursor/jsonpath-ast-implementation-bbd2
Closed

JsonPath AST implementation#123
simbo1905 wants to merge 4 commits intomainfrom
cursor/jsonpath-ast-implementation-bbd2

Conversation

@simbo1905
Copy link
Owner

This pull request contains changes generated by a Cursor Cloud Agent

Open in Cursor Open in Web

cursoragent and others added 4 commits January 31, 2026 16:04
Co-authored-by: simbo1905 <simbo1905@60hertz.com>
Co-authored-by: simbo1905 <simbo1905@60hertz.com>
Co-authored-by: simbo1905 <simbo1905@60hertz.com>
Co-authored-by: simbo1905 <simbo1905@60hertz.com>
@cursor
Copy link

cursor bot commented Feb 1, 2026

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@gemini-code-assist
Copy link

Summary of Changes

Hello @simbo1905, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request integrates a new JsonPath module into the project, enabling powerful querying capabilities for JSON structures. By parsing JsonPath expressions into a custom AST and evaluating them against existing JSON documents, it provides a lightweight and modern Java 21-centric solution for navigating and extracting data from JSON, without introducing external dependencies.

Highlights

  • New JsonPath Module: Introduces a new Maven module json-java21-jsonpath for implementing JsonPath functionality, adhering to Stefan Goessner's specification.
  • Custom AST and Evaluator: The module includes a custom Abstract Syntax Tree (AST) for parsing JsonPath strings and an evaluator to apply these expressions against JSON documents parsed by the existing jdk.sandbox.java.util.json API.
  • Dependency-Free and Java 21 Focused: Designed with no runtime dependencies beyond java.base and the core json-java21 module, targeting Java 21 with a functional/data-oriented style using records and sealed interfaces.
  • Comprehensive Parsing and Evaluation: Features a hand-rolled scanner and recursive descent parser, capable of handling various JsonPath steps including child selection, recursive descent, wildcards, array indexing, slicing, unions, and filter expressions.
  • Extensive Test Coverage: Includes a suite of unit tests that directly correspond to the examples provided in Stefan Goessner's original JsonPath article, ensuring robust and accurate behavior.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 59d909b17c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +275 to +279
case Value.Json(var x) -> {
if (b instanceof Value.Json j) {
yield switch (x) {
case JsonString js -> (j.value() instanceof JsonString rhs) && js.string().equals(rhs.string());
case JsonNumber jn -> (j.value() instanceof JsonNumber rhs) && Double.compare(jn.toDouble(), rhs.toDouble()) == 0;

Choose a reason for hiding this comment

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

P2 Badge Allow equality between JsonValue and literal values

In filter equality comparisons, equalsValue only returns true when both sides are the same Value variant. This means a path result like @.price (which becomes Value.Json(JsonNumber)) compared to a numeric literal (Value.Num) or string literal (Value.Str) will always be false, so expressions like ?(@.price == 8.95) or ?(@.category == 'fiction') never match. This is a behavioral bug in the new JsonPath evaluator because it makes equality filters against JSON primitives unusable unless both operands come from paths.

Useful? React with 👍 / 👎.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a comprehensive implementation of JsonPath, including a parser, AST, and evaluator. The code is well-structured, using modern Java features like records and sealed interfaces, which aligns with the project's goals. The implementation correctly follows the examples from Stefan Goessner's article.

I've identified a few areas for improvement:

  • The ArraySlice implementation is missing support for the step parameter.
  • The parser's handling of quoted string literals has a bug with escape sequences.
  • There's a potential precision loss when casting script expression results for array indexing.
  • The Maven artifactId could be more conventional.

Overall, this is a great addition to the project. Addressing these points will make the implementation more robust and complete.

Comment on lines +172 to +179
if (c == '\\') {
consume('\\');
if (eof()) throw error("Unterminated escape sequence");
final char e = cur();
consume(e);
sb.append(e);
continue;
}

Choose a reason for hiding this comment

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

high

The handling of escape sequences in parseQuotedString is incomplete. It currently only escapes the character that follows a backslash, which is incorrect for standard JSON string escapes like \n, \t, or \uXXXX. String literals in JsonPath should be treated as regular JSON strings. This can lead to incorrect parsing of property names that contain special characters. A more robust implementation should handle all valid JSON escape sequences.

                if (c == '\\') {
                    consume('\\');
                    if (eof()) throw error("Unterminated escape sequence");
                    final char e = cur();
                    consume(e);
                    switch (e) {
                        case '"' -> sb.append('"');
                        case '\\' -> sb.append('\\');
                        case '/' -> sb.append('/');
                        case 'b' -> sb.append('\b');
                        case 'f' -> sb.append('\f');
                        case 'n' -> sb.append('\n');
                        case 'r' -> sb.append('\r');
                        case 't' -> sb.append('\t');
                        case 'u' -> {
                            if (i + 3 >= in.length()) throw error("Invalid unicode escape sequence");
                            String hex = in.substring(i, i + 4);
                            try {
                                sb.append((char) Integer.parseInt(hex, 16));
                                i += 4;
                            } catch (NumberFormatException nfe) {
                                throw error("Invalid unicode escape: \\u" + hex);
                            }
                        }
                        default -> throw error("Invalid escape sequence: \\" + e);
                    }
                    continue;
                }

<version>0.1.9</version>
</parent>

<artifactId>java.util.json.jsonpath</artifactId>

Choose a reason for hiding this comment

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

medium

The artifactId java.util.json.jsonpath is unconventional and inconsistent with the module's directory name (json-java21-jsonpath). While this seems to follow a pattern from the jtd module, it can be confusing. Maven convention generally suggests that the artifactId matches the directory name for multi-module projects. Consider renaming the artifactId to json-java21-jsonpath for better clarity and consistency with standard Maven practices.

Suggested change
<artifactId>java.util.json.jsonpath</artifactId>
<artifactId>json-java21-jsonpath</artifactId>


record ArrayIndex(int index) implements Step {}

record ArraySlice(Integer startInclusive, Integer endExclusive) implements Step {}

Choose a reason for hiding this comment

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

medium

The ArraySlice record is missing the step parameter. The JsonPath syntax as described in the Goessner article includes support for [<start>:<end>:<step>]. The implementation plan in PLAN_121.md also mentioned step. This is a feature gap that limits the expressiveness of slice operations. Please consider adding support for the step parameter, which would also require updates to the parser and evaluator.

Suggested change
record ArraySlice(Integer startInclusive, Integer endExclusive) implements Step {}
record ArraySlice(Integer startInclusive, Integer endExclusive, Integer step) implements Step {}

final var value = evalValue(expr, arr);
final var number = toNumber(value);
if (number == null) continue;
final int idx = normalizeIndex((int) number.doubleValue(), arr.elements().size());

Choose a reason for hiding this comment

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

medium

In selectScriptIndex, the result of a script expression is cast from a double to an int for array indexing. This truncation can lead to a loss of precision and unexpected behavior if the expression evaluates to a non-integer value (e.g., 1.9 would become 1). The JsonPath specification is not explicit here, but this silent truncation might be a bug. Consider validating that the number is a whole number, or using a defined rounding method like Math.round() to make the behavior explicit.

Suggested change
final int idx = normalizeIndex((int) number.doubleValue(), arr.elements().size());
final int idx = normalizeIndex((int) Math.round(number), arr.elements().size());

@simbo1905 simbo1905 closed this Feb 1, 2026
@simbo1905 simbo1905 deleted the cursor/jsonpath-ast-implementation-bbd2 branch February 1, 2026 18:39
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.

2 participants