package xapi.javac.dev.api;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.util.JavacTask;
import com.sun.source.util.TaskListener;
import xapi.fu.In1;
import xapi.fu.Out2;
import xapi.inject.X_Inject;
import xapi.javac.dev.model.CompilerSettings;
import xapi.javac.dev.model.CompilerSettings.ImplicitMode;
import xapi.javac.dev.model.CompilerSettings.ProcessorMode;
import xapi.javac.dev.model.JavaDocument;
import xapi.reflect.X_Reflect;
import xapi.util.X_String;
import javax.lang.model.element.TypeElement;
import java.net.URL;
/**
* @author James X. Nelson (james@wetheinter.net)
* Created on 4/3/16.
*/
public interface CompilerService {
default CompilerSettings defaultSettings() {
return new CompilerSettings();
}
Out2<Integer, URL> compileFiles(CompilerSettings settings, String ... files);
default Out2<Integer, URL> compileClasses(CompilerSettings settings, Class ... classes) {
return compileFiles(settings, X_String.classesToSourceFiles(classes));
}
static CompilerService compileServiceFrom(JavacService service) {
return service.getOrCreate(CompilerService.class, cls->{
final CompilerService result = X_Inject.singleton(CompilerService.class);
result.init(service);
return result;
});
}
void init(JavacService service);
void record(CompilationUnitTree cup, TypeElement typeElement);
void peekOnCompiledUnits(In1<JavaDocument> callback);
void onCompilationUnitFinished(String name, In1<CompilationUnitTree> callback);
void onFinished(Runnable r);
TaskListener getTaskListener(JavacTask task);
void overwriteCompilationUnit(JavaDocument doc, String newSource);
/**
* When a magic method emits code that contains more magic methods,
* we must recompile the source potentially many times,
* so we create iterations of the file in a tmp package,
* which you can easily exclude from final output in your build tool
* (a cleanup mechanism is forthcoming)
*/
default String workingPackage() {
return "tmp";
}
/**
* The final output of generated code will be made a subpackage of the original source.
* This allows both original source and generated source to coexist nicely.
*
* A final dist build will do a massive whole-world compile
* where final permutations of generated types can be promoted to the live source,
* which will have all references updated to use dist.*.com.original.pkg.name.
*
* Although it may seem nice to promote the generated types on top of the original location,
* you will encounter trouble as soon as you want to touch classes in java.* packages,
* as ClassLoader class will refuse to load them unless they come from signed java jars.
*
* The counter to the java.* package name issue is that native methods must match signatures,
* so classes with native methods [*1] cannot be repackaged
* (thus, you cannot overwrite a java.* class with native methods, and expect it to work).
*
* [*1]: GWT native methods are fine to repackage, provided jsni references are updated correctly.
*
* Given all the issues either way, a mechanism will eventually be implemented to configure these options,
* with the current default to prefer adding the extra package names
*/
default String outputPackage() {
return "dist";
}
boolean isGreedyCompiler();
JavaDocument getDocument(CompilationUnitTree cup);
default PendingCompile startCompile(Class<?> cls) {
return new PendingCompile(cls, this);
}
default CompilerSettings settingsForClass(Class<?> cls) {
String loc = X_Reflect.getFileLoc(cls);
boolean test = loc.contains("test-classes");
final CompilerSettings settings = defaultSettings()
.setTest(test)
.setClearGenerateDirectory(false)
.resetGenerateDirectory()
.setImplicitMode(ImplicitMode.CLASS)
.setProcessorMode(ProcessorMode.Both);
if (test) {
settings.setOutputDirectory(loc);
loc = loc.replace("target/test-classes", "target/generated-test-sources/test-annotations");
settings.setGenerateDirectory(loc);
loc = loc.replace("target/generated-test-sources/test-annotations", "src/test/java");
settings.setSourceDirectory(loc);
} else {
settings.setOutputDirectory(loc);
loc = loc.replace("target/classes", "target/generated-sources/annotations");
settings.setGenerateDirectory(loc);
loc = loc.replace("target/generated-sources/annotations", "src/main/java");
settings.setSourceDirectory(loc);
}
return settings;
}
}