From 789f9c8c4ba5ca1c803383f917e4975cf4efd047 Mon Sep 17 00:00:00 2001 From: Ruedi Steinmann Date: Tue, 15 May 2018 08:55:06 +0200 Subject: [PATCH] introduce a result interface to allow extraction of diagnostics --- .../org/mdkt/compiler/CompilationResult.java | 40 +++++++ .../mdkt/compiler/InMemoryJavaCompiler.java | 107 ++++++++++++++---- 2 files changed, 124 insertions(+), 23 deletions(-) create mode 100644 src/main/java/org/mdkt/compiler/CompilationResult.java diff --git a/src/main/java/org/mdkt/compiler/CompilationResult.java b/src/main/java/org/mdkt/compiler/CompilationResult.java new file mode 100644 index 0000000..cb16a67 --- /dev/null +++ b/src/main/java/org/mdkt/compiler/CompilationResult.java @@ -0,0 +1,40 @@ +package org.mdkt.compiler; + +import java.util.List; +import java.util.Map; + +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; + +public interface CompilationResult { + /** + * Return the compiled classes + */ + Map> classMap() throws ClassNotFoundException; + + /** + * Determine if the compilation did succeed + */ + boolean compilationSucceeded(); + + /** + * Determine if any warnings are present + */ + boolean hasWarnings(); + + /** + * Determine if any errors are present + */ + boolean hasErrors(); + + /** + * Return the diagnostics produced by the compiler + */ + List> getDiagnostics(); + + /** + * Throw an exception if the compilation did not succeed + */ + CompilationResult checkNoErrors(); + +} diff --git a/src/main/java/org/mdkt/compiler/InMemoryJavaCompiler.java b/src/main/java/org/mdkt/compiler/InMemoryJavaCompiler.java index b853590..757df2d 100644 --- a/src/main/java/org/mdkt/compiler/InMemoryJavaCompiler.java +++ b/src/main/java/org/mdkt/compiler/InMemoryJavaCompiler.java @@ -1,8 +1,18 @@ package org.mdkt.compiler; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; -import javax.tools.*; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.ToolProvider; /** * Compile Java sources in-memory @@ -65,6 +75,14 @@ public InMemoryJavaCompiler ignoreWarnings() { * @throws Exception */ public Map> compileAll() throws Exception { + return compile().checkNoErrors().classMap(); + } + + /** + * Compile all sources added until now and return {@link CompilationResult}, + * providing access to the compiled classes and/or errors and warnings + */ + public CompilationResult compile() throws Exception { if (sourceCodes.size() == 0) { throw new CompilationException("No source code to compile"); } @@ -77,41 +95,84 @@ public Map> compileAll() throws Exception { code[i] = new CompiledCode(iter.next().getClassName()); } DiagnosticCollector collector = new DiagnosticCollector<>(); - ExtendedStandardJavaFileManager fileManager = new ExtendedStandardJavaFileManager(javac.getStandardFileManager(null, null, null), classLoader); - JavaCompiler.CompilationTask task = javac.getTask(null, fileManager, collector, options, null, compilationUnits); - boolean result = task.call(); - if (!result || collector.getDiagnostics().size() > 0) { - StringBuffer exceptionMsg = new StringBuffer(); - exceptionMsg.append("Unable to compile the source"); - boolean hasWarnings = false; - boolean hasErrors = false; + ExtendedStandardJavaFileManager fileManager = new ExtendedStandardJavaFileManager( + javac.getStandardFileManager(null, null, null), classLoader); + JavaCompiler.CompilationTask task = javac.getTask(null, fileManager, collector, options, null, + compilationUnits); + task.call(); + boolean hasWarnings; + boolean hasErrors; + + { + boolean hasWarningsTmp = false; + boolean hasErrorsTmp = false; for (Diagnostic d : collector.getDiagnostics()) { switch (d.getKind()) { case NOTE: case MANDATORY_WARNING: case WARNING: - hasWarnings = true; + hasWarningsTmp = true; break; case OTHER: case ERROR: default: - hasErrors = true; + hasErrorsTmp = true; break; } - exceptionMsg.append("\n").append("[kind=").append(d.getKind()); - exceptionMsg.append(", ").append("line=").append(d.getLineNumber()); - exceptionMsg.append(", ").append("message=").append(d.getMessage(Locale.US)).append("]"); - } - if (hasWarnings && !ignoreWarnings || hasErrors) { - throw new CompilationException(exceptionMsg.toString()); } + hasWarnings = hasWarningsTmp; + hasErrors = hasErrorsTmp; } - Map> classes = new HashMap>(); - for (String className : sourceCodes.keySet()) { - classes.put(className, classLoader.loadClass(className)); - } - return classes; + return new CompilationResult() { + + @Override + public Map> classMap() throws ClassNotFoundException { + Map> classes = new HashMap>(); + for (String className : sourceCodes.keySet()) { + classes.put(className, classLoader.loadClass(className)); + } + return classes; + } + + @Override + public boolean compilationSucceeded() { + if (hasWarnings && !ignoreWarnings) + return false; + return !hasErrors; + } + + @Override + public boolean hasWarnings() { + return hasWarnings; + } + + @Override + public boolean hasErrors() { + return hasErrors; + } + + @Override + public List> getDiagnostics() { + return collector.getDiagnostics(); + } + + @Override + public CompilationResult checkNoErrors() { + if (!compilationSucceeded()) { + StringBuffer exceptionMsg = new StringBuffer(); + exceptionMsg.append("Unable to compile the source"); + for (Diagnostic d : getDiagnostics()) { + exceptionMsg.append("\n").append("[kind=").append(d.getKind()); + exceptionMsg.append(", ").append("line=").append(d.getLineNumber()); + exceptionMsg.append(", ").append("message=").append(d.getMessage(Locale.US)).append("]"); + } + throw new CompilationException(exceptionMsg.toString()); + } + return this; + } + + }; } /**