Description
I had a Java class using a builder pattern to put together a lookup table. There was another class which chained together 600+ method calls on a single line on this builder, assembling the table. Understandably, as the number of entries in the lookup table grew, we eventually ran into a StackOverflowError
from javac
while compiling the class. javac
does not handle this gracefully; the SOE stacktrace is written to stderr with no surrounding context clues, and then the compiler exits.
The project is built using Maven, which of course uses plexus-compiler-javac
. We run the build in forked mode.
Unfortunately, the Plexus compiler recognizes the forked build as failed, but does not capture the cause. There are no messages on the CompilerResult
, and nothing is printed to stdout/stderr. It was therefore quite difficult for me to diagnose the cause of the compilation failure. By enabling verbose mode, I was able to see the compiler's progress, and through process of elimination I identified the problematic class. One look at the class led me to suspect an SOE, which I was able to verify by compiling the class manually at the command line. From there, it was a simple matter of splitting up the line of code into multiple lines.
I have created an MVCE here: https://github.com/jakerobb/plexus-javac-compiler-bug. It's a small Maven project. Just clone it and run mvn test
to reproduce the issue.
I think that #39 would have been helpful here, but I also think that some other improvements are called for:
- If compilation fails and there are no messages, add a custom message indicating that there is a likely compiler issue, and then proxy the entire output through, regardless of whether any "debug flag" is set.
- Capture and recognize exception stacktraces on javac's stderr. Treat them similarly to number 1 above, but with a different message.
- If possible, include the name of the problematic file in the output. I know javac isn't returning this, but it seems like it might be possible to determine; I don't want to assume.
Of course, ideally, javac should be fixed to not throw an SOE in this scenario, probably by replacing recursion with iteration, and also to write out the file it was working on when compilation fails. I'm now off to figure out how to report an improvement request in javac....