Skip to content

Commit 414ed21

Browse files
committed
Improve javac error output parsing
Instead of two separate 'while' loops, one inline and one in an extra method, parsing stack traces after finding error messages specific to the English locale of the JDK, now there is generic stack trace parsing, which works in these two cases independent of locale and also in others previously not covered. For backward compatibility, the Javac localized message 'javac.msg.bug' ("An exception has occurred in the compiler ... Please file a bug") is salvaged in a locale-independent way, matching on error reporting URLs always occurring in all JDK locales (English, Japanese, Chinese, German as of JDK 21).
1 parent 48ac162 commit 414ed21

File tree

1 file changed

+45
-30
lines changed
  • plexus-compilers/plexus-compiler-javac/src/main/java/org/codehaus/plexus/compiler/javac

1 file changed

+45
-30
lines changed

plexus-compilers/plexus-compiler-javac/src/main/java/org/codehaus/plexus/compiler/javac/JavacCompiler.java

+45-30
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
import java.util.Properties;
6666
import java.util.StringTokenizer;
6767
import java.util.concurrent.ConcurrentLinkedDeque;
68+
import java.util.regex.Pattern;
6869

6970
import org.codehaus.plexus.compiler.AbstractCompiler;
7071
import org.codehaus.plexus.compiler.CompilerConfiguration;
@@ -627,6 +628,16 @@ private static CompilerResult compileInProcess0(Class<?> javacClass, String[] ar
627628
return new CompilerResult(success, messages);
628629
}
629630

631+
// Match ~95% of existing JDK exception name patterns (last checked for JDK 21)
632+
private static final Pattern STACK_TRACE_FIRST_LINE = Pattern.compile("^(?:[\\w+.-]+\\.)[\\w$]*?(?:"
633+
+ "Exception|Error|Throwable|Failure|Result|Abort|Fault|ThreadDeath|Overflow|Warning|"
634+
+ "NotSupported|NotFound|BadArgs|BadClassFile|Illegal|Invalid|Unexpected|Unchecked|Unmatched\\w+"
635+
+ ").*$");
636+
637+
// Match exception causes, existing and omitted stack trace elements
638+
private static final Pattern STACK_TRACE_OTHER_LINE =
639+
Pattern.compile("^(?:Caused by:\\s.*|\\s*at .*|\\s*\\.\\.\\.\\s\\d+\\smore)$");
640+
630641
/**
631642
* Parse the output from the compiler into a list of CompilerMessage objects
632643
*
@@ -643,6 +654,7 @@ static List<CompilerMessage> parseModernStream(int exitCode, BufferedReader inpu
643654
StringBuilder buffer = new StringBuilder();
644655

645656
boolean hasPointer = false;
657+
int stackTraceLineCount = 0;
646658

647659
while (true) {
648660
line = input.readLine();
@@ -659,26 +671,44 @@ static List<CompilerMessage> parseModernStream(int exitCode, BufferedReader inpu
659671
} else if (hasPointer) {
660672
// A compiler message remains in buffer at end of parse stream
661673
errors.add(parseModernError(exitCode, bufferAsString));
674+
} else if (stackTraceLineCount > 0) {
675+
// Extract stack trace from end of buffer
676+
String[] lines = bufferAsString.split("\\R");
677+
int linesTotal = lines.length;
678+
buffer = new StringBuilder();
679+
int firstLine = linesTotal - stackTraceLineCount;
680+
681+
// Salvage Javac localized message 'javac.msg.bug' ("An exception has occurred in the
682+
// compiler ... Please file a bug")
683+
if (firstLine > 0) {
684+
final String lineBeforeStackTrace = lines[firstLine - 1];
685+
// One of those two URL substrings should always appear, without regard to JVM locale.
686+
// TODO: Update, if the URL changes, last checked for JDK 21.
687+
if (lineBeforeStackTrace.contains("java.sun.com/webapps/bugreport")
688+
|| lineBeforeStackTrace.contains("bugreport.java.com")) {
689+
firstLine--;
690+
}
691+
}
692+
693+
// Note: For message 'javac.msg.proc.annotation.uncaught.exception' ("An annotation processor
694+
// threw an uncaught exception"), there is no locale-independent substring, and the header is
695+
// also multi-line. It was discarded in the removed method 'parseAnnotationProcessorStream',
696+
// and we continue to do so.
697+
698+
for (int i = firstLine; i < linesTotal; i++) {
699+
buffer.append(lines[i]).append(EOL);
700+
}
701+
errors.add(new CompilerMessage(buffer.toString(), CompilerMessage.Kind.ERROR));
662702
}
663703
}
664704
return errors;
665705
}
666706

667-
// A compiler error occurred, treat everything that follows as part of the error.
668-
if (line.startsWith("An exception has occurred in the compiler")) {
669-
buffer = new StringBuilder();
670-
671-
while (line != null) {
672-
buffer.append(line);
673-
buffer.append(EOL);
674-
line = input.readLine();
675-
}
676-
677-
errors.add(new CompilerMessage(buffer.toString(), CompilerMessage.Kind.ERROR));
678-
return errors;
679-
} else if (line.startsWith("An annotation processor threw an uncaught exception.")) {
680-
CompilerMessage annotationProcessingError = parseAnnotationProcessorStream(input);
681-
errors.add(annotationProcessingError);
707+
if (stackTraceLineCount == 0 && STACK_TRACE_FIRST_LINE.matcher(line).matches()
708+
|| STACK_TRACE_OTHER_LINE.matcher(line).matches()) {
709+
stackTraceLineCount++;
710+
} else {
711+
stackTraceLineCount = 0;
682712
}
683713

684714
// new error block?
@@ -714,21 +744,6 @@ static List<CompilerMessage> parseModernStream(int exitCode, BufferedReader inpu
714744
}
715745
}
716746

717-
private static CompilerMessage parseAnnotationProcessorStream(final BufferedReader input) throws IOException {
718-
String line = input.readLine();
719-
final StringBuilder buffer = new StringBuilder();
720-
721-
while (line != null) {
722-
if (!line.startsWith("Consult the following stack trace for details.")) {
723-
buffer.append(line);
724-
buffer.append(EOL);
725-
}
726-
line = input.readLine();
727-
}
728-
729-
return new CompilerMessage(buffer.toString(), CompilerMessage.Kind.ERROR);
730-
}
731-
732747
private static boolean isMisc(String line) {
733748
return startsWithPrefix(line, MISC_PREFIXES);
734749
}

0 commit comments

Comments
 (0)