Parser fails on extraneous semicolon in import statement when followed by another import
What version of OpenRewrite are you using?
I am using
- OpenRewrite v8.64.0
- Maven plugin v6.23.0
How are you running OpenRewrite?
I am using the Maven plugin to upgrade repositories to JDK 21. The issue occurs during the parsing stage when running mvn rewrite:run.
Configurations I am using
mvn -v
Output:
Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Maven home: /Users/saransh.kasliwal/.sdkman/candidates/maven/current
Java version: 17.0.1, vendor: Oracle Corporation, runtime: /Users/saransh.kasliwal/.sdkman/candidates/java/17.0.1-open
Default locale: en_IN, platform encoding: UTF-8
OS name: "mac os x", version: "15.6", arch: "aarch64", family: "mac"
java -version
Output:
openjdk version "17.0.1" 2021-10-19
OpenJDK Runtime Environment (build 17.0.1+12-39)
OpenJDK 64-Bit Server VM (build 17.0.1+12-39, mixed mode, sharing)
I am using the Maven plugin on a multi-module project, but the issue is reproducible in a single module project. The issue occurs during the parsing stage when running mvn rewrite:run.
What is the smallest, simplest way to reproduce the problem?
This code FAILS to parse:
Create a simple Maven project and add a file at src/main/java/Main.java with the following content:
import java.util.*;; // Semicolon here
import java.io.*; // Followed by another import
public class Main {
public static void main(String[] args) {
System.out.printf("Hello and welcome!");
}
}
When you run mvn rewrite:run with this org.openrewrite.staticanalysis.RemoveExtraSemicolons recipe, the build will show a parsing warning for Main.java, and no changes will be applied.
Interestingly, if the import with the extraneous semicolon is the last import, the parser handles it correctly and the recipe works as expected.
This code is parsed SUCCESSFULLY:
import java.util.*;; // Semicolon here, but it's the last import
public class Main {
public static void main(String[] args) {
System.out.printf("Hello and welcome!");
}
}
What did you expect to see?
I expected the parser to successfully handle the code without any warnings. Then, I expected the RemoveExtraSemicolons recipe to run and correct the code, resulting in:
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) {
System.out.printf("Hello and welcome!");
}
}
What did you see instead?
Instead of a successful run, the parser fails and emits a warning. The file is not processed by any recipes, and no changes are made. The original code remains unchanged.
I believe this points to an issue in the parser logic that prevents it from handling this specific syntax case. As a temporary workaround, we were able to make the change using a Find and replace text recipe, but this is not a sustainable solution.
The critical impact is that this parsing failure blocks all other recipes from running on the affected files. If a file contains this minor syntax issue, it cannot receive more complex and necessary refactoring from other recipes. This is a significant blocker for our upgrade process and could impact many other users as well.
What is the full stack trace of any errors you encountered?
Run Command mvn rewrite:run --errors
And see logs like this:
[INFO] Error stacktraces are turned on.
[INFO] Using active recipe(s) [org.openrewrite.staticanalysis.RemoveExtraSemicolons]
[INFO] Using active styles(s) []
[INFO] Validating active recipes...
[INFO] Project [TestProject] Resolving Poms...
[INFO] Project [TestProject] Parsing source files
[WARNING] There were problems parsing some source files
[WARNING] There were problems parsing src/main/java/Main.java
[WARNING] java.lang.IllegalStateException: src/main/java/Main.java is not print idempotent.
diff --git a//Users/saransh.kasliwal/Documents/GitHub/TestProject/src/main/java/Main.java b//Users/saransh.kasliwal/Documents/GitHub/TestProject/src/main/java/Main.java
index 6964b61..3fdcfd0 100644
--- a//Users/saransh.kasliwal/Documents/GitHub/TestProject/src/main/java/Main.java
+++ b//Users/saransh.kasliwal/Documents/GitHub/TestProject/src/main/java/Main.java
@@ -1,4 +1,4 @@
-import java.util.*;; // Semicolon here
+import java.util.*;importjava Semicolon here
import java.io.*; // Followed by another import
public class Main {
org.openrewrite.Parser.requirePrintEqualsInput(Parser.java:52)
[INFO] Running recipe(s)...
[INFO] Printing available datatables to: target/rewrite/datatables/2025-11-19_16-17-43-116
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.752 s
[INFO] Finished at: 2025-11-19T16:17:43+05:30
[INFO] ------------------------------------------------------------------------
Are you interested in contributing a fix to OpenRewrite?
Yes, I would love to contribute and understand the parsing logic better.
Thanks for the help! Feel free to start a draft pull request with a new failing test and explore from there.
There's also been some earlier related work in this topic:
- https://github.com/openrewrite/rewrite/issues/4569
- https://github.com/openrewrite/rewrite/pull/5878
- https://github.com/openrewrite/rewrite/issues/5735
I've created this draft PR to investigate and address the consecutive semicolons parsing issue. Here's the current status:
I've successfully added a debug test that reproduces the consecutive semicolons problem. The good news is that my changes prevent the parser from throwing a ParseError, it now generates an LST tree and maintains source code round-trip preservation. However, the resulting tree contains J.Erroneous nodes, indicating it's not correctly representing the consecutive semicolons. I've tried fixing the tree generation but can't eliminate these erroneous nodes. I need guidance from maintainers on the proper approach whether to handle this at the grammar level or post-processing, and how to correctly represent extra semicolons in the LST without J.Erroneous nodes.
- The draft PR is at https://github.com/openrewrite/rewrite/pull/6323.
Would love feedback on the direction and suggestions for proper implementation.
OSS repro for similar or maybe the same problem:
- https://github.com/Fr4gorSoftware/SecScanQR/blob/6d38f69fed1ebad1794befc0741c2d650ea32d82/app/src/main/java/de/t_dankworth/secscanqr/util/DatabaseHelper.java#L2