# JSqlParser: turning SQL into a Java object tree, and back

> JSqlParser parses SQL into a traversable Java AST and renders it back to text. The README now points Maven users at Manticore builds rather than the older com.github.jsqlparser release, and that split is the first thing to understand before adopting it.

**JSQLParser/JSqlParser** — JSqlParser parses an SQL statement and translate it into a hierarchy of Java classes. The generated hierarchy can be navigated using the Visitor Pattern.

- Repository: https://github.com/JSQLParser/JSqlParser
- Website: https://github.com/JSQLParser/JSqlParser/wiki
- Stars: 5,964 · Forks: 1,433
- Language: Java
- License: Apache-2.0
- Published: 2026-08-08 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/jsqlparser-jsqlparser

## What JSqlParser is for, and who actually needs it

JSqlParser takes a string containing an SQL statement and produces a hierarchy of Java classes that mirrors the statement's structure. The README's own example is a single line, select 1 from dual where a=b, and the tree it prints shows a PlainSelect node holding selectItems, a Table node named dual, and an EqualsTo node with two Column children, a and b. That is the whole product in miniature.

The audience is narrow and specific. You need this when SQL is data to your program rather than something you send to a driver. Schema migration tools that inspect DDL, query rewriters that inject row filters, lineage and audit systems that need to know which columns a statement touches, and formatters that reprint SQL from a parsed model all sit in this space. If you are writing an application that issues fixed queries, you do not need a parser; a PreparedStatement is cheaper and safer.

The README also positions the project as RDBMS-agnostic: one grammar covering the SQL standard plus the major dialects, with missing syntax added on request through GitHub issues. That claim is the reason the project exists, and also the source of most of its sharp edges.

## How the AST and the Visitor pattern fit together

Parsing is the easy half. The README shows the entry point as CCJSqlParserUtil.parse, which returns a Statement that you cast to the concrete node you expect, here PlainSelect. From there, getSelectItems(), getFromItem() and getWhere() return child nodes, and the README's test asserts that the where clause is an EqualsTo whose left and right expressions are Columns named a and b. Direct casting works when you control the input shape.

The Visitor pattern is the mechanism for when you do not. Rather than instanceof chains across dozens of node types, you implement a visitor and let the tree dispatch to the right method. This matters because the node hierarchy is large: the README lists queries, DML, DDL, PostgreSQL row-level security statements and Salesforce SOQL extensions as covered statement families, and each family brings its own node classes.

The reverse direction is the part people underrate. The same object model can be built from Java through a fluent API and rendered back to SQL text. That makes JSqlParser usable as a rewriting engine: parse, mutate the tree, print. The README does not describe how faithfully the printer preserves the original formatting, comments or dialect-specific spellings, so treat round-trip fidelity as something to verify on your own statements rather than assume.

## Installing JSqlParser and parsing your first statement

The README is unusually direct about which build to use: the stable Manticore builds, released continuously from the current development line, and the upstream com.github.jsqlparser release on Maven Central is described as considerably older. For Maven, the README gives this dependency, with a version range starting at 5.3.218.

```xml
<dependency>
    <groupId>com.manticore-projects.jsqlformatter</groupId>
    <artifactId>jsqlparser</artifactId>
    <version>[5.3.218,)</version>
</dependency>
```

Gradle users get the equivalent one-liner from the README:

```gradle
implementation("com.manticore-projects.jsqlformatter:jsqlparser:+")
```

The README keeps the upstream coordinates in a collapsed section, as a fallback rather than the default:

```xml
<dependency>
    <groupId>com.github.jsqlparser</groupId>
    <artifactId>jsqlparser</artifactId>
    <version>5.3</version>
</dependency>
```

With either resolved, the first real use is the README's own example. It parses a statement, walks to the select item, the from item and the where clause, and asserts on each.

```java
String sqlStr = "select 1 from dual where a=b";

PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(sqlStr);

SelectItem selectItem = select.getSelectItems().get(0);
Assertions.assertEquals(new LongValue(1), selectItem.getExpression());

Table table = (Table) select.getFromItem();
Assertions.assertEquals("dual", table.getName());

EqualsTo equalsTo = (EqualsTo) select.getWhere();
Column a = (Column) equalsTo.getLeftExpression();
Column b = (Column) equalsTo.getRightExpression();
Assertions.assertEquals("a", a.getColumnName());
Assertions.assertEquals("b", b.getColumnName());
```

If those assertions pass, you have a working parse path. Note the cast to PlainSelect and the cast to EqualsTo: the API is typed by node class, so the caller is responsible for knowing what shape it asked for. Snapshot coordinates and repository configuration live on the project's build dependencies page, which the README links rather than reproducing.

## The two Maven coordinates are the real adoption decision

Most Java libraries have one coordinate. JSqlParser's README presents two, and tells you to prefer the one that is not on Maven Central under the traditional group. That is a governance question disguised as a build detail.

The Manticore artifact is com.manticore-projects.jsqlformatter:jsqlparser, versioned with a range like [5.3.218,). A version range means your build resolves to whatever is newest at build time, which is convenient for picking up grammar fixes and inconvenient for reproducible builds. The upstream artifact is com.github.jsqlparser:jsqlparser at a pinned 5.3, which is older but stable in the sense that the version string never moves.

The performance section is where the split becomes concrete. The README reports the latest build at 7.602 ms/op against 5.3 at 84.687 ms/op on JSQLParserBenchmark.parseSQLStatements, an 11x difference, with methodology in the manticore-projects/jsqlparser-bench repository. Those numbers come from the project's own benchmark harness and its own SELECT test suite, so read them as an indication of where the development line has gone rather than as a neutral measurement. The useful takeaway is directional: the Manticore line is where grammar and performance work lands, and the pinned upstream release is behind it.

