package fr.lteconsulting.hexa.databinding.annotation.processor; import fr.lteconsulting.hexa.databinding.annotation.processor.modules.ProcessorModule; import javax.annotation.processing.*; import javax.lang.model.element.TypeElement; import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import java.io.IOException; import java.io.Writer; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; import java.util.Set; import static fr.lteconsulting.hexa.databinding.annotation.processor.Tags.*; import static fr.lteconsulting.hexa.databinding.annotation.processor.Tags.TARGET_CLASS_NAME; public abstract class BaseAnnotationProcessor extends AbstractProcessor { public static class ProcInfo { TypeElement typeElement; Annotation annotation; String implName; String packageName; List<String> extraImports; public ProcInfo(TypeElement typeElement, Annotation annotation, String implName, String packageName) { this.typeElement = typeElement; this.annotation = annotation; this.implName = implName; this.packageName = packageName; extraImports = new ArrayList<>(); } public TypeElement getTypeElement() { return typeElement; } public Annotation getAnnotation() { return annotation; } public String getImplName() { return implName; } public String getPackageName() { return packageName; } public List<String> getExtraImports() { return extraImports; } public void addExtraImport(String newImport) { extraImports.add(newImport); } } protected Elements elementUtils; protected Types typeUtils; protected Filer filer; protected Types types; protected Messager msg; protected TypeSimplifier typeSimplifier; @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); elementUtils = processingEnv.getElementUtils(); typeUtils = processingEnv.getTypeUtils(); msg = processingEnv.getMessager(); filer = processingEnv.getFiler(); types = processingEnv.getTypeUtils(); typeSimplifier = new TypeSimplifier(types); } @Override @SuppressWarnings("unchecked") public boolean process(Set<? extends TypeElement> arg0, RoundEnvironment roundEnv) { if( !roundEnv.processingOver() ) { for(String supported : getSupportedAnnotationTypes()) { try { Class<? extends Annotation> annotationClazz = (Class<? extends Annotation>)Class.forName(supported); for (final TypeElement typeElement : ElementFilter.typesIn(roundEnv.getElementsAnnotatedWith(annotationClazz))) { Annotation annotation = typeElement.getAnnotation(annotationClazz); String packageName = elementUtils.getPackageOf(typeElement).getQualifiedName().toString(); String targetTypeName = getTargetTypeName(typeElement); try { JavaFileObject jfo = filer.createSourceFile(packageName + "." + targetTypeName); Writer writer = jfo.openWriter(); // Start processing doProcess(new ProcInfo(typeElement, annotation, targetTypeName, packageName), writer); writer.close(); } catch(IOException e) { e.printStackTrace(); error(e.getMessage()); } } } catch (ClassNotFoundException | ClassCastException ex) { ex.printStackTrace(); } } } return true; } protected abstract void doProcess(ProcInfo procInfo, Writer writer) throws IOException; protected String getTargetTypeName(TypeElement typeElement) { return typeElement.getSimpleName().toString().replace(".", "_") + "Impl"; } protected final void parseGeneralTags(Template template, ProcInfo procInfo) { String sourceName = procInfo.typeElement.getSimpleName().toString(); template.replace(PACKAGE_NAME, procInfo.packageName); template.replace(SOURCE_CLASS_FQN, procInfo.typeElement.getQualifiedName().toString()); template.replace(SOURCE_CLASS_NAME, sourceName + TypeSimplifier.actualTypeParametersString(procInfo.typeElement)); template.replace(TARGET_CLASS_PARAMETRIZED, procInfo.implName + typeSimplifier.formalTypeParametersString(procInfo.typeElement)); template.replace(TARGET_CLASS_NAME, procInfo.implName); } protected void registerProcessorModule(ProcessorModule module) { ProcessorModuleRegistry.register(module); } protected List<ProcessorModule> getProcessorModules() { return ProcessorModuleRegistry.getProcessorModules(); } protected void error( String msg ) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg); } }