| /** |
| * 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; |
| } |
| } |