The practical rule is to pick one coordinate and pin it explicitly, even if the README shows a range. Mixing both artifacts on one classpath is the failure mode nobody wants to debug.

## Dialect coverage, JDK requirements and where it breaks

The README claims one grammar for twelve-plus dialects, listing BigQuery, Snowflake, DuckDB, Redshift, Oracle, MS SQL Server, Sybase, PostgreSQL, MySQL, MariaDB, DB2, H2, HSQLDB, Derby and SQLite. It also names the specific hard cases the grammar handles: nested sub-selects, bind parameters in both ? and :name form, window and analytic functions, Oracle hints, and the T-SQL square-bracket versus array-literal ambiguity. Piped SQL support is described as progressing, not finished, with a sample using the |> operator and FROM-first ordering.

That is a lot of surface, and the honest reading is that coverage is per-construct, not per-dialect. A statement that is valid in your database may still fail to parse if nobody has added that production to the grammar yet. The README's remedy is to open an issue. For a team shipping on a schedule, a parser that needs a grammar change upstream before it accepts your DDL is a dependency risk, not a bug.

The JDK table is the other hard constraint. Version 4.9 was the last JDK 8 compatible release. Version 5.0 and later require JDK 11 at runtime and introduced breaking changes to the AST visitors, documented in a migration guide. From 5.1, building the project requires a JDK 17 toolchain because of a plugin requirement, and 5.4 and later generate the parser with JavaCC 8. If you are pinned to JDK 8, the modern line is simply unavailable to you. If you have written visitor implementations, the 5.0 visitor changes are the migration cost, and the README points at the guide rather than describing the changes inline.

## Alternatives: JOOQ's parser and the Python side

The README names JOOQ as the alternative, and the difference is architectural. JOOQ ships a hand-written parser with broad RDBMS support, cross-dialect translation, SQL transformation and a JDBC integration story, under a dual licence. JSqlParser generates its parser from a grammar. The practical consequences run in both directions: a hand-written parser can encode dialect quirks that a grammar expresses awkwardly, while a generated grammar tends to be more uniform across the statement families it covers and easier to extend by adding productions.

The other difference is scope. JOOQ is a database access library that happens to include a parser; JSqlParser is a parser and an object model. If you want to translate a MySQL query into PostgreSQL syntax, the README points at a sister project, JSQLTranspiler, which handles dialect-specific rewriting, column resolution and lineage. JSqlParser alone gives you the tree; the rewriting rules are a separate concern.

For readers coming from Python, the search terms around Python SQL parsing are common, but this project is JVM-only. sqlglot appears in the README only as a benchmark comparison target, not as an integration path, and the README's comparison runs on JSqlParser's own SELECT test suite. If your pipeline is Python, JSqlParser is the wrong tool regardless of how the benchmark table reads.

## Version support, licensing and the cost of staying current

The repository root contains both LICENSE_APACHEV2 and LICENSE_LGPLV21, and the project description states Apache-2.0. Two licence files in one tree is a signal that different parts of the distribution may carry different terms, and the README does not explain which file governs which artifact. That is a question for your own legal review, not something to infer from the file names. The point worth flagging is simply that the licence situation is not a single line in a table.

On maintenance: the most recent release listed is jsqlparser-5.3, pushed on 2025-05-17, with 5.2 on 2025-05-04 and 5.1 on 2025-01-02. The repository is not archived. The README's own framing, that the Manticore builds are released continuously from the current development line, describes a cadence that the tagged releases alone do not capture.

Upgrade cost concentrates in two places. The visitor interfaces changed at 5.0, so any code implementing them needs the migration guide. The Maven coordinate question resurfaces at every dependency review, because the README's recommended artifact is not the one most build files already contain. Neither is expensive once, but both are recurring if your team does not write the decision down.

## Conclusion

Adopt JSqlParser if you are on the JVM and need to read, rewrite or regenerate SQL as structured objects rather than as strings, and you accept that the Maven coordinates the README recommends are the Manticore builds, not com.github.jsqlparser. Do not adopt it if you need a general-purpose SQL engine, a cross-dialect translator (that is JSQLTranspiler's job), or a parser for a language that is not SQL. Before committing, verify three things against your own corpus: that your dialect's specific syntax parses under the 5.3 line, which of the two Maven coordinates you are actually resolving, and whether the LGPL-2.1 file in the repository root affects the artifact you ship.

## FAQ

### What is the main difference between SQL and JPQL?

The README does not cover JPQL. JSqlParser parses SQL: it takes a statement such as select 1 from dual where a=b and produces a Java object tree, and its dialect list names database engines rather than query languages.

### What is SQL parsing?

It is the step that turns an SQL string into a structured representation a program can inspect. In JSqlParser the result is a hierarchy of Java classes, with PlainSelect, Table, Column and EqualsTo nodes in the README's example, walkable with the Visitor pattern.

### Is there a Python library that can parse SQL?

The README does not recommend one. It is a JVM parser, and sqlglot appears there only as a benchmark comparison target, not as an integration path. Python pipelines need a different tool.

### Is JQL similar to SQL?

The README says nothing about JQL. JSqlParser targets SQL and its dialects, and lists BigQuery, Snowflake, DuckDB, Redshift, Oracle, MS SQL Server, PostgreSQL, MySQL, MariaDB, DB2, H2, HSQLDB, Derby and SQLite.

## Sources

- [Official documentation](https://github.com/JSQLParser/JSqlParser/wiki)
- [Official README](https://github.com/JSQLParser/JSqlParser#readme)
- [Project repository](https://github.com/JSQLParser/JSqlParser)
- [Release notes](https://github.com/JSQLParser/JSqlParser/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/jsqlparser-jsqlparser
