Skip to content

Introduce a result interface to allow extraction of diagnostics #19

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions src/main/java/org/mdkt/compiler/CompilationResult.java
Original file line number Diff line number Diff line change
@@ -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<String, Class<?>> 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<Diagnostic<? extends JavaFileObject>> getDiagnostics();

/**
* Throw an exception if the compilation did not succeed
*/
CompilationResult checkNoErrors();

}
107 changes: 84 additions & 23 deletions src/main/java/org/mdkt/compiler/InMemoryJavaCompiler.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -65,6 +75,14 @@ public InMemoryJavaCompiler ignoreWarnings() {
* @throws Exception
*/
public Map<String, Class<?>> 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");
}
Expand All @@ -77,41 +95,84 @@ public Map<String, Class<?>> compileAll() throws Exception {
code[i] = new CompiledCode(iter.next().getClassName());
}
DiagnosticCollector<JavaFileObject> 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<? extends JavaFileObject> 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<String, Class<?>> classes = new HashMap<String, Class<?>>();
for (String className : sourceCodes.keySet()) {
classes.put(className, classLoader.loadClass(className));
}
return classes;
return new CompilationResult() {

@Override
public Map<String, Class<?>> classMap() throws ClassNotFoundException {
Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
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<Diagnostic<? extends JavaFileObject>> getDiagnostics() {
return collector.getDiagnostics();
}

@Override
public CompilationResult checkNoErrors() {
if (!compilationSucceeded()) {
StringBuffer exceptionMsg = new StringBuffer();
exceptionMsg.append("Unable to compile the source");
for (Diagnostic<? extends JavaFileObject> 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;
}

};
}

/**
Expand Down