blob: 71c9a6f5c4571b8aeb1dd90575c3716a7cfd1245 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.camel.tools.apt;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URI;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
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.type.TypeKind;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import static org.apache.camel.tools.apt.IOHelper.loadText;
import static org.apache.camel.tools.apt.Strings.canonicalClassName;
import static org.apache.camel.tools.apt.Strings.isNullOrEmpty;
/**
* Abstract class for Camel apt plugins.
*/
public abstract class AbstractAnnotationProcessor extends AbstractProcessor {
protected String findJavaDoc(Elements elementUtils, Element element, String fieldName, String name, TypeElement classElement, boolean builderPattern) {
String answer = null;
if (element != null) {
answer = elementUtils.getDocComment(element);
}
if (isNullOrEmpty(answer)) {
ExecutableElement setter = findSetter(fieldName, classElement);
if (setter != null) {
String doc = elementUtils.getDocComment(setter);
if (!isNullOrEmpty(doc)) {
answer = doc;
}
}
// lets find the getter
if (answer == null) {
ExecutableElement getter = findGetter(fieldName, classElement);
if (getter != null) {
String doc = elementUtils.getDocComment(getter);
if (!isNullOrEmpty(doc)) {
answer = doc;
}
}
}
// lets try builder pattern
if (answer == null && builderPattern) {
List<ExecutableElement> methods = ElementFilter.methodsIn(classElement.getEnclosedElements());
// lets try the builder pattern using annotation name (optional) as the method name
if (name != null) {
for (ExecutableElement method : methods) {
String methodName = method.getSimpleName().toString();
if (name.equals(methodName) && method.getParameters().size() == 1) {
String doc = elementUtils.getDocComment(method);
if (!isNullOrEmpty(doc)) {
answer = doc;
break;
}
}
}
// there may be builder pattern with no-parameter methods, such as more common for boolean types
// so lets try those as well
for (ExecutableElement method : methods) {
String methodName = method.getSimpleName().toString();
if (name.equals(methodName) && method.getParameters().size() == 0) {
String doc = elementUtils.getDocComment(method);
if (!isNullOrEmpty(doc)) {
answer = doc;
break;
}
}
}
}
// lets try builder pattern using fieldName as the method name
for (ExecutableElement method : methods) {
String methodName = method.getSimpleName().toString();
if (fieldName.equals(methodName) && method.getParameters().size() == 1) {
String doc = elementUtils.getDocComment(method);
if (!isNullOrEmpty(doc)) {
answer = doc;
break;
}
}
}
// there may be builder pattern with no-parameter methods, such as more common for boolean types
// so lets try those as well
for (ExecutableElement method : methods) {
String methodName = method.getSimpleName().toString();
if (fieldName.equals(methodName) && method.getParameters().size() == 0) {
String doc = elementUtils.getDocComment(method);
if (!isNullOrEmpty(doc)) {
answer = doc;
break;
}
}
}
}
}
return answer;
}
protected ExecutableElement findSetter(String fieldName, TypeElement classElement) {
String setter = "set" + fieldName.substring(0, 1).toUpperCase();
if (fieldName.length() > 1) {
setter += fieldName.substring(1);
}
// lets find the setter
List<ExecutableElement> methods = ElementFilter.methodsIn(classElement.getEnclosedElements());
for (ExecutableElement method : methods) {
String methodName = method.getSimpleName().toString();
if (setter.equals(methodName) && method.getParameters().size() == 1 && method.getReturnType().getKind().equals(TypeKind.VOID)) {
return method;
}
}
return null;
}
protected ExecutableElement findGetter(String fieldName, TypeElement classElement) {
String getter1 = "get" + fieldName.substring(0, 1).toUpperCase();
if (fieldName.length() > 1) {
getter1 += fieldName.substring(1);
}
String getter2 = "is" + fieldName.substring(0, 1).toUpperCase();
if (fieldName.length() > 1) {
getter2 += fieldName.substring(1);
}
// lets find the getter
List<ExecutableElement> methods = ElementFilter.methodsIn(classElement.getEnclosedElements());
for (ExecutableElement method : methods) {
String methodName = method.getSimpleName().toString();
if ((getter1.equals(methodName) || getter2.equals(methodName)) && method.getParameters().size() == 0) {
return method;
}
}
return null;
}
protected TypeElement findTypeElement(RoundEnvironment roundEnv, String className) {
if (isNullOrEmpty(className) || "java.lang.Object".equals(className)) {
return null;
}
Set<? extends Element> rootElements = roundEnv.getRootElements();
for (Element rootElement : rootElements) {
if (rootElement instanceof TypeElement) {
TypeElement typeElement = (TypeElement) rootElement;
String aRootName = canonicalClassName(typeElement.getQualifiedName().toString());
if (className.equals(aRootName)) {
return typeElement;
}
}
}
// fallback using package name
Elements elementUtils = processingEnv.getElementUtils();
int idx = className.lastIndexOf('.');
if (idx > 0) {
String packageName = className.substring(0, idx);
PackageElement pe = elementUtils.getPackageElement(packageName);
if (pe != null) {
List<? extends Element> enclosedElements = pe.getEnclosedElements();
for (Element rootElement : enclosedElements) {
if (rootElement instanceof TypeElement) {
TypeElement typeElement = (TypeElement) rootElement;
String aRootName = canonicalClassName(typeElement.getQualifiedName().toString());
if (className.equals(aRootName)) {
return typeElement;
}
}
}
}
}
return null;
}
protected void findTypeElementChildren(RoundEnvironment roundEnv, Set<TypeElement> found, String superClassName) {
Elements elementUtils = processingEnv.getElementUtils();
int idx = superClassName.lastIndexOf('.');
if (idx > 0) {
String packageName = superClassName.substring(0, idx);
PackageElement pe = elementUtils.getPackageElement(packageName);
if (pe != null) {
List<? extends Element> enclosedElements = pe.getEnclosedElements();
for (Element rootElement : enclosedElements) {
if (rootElement instanceof TypeElement) {
TypeElement typeElement = (TypeElement) rootElement;
String aSuperClassName = canonicalClassName(typeElement.getSuperclass().toString());
if (superClassName.equals(aSuperClassName)) {
found.add(typeElement);
}
}
}
}
}
}
protected boolean hasSuperClass(RoundEnvironment roundEnv, TypeElement classElement, String superClassName) {
String aRootName = canonicalClassName(classElement.getQualifiedName().toString());
if (isNullOrEmpty(aRootName) || "java.lang.Object".equals(aRootName)) {
return false;
}
String aSuperClassName = canonicalClassName(classElement.getSuperclass().toString());
if (superClassName.equals(aSuperClassName)) {
return true;
}
TypeElement aSuperClass = findTypeElement(roundEnv, aSuperClassName);
if (aSuperClass != null) {
return hasSuperClass(roundEnv, aSuperClass, superClassName);
} else {
return false;
}
}
/**
* Helper method to produce class output text file using the given handler
*/
protected void processFile(String packageName, String fileName, Func1<PrintWriter, Void> handler) {
PrintWriter writer = null;
try {
Writer out;
Filer filer = processingEnv.getFiler();
FileObject resource;
try {
resource = filer.getResource(StandardLocation.CLASS_OUTPUT, packageName, fileName);
} catch (Throwable e) {
resource = filer.createResource(StandardLocation.CLASS_OUTPUT, packageName, fileName);
}
URI uri = resource.toUri();
File file = null;
if (uri != null) {
try {
file = new File(uri.getPath());
} catch (Exception e) {
warning("Could not convert output directory resource URI to a file " + e);
}
}
if (file == null) {
warning("No class output directory could be found!");
} else {
file.getParentFile().mkdirs();
out = new FileWriter(file);
writer = new PrintWriter(out);
handler.call(writer);
}
} catch (IOException e) {
log(e);
} finally {
if (writer != null) {
writer.close();
}
}
}
protected void log(String message) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message);
}
protected void warning(String message) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, message);
}
protected void error(String message) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message);
}
protected void log(Throwable e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
StringWriter buffer = new StringWriter();
PrintWriter writer = new PrintWriter(buffer);
e.printStackTrace(writer);
writer.close();
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, buffer.toString());
}
protected String loadResource(String packageName, String fileName) {
Filer filer = processingEnv.getFiler();
FileObject resource;
try {
resource = filer.getResource(StandardLocation.CLASS_OUTPUT, "", packageName + "/" + fileName);
} catch (Throwable e) {
return "Crap" + e.getMessage();
}
if (resource == null) {
return null;
}
try {
InputStream is = resource.openInputStream();
return loadText(is, true);
} catch (Exception e) {
warning("Could not load file");
}
return null;
}
}