package com.sora.util.akatsuki;
import static com.google.common.base.Charsets.UTF_8;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import javax.annotation.processing.Processor;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.sora.util.akatsuki.InMemoryJavaFileManager.InMemoryJavaFileObject;
public class CompilerUtils {
static Result compile(ClassLoader loader, Iterable<Processor> processors,
Iterable<String> options, JavaFileObject... objects) {
// we need all this because we got a annotation processor, the generated
// class has to go into memory too
final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<>();
InMemoryJavaFileManager fileManager = new InMemoryJavaFileManager(
compiler.getStandardFileManager(diagnosticCollector, Locale.getDefault(), UTF_8),
loader);
CompilationTask task = compiler.getTask(null, fileManager, diagnosticCollector, options,
null, Arrays.asList(objects));
task.setProcessors(processors);
Exception exception = null;
try {
if (!task.call())
throw new RuntimeException("File compiled with error, the cause is unknown");
} catch (Exception e) {
exception = e;
}
System.out.println(printVertically(diagnosticCollector.getDiagnostics()));
return new Result(fileManager.getClassLoader(StandardLocation.CLASS_OUTPUT),
fileManager.getOutputFiles(),
exception == null ? null
: new RuntimeException(
"Compilation failed:\n"
+ printVertically(diagnosticCollector.getDiagnostics()),
exception));
}
static String printVertically(List<?> collection) {
return Joiner.on("\n\t>").join(new ArrayList<>(collection));
}
static String printAllSources(List<JavaFileObject> sources, String linePrefix) {
final List<InMemoryJavaFileObject> sourceFiles = sources.stream()
.filter(f -> f instanceof InMemoryJavaFileObject)
.map(f -> (InMemoryJavaFileObject) f).filter(InMemoryJavaFileObject::isSource)
.collect(Collectors.toList());
final StringWriter writer = new StringWriter();
writer.append("\n").append(linePrefix).append("Overview:");
for (JavaFileObject fileObject : sources) {
writer.append("\n").append(linePrefix).append("\t")
.append(fileObject.toUri().toString());
}
writer.append("\n").append(linePrefix).append("Generated source(s):\n");
for (InMemoryJavaFileObject file : sourceFiles) {
writer.append(linePrefix).append("File: ").append(file.toUri().toString()).append("\n");
try {
file.printSource(writer, linePrefix+"\t");
} catch (IOException e) {
// what else can we do?
writer.append(linePrefix)
.append("An exception occurred while trying to print the " + "source:\n");
e.printStackTrace(new PrintWriter(writer));
}
writer.append("\n").append(linePrefix).append("===============================\n");
}
return writer.toString();
}
static class Result {
public final ClassLoader classLoader;
public final ImmutableList<JavaFileObject> sources;
public final Exception compilationException;
public Result(ClassLoader classLoader, ImmutableList<JavaFileObject> sources,
Exception compilationException) {
this.classLoader = classLoader;
this.sources = sources;
this.compilationException = compilationException;
}
public String printGeneratedSources(String linePrefix) {
return CompilerUtils.printAllSources(sources, linePrefix);
}
}
}