All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pro.projo.generation.ProjoTemplateFactoryProcessor Maven / Gradle / Ivy

The newest version!
//                                                                          //
// Copyright 2018 - 2024 Mirko Raner                                        //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
//                                                                          //
package pro.projo.generation;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.Collection;
import java.util.Set;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.tools.FileObject;
import pro.projo.interfaces.annotation.Options;
import pro.projo.template.annotation.Configuration;
import pro.projo.template.annotation.Template;
import static java.io.File.separatorChar;
import static javax.lang.model.SourceVersion.RELEASE_8;
import static javax.tools.Diagnostic.Kind.NOTE;
import static javax.tools.StandardLocation.SOURCE_PATH;

/**
* The {@link ProjoTemplateFactoryProcessor} is an annotation processor that, at compile time, detects source files that
* have an {@link Template @Template} annotation and will use these sources for generating additional source files according
* to the template's {@link Template#input() input} {@link Configuration}.
*
* @author Mirko Raner
**/
@SupportedSourceVersion(RELEASE_8)
@SupportedAnnotationTypes("pro.projo.template.annotation.Template")
public class ProjoTemplateFactoryProcessor extends ProjoProcessor
{
    private Filer filer;
    private Elements elements;
    private Messager messager;

    @Override
    public Elements elements()
    {
        return elements;
    }

    @Override
    public synchronized void init(ProcessingEnvironment environment)
    {
        super.init(environment);
        filer = environment.getFiler();
        elements = environment.getElementUtils();
        messager = environment.getMessager();
    }

    @Override
    public boolean process(Set annotations, RoundEnvironment round)
    {
        ProjoTemplateFactoryGenerator generator = new ProjoTemplateFactoryGenerator();
        for (Element element: round.getElementsAnnotatedWith(Template.class))
        {
            Template template = element.getAnnotation(Template.class);
            messager.printMessage(NOTE, "@Template annotation found in " + element);
            FileObject templateFile = getTemplateFile(element);
            Collection configurations = getConfiguration(getTypeMirror(template::input));
            messager.printMessage(NOTE, "Generating " + configurations.size() + " additional sources...");
            for (Configuration configuration: configurations)
            {
                String className = configuration.fullyQualifiedClassName();
                TypeElement typeElement = elements.getTypeElement(className);
                try
                {
                    Options options = configuration.options();
                    String fileExtension = configuration.options().fileExtension();
                    FileObject sourceFile = fileExtension.equals(".java")?
                        filer.createSourceFile(className, typeElement):
                        filer.createResource
                        (
                            options.outputLocation(),
                            packageName(configuration),
                            fileName(configuration),
                            typeElement
                        );
                    try (PrintWriter writer = new PrintWriter(sourceFile.openWriter(), true))
                    {
                        try (Reader reader = templateFile.openReader(true))
                        {
                            generator.generate(reader, templateFile.getName(), configuration.parameters(), writer);
                        }
                    }
                    messager.printMessage(NOTE, "Generated " + className);
                }
                catch (IOException ioException)
                {
                    // Carry on for now; throwing an exception here would bring the compiler to a halt...
                    //
                    ioException.printStackTrace();
                }
            }
        }
        return true;
    }

    private String packageName(Configuration configuration)
    {
        String name = configuration.fullyQualifiedClassName();
        int index = name.lastIndexOf('.');
        return name.substring(0, index);
    }

    private String fileName(Configuration configuration)
    {
        String name = configuration.fullyQualifiedClassName();
        int index = name.lastIndexOf('.');
        return name.substring(index+1) + configuration.options().fileExtension();
    }

    private FileObject getTemplateFile(Element element)
    {
        String simpleName = element.getSimpleName().toString();
        String packageName = elements.getPackageOf(element).getQualifiedName().toString();
        String sourceName = packageName.replace('.', separatorChar) + separatorChar + simpleName + ".java";
        try
        {
            return filer.getResource(SOURCE_PATH, "", sourceName);
        }
        catch (@SuppressWarnings("unused") IOException ioException)
        {
            return null;
        }
    }

    private Collection getConfiguration(TypeMirror type)
    {
        try
        {
            return getClass(type).getDeclaredConstructor().newInstance();
        }
        catch (@SuppressWarnings("unused") Exception exception)
        {
            return null;
        }
    }

    private Class> getClass(TypeMirror type)
    {
        try
        {
            @SuppressWarnings("unchecked")
            Class> configurationClass = (Class>)Class.forName(type.toString());
            return configurationClass;
        }
        catch (@SuppressWarnings("unused") ClassNotFoundException classNotFound)
        {
            return null;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy