Skip to content

Commit d31f81d

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 d31f81d

File tree

1 file changed

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

1 file changed

+40
-30
lines changed

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

+40-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,11 @@ private static CompilerResult compileInProcess0(Class<?> javacClass, String[] ar
627628
return new CompilerResult(success, messages);
628629
}
629630

631+
private static final Pattern STACK_TRACE_FIRST_LINE =
632+
Pattern.compile("^(?:[\\w+.-]+\\.)[\\w$]*?(?:Exception|Error|Throwable|Failure).*$");
633+
private static final Pattern STACK_TRACE_OTHER_LINE =
634+
Pattern.compile("^(?:Caused by:\\s.*|\\s*at .*|\\s*\\.\\.\\.\\s\\d+\\smore)$");
635+
630636
/**
631637
* Parse the output from the compiler into a list of CompilerMessage objects
632638
*
@@ -643,6 +649,7 @@ static List<CompilerMessage> parseModernStream(int exitCode, BufferedReader inpu
643649
StringBuilder buffer = new StringBuilder();
644650

645651
boolean hasPointer = false;
652+
int stackTraceLineCount = 0;
646653

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

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);
702+
if (stackTraceLineCount == 0 && STACK_TRACE_FIRST_LINE.matcher(line).matches()
703+
|| STACK_TRACE_OTHER_LINE.matcher(line).matches()) {
704+
stackTraceLineCount++;
705+
} else {
706+
stackTraceLineCount = 0;
682707
}
683708

684709
// new error block?
@@ -714,21 +739,6 @@ static List<CompilerMessage> parseModernStream(int exitCode, BufferedReader inpu
714739
}
715740
}
716741

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-
732742
private static boolean isMisc(String line) {
733743
return startsWithPrefix(line, MISC_PREFIXES);
734744
}

0 commit comments

Comments
 (0)