openrewrite / openrewrite/rewrite
Java parse-to-print idempotence: untyped lambda in super() prints as varprocessBuilder
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 3.7k
- Forks
- 571
- Avg merge
- 13h 12m
- Merged PRs (30d)
- 261
Description
What version of OpenRewrite are you using?
I am using
- rewrite-java-25 v8.90.3
(JDK 25)
How are you running OpenRewrite?
Custom code using JavaParser.fromJavaVersion().build() to parse a source file (same parser stack recipes use for Java sources).
What is the smallest, simplest way to reproduce the problem?
When a constructor calls super(...) with an untyped lambda argument for a functional-interface parameter, parse-to-print idempotence fails: the parser returns ParseError instead of CompilationUnit. The erroneous tree prints the lambda parameter as varprocessBuilder -> instead of processBuilder ->.
An explicit functional-interface cast makes the source round-trip.
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.java.JavaParser;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaParserResult;
public class ReproduceSuperCallLambdaParseIdempotence {
public static void main(String[] args) {
String source = """
package example.superlambda;
import java.nio.file.Path;
interface ProcessLauncher {
void launch(Object processBuilder);
}
class ParentProperties {
ParentProperties(Object... ignored) {}
}
class ParentRunManager {
ParentRunManager(ParentProperties properties, ProcessLauncher launcher, Object config) {}
}
class ChildRunManager extends ParentRunManager {
ChildRunManager() {
super(
new ParentProperties(
Path.of("build"), Path.of("app.jar"), 1, 1, 0.10, 100, 4096, ""),
processBuilder -> {
throw new UnsupportedOperationException("never launches processes");
},
new Object());
}
}
""";
var ctx = new InMemoryExecutionContext(t -> { throw new RuntimeException(t); });
JavaParserResult result = JavaParser.fromJavaVersion().build().parse(ctx, source).findFirst().orElseThrow();
System.out.println("Parse result class: " + result.getClass().getSimpleName());
if (result instanceof J.ParseError parseError) {
System.out.println("=== ERRONEOUS PRINT ===");
System.out.println(parseError.getErroneous().printAll());
}
}
}
What did you expect to see?
parse(...)yieldsCompilationUnit(parse-to-print idempotence).- Printed source contains
processBuilder ->, notvarprocessBuilder ->.
What did you see instead?
ParseErrorwith parse-to-print idempotence failure.- Erroneous print contains
varprocessBuilder ->(spuriousvarfused onto the parameter name).
What is the full stack trace of any errors you encountered?
No exception stack trace — failure is the non-CompilationUnit parse result and non-idempotent print.
Workaround
Add an explicit functional-interface cast on the lambda:
(ProcessLauncher) (processBuilder -> {
throw new UnsupportedOperationException("never launches processes");
})
After the cast, the same compilation unit parses as CompilationUnit.
Related (not this bug)
- #5921 — unnamed
_lambda parameters (fixed) - #5329 — type annotations on arrays (fixed)
Are you interested in contributing a fix to OpenRewrite?
Yes, happy to contribute a PR or upstream test if you can point to the preferred location in the Java parser/printer.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the reproducer through JavaParser.fromJavaVersion().build().parse and inspect the J.ParseError output from printAll(). Trace how an untyped lambda in a super(...) argument is parsed and printed. Done means the source parses as a CompilationUnit and the output contains processBuilder -> rather than varprocessBuilder ->.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100