/* * Copyright 2013 Blazebit. * * 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 com.blazebit.message.apt; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.tools.Diagnostic.Kind; import javax.tools.FileObject; import javax.tools.StandardLocation; /** * * @author Christian */ public abstract class AbstractInterfaceProcessor<M extends InterfaceMethodInfo, T extends InterfaceInfo<M>> extends AbstractProcessor { protected abstract Set<Class<? extends Annotation>> getAnnotationsToProcess(); protected abstract void processInterfaceInfo(T interfaceInfo) throws IOException; @Override public Set<String> getSupportedAnnotationTypes() { Set<String> supportedAnnotationTypes = new HashSet<String>(); for (Class<? extends Annotation> annotationClass : getAnnotationsToProcess()) { supportedAnnotationTypes.add(annotationClass.getName()); } return supportedAnnotationTypes; } protected void printMessage(Kind kind, String message, Element e, Throwable t) { StringWriter sw = new StringWriter(); sw.append(message); sw.append('\n'); t.printStackTrace(new PrintWriter(sw)); processingEnv.getMessager().printMessage(kind, sw.getBuffer(), e); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if (annotations.isEmpty()) { return false; } for (Class<? extends Annotation> annotationClass : getAnnotationsToProcess()) { for (Element e : roundEnv.getElementsAnnotatedWith(annotationClass)) { if (e instanceof TypeElement) { TypeElement typeElement = (TypeElement) e; T info = processElement(typeElement, annotationClass); if (info != null) { try { processInterfaceInfo(info); } catch (Exception ex) { printMessage(Kind.ERROR, "Could not process interface info for type '" + info.getElement().getQualifiedName() + "'!", info.getElement(), ex); } } } } } return false; } private T processElement(TypeElement e, Class<? extends Annotation> annotationClass) { String packageName = ((PackageElement) e.getEnclosingElement()).getQualifiedName().toString(); String qualifiedName = e.getQualifiedName().toString(); String simpleName = e.getSimpleName().toString(); List<M> methodInfos = new ArrayList<M>(); for (Element method : e.getEnclosedElements()) { if (method instanceof ExecutableElement) { M methodInfo = processMethod((ExecutableElement) method); if (methodInfo != null) { methodInfos.add(methodInfo); } } } File javaSourceFile = getJavaSourceFile(packageName, simpleName); long lastModified = javaSourceFile.lastModified(); return processElement(new DefaultInterfaceInfo<M>(e, qualifiedName, packageName, simpleName, javaSourceFile.getAbsolutePath(), lastModified, methodInfos), annotationClass); } protected T processElement(InterfaceInfo<M> interfaceInfo, Class<? extends Annotation> annotationClass) { return (T) interfaceInfo; } private M processMethod(ExecutableElement method) { String name = method.getSimpleName().toString(); String qualifiedReturnTypeName = method.getReturnType().toString(); List<? extends VariableElement> parameters = method.getParameters(); List<String> qualifiedParameterTypeNames = new ArrayList<String>(parameters.size()); for (VariableElement parameter : parameters) { qualifiedParameterTypeNames.add(parameter.asType().toString()); } return processMethod(new DefaultInterfaceMethodInfo(method, name, qualifiedReturnTypeName, qualifiedParameterTypeNames)); } protected M processMethod(InterfaceMethodInfo methodInfo) { return (M) methodInfo; } protected File getJavaSourceFile(String packageName, String className) { try { FileObject fileObject = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, packageName, className + ".java"); return new File(fileObject.toUri()); } catch(FileNotFoundException ex) { throw new IllegalArgumentException("Could not find the source file '" + className + ".java' that actually triggered the enum generation process", ex); } catch (IOException ex) { throw new IllegalArgumentException("Could not find the source file '" + className + ".java' that actually triggered the enum generation process", ex); } } }