package xapi.javac.dev.model; import com.github.javaparser.JavaParser; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.body.TypeDeclaration; import com.sun.source.tree.CompilationUnitTree; import xapi.fu.Lazy; import xapi.fu.Out1; import xapi.fu.Pointer; import xapi.io.X_IO; import xapi.javac.dev.api.JavacService; import xapi.log.X_Log; import xapi.source.X_Source; import xapi.util.api.DebugRethrowable; import static xapi.fu.Lazy.deferSupplier; import static xapi.fu.Pointer.pointerDeferred; import javax.lang.model.element.TypeElement; import javax.tools.JavaFileObject; import java.io.IOException; /** * @author James X. Nelson (james@wetheinter.net) * Created on 4/9/16. */ public class JavaDocument implements DebugRethrowable { private final CompilationUnitTree compilationUnit; private final TypeElement type; private final JavacService service; private final Lazy<String> originalSource; private final Lazy<String> packageName; private final Lazy<String> enclosedName; private final Lazy<String> fileName; private final Pointer<CompilationUnit> currentSource; private final Pointer<TypeDeclaration> currentType; private final JavaDocument previousVersion; public JavaDocument( JavacService service, CompilationUnitTree compilationUnit, TypeElement type ) { this(null, service, compilationUnit, type); } public JavaDocument( JavaDocument previousVersion, JavacService service, CompilationUnitTree compilationUnit, TypeElement type ) { this.previousVersion = previousVersion; this.service = service; this.type = type; this.compilationUnit = compilationUnit; assert service != null : "null service"; assert compilationUnit != null : "null compilation unit"; assert type != null : "null type"; packageName = deferSupplier(service::getPackageName, compilationUnit); enclosedName = Lazy.deferred1(()->getTypeName().replace(packageName.out1()+".", "")); fileName = Lazy.deferred1(()->service.getFileName(compilationUnit)); originalSource = deferSupplier(this::toSource, compilationUnit); currentSource = pointerDeferred( originalSource.map(X_IO::toStreamUtf8) .mapUnsafe(JavaParser::parse) ); currentType = pointerDeferred(currentSource .map(unit-> unit.getTypes().stream() .filter(typeDecl -> { String name = typeDecl.getName(); return name.equals(type.getQualifiedName().toString()); }) .findFirst().get() )); } public String toSource(CompilationUnitTree unit) { final JavaFileObject source = unit.getSourceFile(); try { return X_IO.toStringUtf8(source.openInputStream()); } catch (IOException e) { throw rethrow(e); } } public boolean hasImport(String importName) { return compilationUnit.getImports().stream() .anyMatch(importTree->{ final String name = service.getQualifiedName(compilationUnit, importTree); return name.startsWith(importName); }); } /** * Called whenever a unit which exists is seen again. * * This will not be relevant until multi-phase compilation is complete. */ public void record(CompilationUnitTree cup, TypeElement typeElement) { } public String getCompilationUnitName() { return service.getQualifiedName(compilationUnit); } public void finish() { X_Log.info(getClass(), "Finished compilation of document ",getTypeName(), this); } public String getTypeName() { return type.getQualifiedName().toString(); } public String getEnclosedName() { return enclosedName.out1(); } public JavaFileObject getSourceFile() { return compilationUnit.getSourceFile(); } public String getPackageName() { return service.getPackageName(compilationUnit); } public String getFileName() { return fileName.out1(); } public String getSource() { return originalSource.out1(); } public CompilationUnit getAst() { return currentSource.out1(); } public CompilationUnitTree getCompilationUnit() { return compilationUnit; } /** * Called when a document that has had source rewritten has been finalized * (i.e., it's source was in the working directory, and it finished compilation * without any plugins requesting source rewrites, so now it will be placed in the final output directory). */ public void finalize(JavacService service) { // TODO add in listeners who want to be notified that this document has completed all source rewriting. } @Override public String toString() { X_Log.trace(getClass(), "JavaDocument: ", getTypeName(), "Source:\n\n", Out1.out1(this::getSource), "\n\nCompilation Unit:", Out1.out1(this::getCompilationUnit) ); return "JavaDocument [" + getTypeName() +"]"; } public String getAstName() { return X_Source.qualifiedName(getPackageName(), getEnclosedName().split("[.]")[0]); } }