summaryrefslogtreecommitdiff
path: root/src/main/java/com/fivetran/javac/JavacTaskBuilder.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/fivetran/javac/JavacTaskBuilder.java')
-rw-r--r--src/main/java/com/fivetran/javac/JavacTaskBuilder.java225
1 files changed, 225 insertions, 0 deletions
diff --git a/src/main/java/com/fivetran/javac/JavacTaskBuilder.java b/src/main/java/com/fivetran/javac/JavacTaskBuilder.java
new file mode 100644
index 0000000..3637210
--- /dev/null
+++ b/src/main/java/com/fivetran/javac/JavacTaskBuilder.java
@@ -0,0 +1,225 @@
+package com.fivetran.javac;
+
+import com.google.common.base.Joiner;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TaskEvent;
+import com.sun.source.util.TaskListener;
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.comp.CompileStates;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.main.JavaCompiler;
+import com.sun.tools.javac.parser.FuzzyParserFactory;
+import com.sun.tools.javac.util.Context;
+
+import javax.tools.DiagnosticCollector;
+import javax.tools.JavaFileObject;
+import javax.tools.ToolProvider;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+public class JavacTaskBuilder {
+ private static final Logger LOG = Logger.getLogger("");
+
+ public static final JavacTool SYSTEM_JAVA_COMPILER = (JavacTool) ToolProvider.getSystemJavaCompiler();
+ public static final JavacFileManager STANDARD_FILE_MANAGER = SYSTEM_JAVA_COMPILER.getStandardFileManager(null, null, null);
+
+ private final Context context = new Context();
+ private boolean fuzzyParser = false;
+ /** Files we're going to compile */
+ private final List<JavaFileObject> files = new ArrayList<>();
+ /** Error collector. Can only be set once. */
+ private DiagnosticCollector<JavaFileObject> errors;
+ /** Tasks that get run after the parsing phase of compilation */
+ private List<BridgeExpressionScanner> afterParse = new ArrayList<>();
+ /** Tasks that get run after the enter phase of compilation */
+ private List<BridgeExpressionScanner> afterEnter = new ArrayList<>();
+ /** Tasks that get run after the analysis phase of compilation */
+ private List<BridgeExpressionScanner> afterAnalyze = new ArrayList<>();
+ /** Command line options */
+ private List<String> options = new ArrayList<>();
+ /** When to stop if error */
+ private CompileStates.CompileState shouldStopPolicyIfError = CompileStates.CompileState.ENTER;
+ /** When to stop if no error */
+ private CompileStates.CompileState shouldStopPolicyIfNoError = CompileStates.CompileState.GENERATE;
+
+ private JavacTaskBuilder() {
+ }
+
+ /**
+ * Build a JavacTask using the system java compiler and the standard file manager
+ */
+ public static JavacTaskBuilder create() {
+ return new JavacTaskBuilder();
+ }
+
+ public JavacTaskBuilder fuzzyParser() {
+ fuzzyParser = true;
+
+ return this;
+ }
+
+ /**
+ * Add a file to the compilation todo list
+ */
+ public JavacTaskBuilder addFile(JavaFileObject file) {
+ files.add(file);
+
+ return this;
+ }
+
+ /**
+ * Report errors from all phases of compilation to collector
+ */
+ public JavacTaskBuilder reportErrors(DiagnosticCollector<JavaFileObject> collector) {
+ if (errors != null)
+ throw new IllegalStateException();
+ else {
+ errors = collector;
+
+ return this;
+ }
+ }
+
+ /**
+ * After parsing, scan the abstract syntax tree with visitor.
+ * The javac parser has error recovery, so this will still work even if there are syntax errors.
+ */
+ public JavacTaskBuilder afterParse(BridgeExpressionScanner visitor) {
+ afterParse.add(visitor);
+
+ return this;
+ }
+
+ /**
+ * After entering the tree, scan the abstract syntax tree with visitor.
+ * If syntax errors are present, visitor will never get run.
+ */
+ public JavacTaskBuilder afterEnter(BridgeExpressionScanner visitor) {
+ afterEnter.add(visitor);
+
+ return this;
+ }
+
+ /**
+ * After analysis, scan the abstract syntax tree with visitor.
+ * If syntax errors are present, visitor will never get run.
+ */
+ public JavacTaskBuilder afterAnalyze(BridgeExpressionScanner visitor) {
+ afterAnalyze.add(visitor);
+
+ return this;
+ }
+
+ public JavacTaskBuilder classPath(List<String> classPath) {
+ LOG.info("classpath: " + classPath);
+
+ options.add("-classpath");
+ options.add(Joiner.on(':').join(classPath));
+
+ return this;
+ }
+
+ public JavacTaskBuilder sourcePath(List<String> sourcePath) {
+ LOG.info("sourcepath: " + sourcePath);
+
+ options.add("-sourcepath");
+ options.add(Joiner.on(':').join(sourcePath));
+
+ return this;
+ }
+
+ public JavacTaskBuilder outputDirectory(String outputDirectory) {
+ LOG.info("outputDirectory: " + outputDirectory);
+
+ try {
+ Files.createDirectories(Paths.get(outputDirectory));
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+
+ options.add("-d");
+ options.add(outputDirectory);
+
+ return this;
+ }
+
+ public JavacTaskBuilder stopIfError(CompileStates.CompileState state) {
+ shouldStopPolicyIfError = state;
+
+ return this;
+ }
+
+ public JavacTaskBuilder stopIfNoError(CompileStates.CompileState state) {
+ shouldStopPolicyIfNoError = state;
+
+ return this;
+ }
+
+ public JavacTask build() {
+ JavacTask task = SYSTEM_JAVA_COMPILER.getTask(null,
+ STANDARD_FILE_MANAGER,
+ errors,
+ options,
+ null,
+ files,
+ context);
+
+ if (fuzzyParser)
+ FuzzyParserFactory.instance(context);
+
+ JavaCompiler.instance(context).shouldStopPolicyIfError = shouldStopPolicyIfError;
+ JavaCompiler.instance(context).shouldStopPolicyIfNoError = shouldStopPolicyIfNoError;
+
+ task.addTaskListener(new TaskListener() {
+ @Override
+ public void started(TaskEvent e) {
+ LOG.info("started " + e);
+ }
+
+ @Override
+ public void finished(TaskEvent e) {
+ LOG.info("finished " + e);
+
+ switch (e.getKind()) {
+ case PARSE:
+ for (BridgeExpressionScanner visitor : afterParse) {
+ visitor.task = task;
+
+ e.getCompilationUnit().accept(visitor, null);
+ }
+
+ break;
+ case ENTER:
+ for (BridgeExpressionScanner visitor : afterEnter) {
+ visitor.task = task;
+
+ e.getCompilationUnit().accept(visitor, null);
+ }
+
+ break;
+ case ANALYZE:
+ for (BridgeExpressionScanner visitor : afterAnalyze) {
+ visitor.task = task;
+
+ e.getCompilationUnit().accept(visitor, null);
+ }
+
+ break;
+ case GENERATE:
+ break;
+ case ANNOTATION_PROCESSING:
+ break;
+ case ANNOTATION_PROCESSING_ROUND:
+ break;
+ }
+ }
+ });
+
+ return task;
+ }
+}