
com.github.sviperll.texttemplates.TemplateFormatProcessor Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2014, Victor Nazarov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.github.sviperll.texttemplates;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
/**
*
* @author Victor Nazarov
*/
@SupportedAnnotationTypes("com.github.sviperll.texttemplates.TemplateFormat")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class TemplateFormatProcessor extends AbstractProcessor {
private final List errors = new ArrayList();
@Override
public boolean process(Set extends TypeElement> processEnnotations,
RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) {
for (String error: errors) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, error);
}
} else {
for (Element element: roundEnv.getElementsAnnotatedWith(TemplateFormat.class)) {
TemplateFormat directive = element.getAnnotation(TemplateFormat.class);
processElement((TypeElement)element, directive);
}
}
return true;
}
private void processElement(TypeElement templateFormatElement, TemplateFormat directive) {
if (!templateFormatElement.getTypeParameters().isEmpty()) {
Object[] arguments = new Object[] {templateFormatElement.getQualifiedName(), TemplateFormat.class.getName()};
String message = MessageFormat.format("{0} class annotated with {1} annotation should not contain type variables", arguments);
errors.add(message);
}
ExecutableElement method = getCreateEscapingAppendableMethod(templateFormatElement, directive);
if (method == null) {
Object[] arguments = new Object[] {templateFormatElement.getQualifiedName(), TemplateFormat.class.getName(), directive.createEscapingAppendableMethodName()};
String message = MessageFormat.format("{0} class annotated with {1} annotation should contain {2} method:\n public static Appendable {2}(Appendable appendable)", arguments);
errors.add(message);
}
}
private ExecutableElement getCreateEscapingAppendableMethod(TypeElement templateFormatElement, TemplateFormat directive) {
List extends Element> elements = templateFormatElement.getEnclosedElements();
for (Element element: elements) {
if (element.getKind() == ElementKind.METHOD) {
ExecutableElement method = (ExecutableElement)element;
Set modifiers = method.getModifiers();
if (method.getSimpleName().contentEquals(directive.createEscapingAppendableMethodName())
&& modifiers.contains(Modifier.PUBLIC)
&& modifiers.contains(Modifier.STATIC)
&& isAppendableToAppendable(method)
&& !hasCheckedExceptions(method)) {
return method;
}
}
}
return null;
}
private boolean isAppendableToAppendable(ExecutableElement method) {
List extends VariableElement> parameters = method.getParameters();
if (parameters.size() != 1) {
return false;
} else {
TypeMirror returnType = method.getReturnType();
TypeMirror argumentType = parameters.iterator().next().asType();
TypeElement appendableElement = processingEnv.getElementUtils().getTypeElement(Appendable.class.getName());
TypeMirror appendableType = appendableElement.asType();
return processingEnv.getTypeUtils().isSubtype(returnType, appendableType)
&& processingEnv.getTypeUtils().isSubtype(appendableType, argumentType);
}
}
private boolean hasCheckedExceptions(ExecutableElement method) {
List extends TypeMirror> thrownTypes = method.getThrownTypes();
for (TypeMirror thrownType: thrownTypes) {
if (isCheckedException(thrownType)) {
return true;
}
}
return false;
}
private boolean isCheckedException(TypeMirror thrownType) {
TypeElement runtimeExceptionElement = processingEnv.getElementUtils().getTypeElement(RuntimeException.class.getName());
TypeMirror runtimeExceptionType = runtimeExceptionElement.asType();
TypeElement errorElement = processingEnv.getElementUtils().getTypeElement(Error.class.getName());
TypeMirror errorType = errorElement.asType();
return !processingEnv.getTypeUtils().isSubtype(thrownType, errorType)
&& !processingEnv.getTypeUtils().isSubtype(thrownType, runtimeExceptionType);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy