You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2016/08/11 08:07:07 UTC

[1/4] camel git commit: CAMEL-9482: Adjust the apt to make camel-core compile again, seems like we need to merge the core/spring into a single apt as the compiler cannot do both on camel-core for some odd reason.

Repository: camel
Updated Branches:
  refs/heads/master bbb7ff941 -> 8a18e2849


http://git-wip-us.apache.org/repos/asf/camel/blob/8a18e284/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpringAnnotationProcessor.java
----------------------------------------------------------------------
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpringAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpringAnnotationProcessor.java
new file mode 100644
index 0000000..064872f
--- /dev/null
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpringAnnotationProcessor.java
@@ -0,0 +1,689 @@
+/**
+ * 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.PrintWriter;
+import java.util.Comparator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.annotation.processing.ProcessingEnvironment;
+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.ElementKind;
+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.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.tools.apt.helper.JsonSchemaHelper;
+import org.apache.camel.tools.apt.helper.Strings;
+
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findJavaDoc;
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findTypeElement;
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.processFile;
+import static org.apache.camel.tools.apt.helper.JsonSchemaHelper.sanitizeDescription;
+import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
+import static org.apache.camel.tools.apt.helper.Strings.isNullOrEmpty;
+import static org.apache.camel.tools.apt.helper.Strings.safeNull;
+
+/**
+ * Process camel-spring's <camelContext> and generate json schema documentation
+ */
+@SupportedAnnotationTypes({"javax.xml.bind.annotation.*", "org.apache.camel.spi.Label"})
+@SupportedSourceVersion(SourceVersion.RELEASE_8)
+public class SpringAnnotationProcessor {
+
+    protected void processModelClass(final ProcessingEnvironment processingEnv, final RoundEnvironment roundEnv, final TypeElement classElement) {
+        final String javaTypeName = canonicalClassName(classElement.getQualifiedName().toString());
+        String packageName = javaTypeName.substring(0, javaTypeName.lastIndexOf("."));
+
+        // skip abstract classes
+        if (classElement.getModifiers().contains(Modifier.ABSTRACT)) {
+            return;
+        }
+
+        final XmlRootElement rootElement = classElement.getAnnotation(XmlRootElement.class);
+        if (rootElement == null) {
+            return;
+        }
+
+        String aName = rootElement.name();
+        if (isNullOrEmpty(aName) || "##default".equals(aName)) {
+            XmlType typeElement = classElement.getAnnotation(XmlType.class);
+            aName = typeElement.name();
+        }
+        final String name = aName;
+
+        // lets use the xsd name as the file name
+        String fileName;
+        if (isNullOrEmpty(name) || "##default".equals(name)) {
+            fileName = classElement.getSimpleName().toString() + ".json";
+        } else {
+            fileName = name + ".json";
+        }
+
+        // write json schema
+        Func1<PrintWriter, Void> handler = new Func1<PrintWriter, Void>() {
+            @Override
+            public Void call(PrintWriter writer) {
+                writeJSonSchemeDocumentation(processingEnv, writer, roundEnv, classElement, rootElement, javaTypeName, name);
+                return null;
+            }
+        };
+        processFile(processingEnv, packageName, fileName, handler);
+    }
+
+    protected void writeJSonSchemeDocumentation(ProcessingEnvironment processingEnv, PrintWriter writer, RoundEnvironment roundEnv,
+                                                TypeElement classElement, XmlRootElement rootElement,
+                                                String javaTypeName, String modelName) {
+        // gather eip information
+        EipModel eipModel = findEipModelProperties(processingEnv, roundEnv, classElement, javaTypeName, modelName);
+
+        // collect eip information
+        Set<EipOption> eipOptions = new TreeSet<EipOption>(new EipOptionComparator(eipModel));
+        findClassProperties(processingEnv, writer, roundEnv, eipOptions, classElement, classElement, "", modelName);
+
+        String json = createParameterJsonSchema(eipModel, eipOptions);
+        writer.println(json);
+    }
+
+    public String createParameterJsonSchema(EipModel eipModel, Set<EipOption> options) {
+        StringBuilder buffer = new StringBuilder("{");
+        // eip model
+        buffer.append("\n \"model\": {");
+        buffer.append("\n    \"kind\": \"").append("model").append("\",");
+        buffer.append("\n    \"name\": \"").append(eipModel.getName()).append("\",");
+        if (eipModel.getTitle() != null) {
+            buffer.append("\n    \"title\": \"").append(eipModel.getTitle()).append("\",");
+        } else {
+            // fallback and use name as title
+            buffer.append("\n    \"title\": \"").append(asTitle(eipModel.getName())).append("\",");
+        }
+        buffer.append("\n    \"description\": \"").append(safeNull(eipModel.getDescription())).append("\",");
+        buffer.append("\n    \"javaType\": \"").append(eipModel.getJavaType()).append("\",");
+        buffer.append("\n    \"label\": \"").append(safeNull(eipModel.getLabel())).append("\"");
+        buffer.append("\n  },");
+
+        buffer.append("\n  \"properties\": {");
+        boolean first = true;
+        for (EipOption entry : options) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(",");
+            }
+            buffer.append("\n    ");
+            // as its json we need to sanitize the docs
+            String doc = entry.getDocumentation();
+            doc = sanitizeDescription(doc, false);
+            buffer.append(JsonSchemaHelper.toJson(entry.getName(), entry.getKind(), entry.isRequired(), entry.getType(), entry.getDefaultValue(), doc,
+                    entry.isDeprecated(), false, null, null, entry.isEnumType(), entry.getEnums(), entry.isOneOf(), entry.getOneOfTypes(), null, null, false));
+        }
+        buffer.append("\n  }");
+
+        buffer.append("\n}\n");
+        return buffer.toString();
+    }
+
+    protected EipModel findEipModelProperties(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement classElement, String javaTypeName, String name) {
+        EipModel model = new EipModel();
+        model.setJavaType(javaTypeName);
+        model.setName(name);
+
+        Metadata metadata = classElement.getAnnotation(Metadata.class);
+        if (metadata != null) {
+            if (!Strings.isNullOrEmpty(metadata.label())) {
+                model.setLabel(metadata.label());
+            }
+            if (!Strings.isNullOrEmpty(metadata.title())) {
+                model.setTitle(metadata.title());
+            }
+        }
+
+        // favor to use class javadoc of component as description
+        if (model.getJavaType() != null) {
+            Elements elementUtils = processingEnv.getElementUtils();
+            TypeElement typeElement = findTypeElement(processingEnv, roundEnv, model.getJavaType());
+            if (typeElement != null) {
+                String doc = elementUtils.getDocComment(typeElement);
+                if (doc != null) {
+                    // need to sanitize the description first (we only want a summary)
+                    doc = sanitizeDescription(doc, true);
+                    // the javadoc may actually be empty, so only change the doc if we got something
+                    if (!Strings.isNullOrEmpty(doc)) {
+                        model.setDescription(doc);
+                    }
+                }
+            }
+        }
+
+        return model;
+    }
+
+    protected void findClassProperties(ProcessingEnvironment processingEnv, PrintWriter writer, RoundEnvironment roundEnv, Set<EipOption> eipOptions,
+                                       TypeElement originalClassType, TypeElement classElement, String prefix, String modelName) {
+        while (true) {
+            List<VariableElement> fieldElements = ElementFilter.fieldsIn(classElement.getEnclosedElements());
+            for (VariableElement fieldElement : fieldElements) {
+
+                String fieldName = fieldElement.getSimpleName().toString();
+
+                XmlAttribute attribute = fieldElement.getAnnotation(XmlAttribute.class);
+                if (attribute != null) {
+                    boolean skip = processAttribute(processingEnv, roundEnv, originalClassType, classElement, fieldElement, fieldName, attribute, eipOptions, prefix, modelName);
+                    if (skip) {
+                        continue;
+                    }
+                }
+
+                XmlElements elements = fieldElement.getAnnotation(XmlElements.class);
+                if (elements != null) {
+                    processElements(processingEnv, roundEnv, classElement, elements, fieldElement, eipOptions, prefix);
+                }
+
+                XmlElementRef elementRef = fieldElement.getAnnotation(XmlElementRef.class);
+                if (elementRef != null) {
+                    processElement(processingEnv, roundEnv, classElement, null, elementRef, fieldElement, eipOptions, prefix);
+                }
+
+                XmlElement element = fieldElement.getAnnotation(XmlElement.class);
+                if (element != null) {
+                    if ("rests".equals(fieldName)) {
+                        processRests(roundEnv, classElement, element, fieldElement, fieldName, eipOptions, prefix);
+                    } else if ("routes".equals(fieldName)) {
+                        processRoutes(roundEnv, classElement, element, fieldElement, fieldName, eipOptions, prefix);
+                    } else {
+                        processElement(processingEnv, roundEnv, classElement, element, null, fieldElement, eipOptions, prefix);
+                    }
+                }
+            }
+
+            // check super classes which may also have fields
+            TypeElement baseTypeElement = null;
+            TypeMirror superclass = classElement.getSuperclass();
+            if (superclass != null) {
+                String superClassName = canonicalClassName(superclass.toString());
+                baseTypeElement = findTypeElement(processingEnv, roundEnv, superClassName);
+            }
+            if (baseTypeElement != null) {
+                classElement = baseTypeElement;
+            } else {
+                break;
+            }
+        }
+    }
+
+    private boolean processAttribute(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement originalClassType,
+                                     TypeElement classElement, VariableElement fieldElement,
+                                     String fieldName, XmlAttribute attribute, Set<EipOption> eipOptions, String prefix, String modelName) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        String name = attribute.name();
+        if (isNullOrEmpty(name) || "##default".equals(name)) {
+            name = fieldName;
+        }
+
+        name = prefix + name;
+        TypeMirror fieldType = fieldElement.asType();
+        String fieldTypeName = fieldType.toString();
+        TypeElement fieldTypeElement = findTypeElement(processingEnv, roundEnv, fieldTypeName);
+
+        String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
+        String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true);
+        if (isNullOrEmpty(docComment)) {
+            Metadata metadata = fieldElement.getAnnotation(Metadata.class);
+            docComment = metadata != null ? metadata.description() : null;
+        }
+        boolean required = attribute.required();
+        // metadata may overrule element required
+        required = findRequired(fieldElement, required);
+
+        // gather enums
+        Set<String> enums = new TreeSet<String>();
+        boolean isEnum = fieldTypeElement != null && fieldTypeElement.getKind() == ElementKind.ENUM;
+        if (isEnum) {
+            TypeElement enumClass = findTypeElement(processingEnv, roundEnv, fieldTypeElement.asType().toString());
+            // find all the enum constants which has the possible enum value that can be used
+            List<VariableElement> fields = ElementFilter.fieldsIn(enumClass.getEnclosedElements());
+            for (VariableElement var : fields) {
+                if (var.getKind() == ElementKind.ENUM_CONSTANT) {
+                    String val = var.toString();
+                    enums.add(val);
+                }
+            }
+        }
+
+        boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null;
+
+        // special for id as its inherited from camel-core
+        if ("id".equals(name) && isNullOrEmpty(docComment)) {
+            if ("CamelContextFactoryBean".equals(originalClassType.getSimpleName().toString())) {
+                docComment = "Sets the id (name) of this CamelContext";
+            } else {
+                docComment = "Sets the id of this node";
+            }
+        }
+
+        EipOption ep = new EipOption(name, "attribute", fieldTypeName, required, defaultValue, docComment, deprecated, isEnum, enums, false, null);
+        eipOptions.add(ep);
+
+        return false;
+    }
+
+    /**
+     * Special for processing an @XmlElement routes field
+     */
+    private void processRoutes(RoundEnvironment roundEnv, TypeElement originalClassType, XmlElement element,
+                               VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) {
+
+        TypeMirror fieldType = fieldElement.asType();
+        String fieldTypeName = fieldType.toString();
+
+        Set<String> oneOfTypes = new TreeSet<String>();
+        oneOfTypes.add("route");
+
+        EipOption ep = new EipOption("route", "element", fieldTypeName, false, "", "Contains the Camel routes", false, false, null, true, oneOfTypes);
+        eipOptions.add(ep);
+    }
+
+    /**
+     * Special for processing an @XmlElement rests field
+     */
+    private void processRests(RoundEnvironment roundEnv, TypeElement originalClassType, XmlElement element,
+                              VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) {
+
+        TypeMirror fieldType = fieldElement.asType();
+        String fieldTypeName = fieldType.toString();
+
+        Set<String> oneOfTypes = new TreeSet<String>();
+        oneOfTypes.add("rest");
+
+        EipOption ep = new EipOption("rest", "element", fieldTypeName, false, "", "Contains the rest services defined using the rest-dsl", false, false, null, true, oneOfTypes);
+        eipOptions.add(ep);
+    }
+
+    private void processElement(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv,
+                                TypeElement classElement, XmlElement element, XmlElementRef elementRef, VariableElement fieldElement,
+                                Set<EipOption> eipOptions, String prefix) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        String fieldName;
+        fieldName = fieldElement.getSimpleName().toString();
+        if (element != null || elementRef != null) {
+
+            String kind = "element";
+            String name = element != null ? element.name() : elementRef.name();
+            if (isNullOrEmpty(name) || "##default".equals(name)) {
+                name = fieldName;
+            }
+            name = prefix + name;
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+            TypeElement fieldTypeElement = findTypeElement(processingEnv, roundEnv, fieldTypeName);
+
+            String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
+            String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true);
+            if (isNullOrEmpty(docComment)) {
+                Metadata metadata = fieldElement.getAnnotation(Metadata.class);
+                docComment = metadata != null ? metadata.description() : null;
+            }
+            boolean required = element != null ? element.required() : elementRef.required();
+            // metadata may overrule element required
+            required = findRequired(fieldElement, required);
+
+            // gather enums
+            Set<String> enums = new LinkedHashSet<String>();
+            boolean isEnum = fieldTypeElement != null && fieldTypeElement.getKind() == ElementKind.ENUM;
+            if (isEnum) {
+                TypeElement enumClass = findTypeElement(processingEnv, roundEnv, fieldTypeElement.asType().toString());
+                // find all the enum constants which has the possible enum value that can be used
+                List<VariableElement> fields = ElementFilter.fieldsIn(enumClass.getEnclosedElements());
+                for (VariableElement var : fields) {
+                    if (var.getKind() == ElementKind.ENUM_CONSTANT) {
+                        String val = var.toString();
+                        enums.add(val);
+                    }
+                }
+            }
+
+            // is it a definition/factory-bean type then its a oneOf
+            TreeSet oneOfTypes = new TreeSet<String>();
+            if (fieldTypeName.endsWith("Definition") || fieldTypeName.endsWith("FactoryBean")) {
+                TypeElement definitionClass = findTypeElement(processingEnv, roundEnv, fieldTypeElement.asType().toString());
+                if (definitionClass != null) {
+                    XmlRootElement rootElement = definitionClass.getAnnotation(XmlRootElement.class);
+                    if (rootElement != null) {
+                        String childName = rootElement.name();
+                        if (childName != null) {
+                            oneOfTypes.add(childName);
+                        }
+                    }
+                }
+            } else if (fieldTypeName.endsWith("Definition>") || fieldTypeName.endsWith("FactoryBean>")) {
+                // its a list so we need to load the generic type
+                String typeName = Strings.between(fieldTypeName, "<", ">");
+                TypeElement definitionClass = findTypeElement(processingEnv, roundEnv, typeName);
+                if (definitionClass != null) {
+                    XmlRootElement rootElement = definitionClass.getAnnotation(XmlRootElement.class);
+                    if (rootElement != null) {
+                        String childName = rootElement.name();
+                        if (childName != null) {
+                            oneOfTypes.add(childName);
+                        }
+                    }
+                }
+            }
+            boolean oneOf = !oneOfTypes.isEmpty();
+
+            boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null;
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, required, defaultValue, docComment, deprecated, isEnum, enums, oneOf, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    private void processElements(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv,
+                                 TypeElement classElement, XmlElements elements, VariableElement fieldElement,
+                                 Set<EipOption> eipOptions, String prefix) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        String fieldName;
+        fieldName = fieldElement.getSimpleName().toString();
+        if (elements != null) {
+            String kind = "element";
+            String name = fieldName;
+            name = prefix + name;
+
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+
+            String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
+            String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true);
+            if (isNullOrEmpty(docComment)) {
+                Metadata metadata = fieldElement.getAnnotation(Metadata.class);
+                docComment = metadata != null ? metadata.description() : null;
+            }
+            boolean required = false;
+            required = findRequired(fieldElement, required);
+
+            // gather oneOf of the elements
+            Set<String> oneOfTypes = new TreeSet<String>();
+            for (XmlElement element : elements.value()) {
+                String child = element.name();
+                oneOfTypes.add(child);
+            }
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, required, defaultValue, docComment, false, false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    private String findDefaultValue(VariableElement fieldElement, String fieldTypeName) {
+        String defaultValue = null;
+        Metadata metadata = fieldElement.getAnnotation(Metadata.class);
+        if (metadata != null) {
+            if (!Strings.isNullOrEmpty(metadata.defaultValue())) {
+                defaultValue = metadata.defaultValue();
+            }
+        }
+        if (defaultValue == null) {
+            // if its a boolean type, then we use false as the default
+            if ("boolean".equals(fieldTypeName) || "java.lang.Boolean".equals(fieldTypeName)) {
+                defaultValue = "false";
+            }
+        }
+
+        return defaultValue;
+    }
+
+    private boolean findRequired(VariableElement fieldElement, boolean defaultValue) {
+        Metadata metadata = fieldElement.getAnnotation(Metadata.class);
+        if (metadata != null) {
+            if (!Strings.isNullOrEmpty(metadata.required())) {
+                defaultValue = "true".equals(metadata.required());
+            }
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Capitializes the name as a title
+     *
+     * @param name  the name
+     * @return as a title
+     */
+    private static String asTitle(String name) {
+        StringBuilder sb = new StringBuilder();
+        for (char c : name.toCharArray()) {
+            boolean upper = Character.isUpperCase(c);
+            boolean first = sb.length() == 0;
+            if (first) {
+                sb.append(Character.toUpperCase(c));
+            } else if (upper) {
+                sb.append(' ');
+                sb.append(c);
+            } else {
+                sb.append(Character.toLowerCase(c));
+            }
+        }
+        return sb.toString().trim();
+    }
+
+    private static final class EipModel {
+
+        private String name;
+        private String title;
+        private String javaType;
+        private String label;
+        private String description;
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String getTitle() {
+            return title;
+        }
+
+        public void setTitle(String title) {
+            this.title = title;
+        }
+
+        public String getJavaType() {
+            return javaType;
+        }
+
+        public void setJavaType(String javaType) {
+            this.javaType = javaType;
+        }
+
+        public String getLabel() {
+            return label;
+        }
+
+        public void setLabel(String label) {
+            this.label = label;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+
+        public void setDescription(String description) {
+            this.description = description;
+        }
+
+    }
+
+    private static final class EipOption {
+
+        private String name;
+        private String kind;
+        private String type;
+        private boolean required;
+        private String defaultValue;
+        private String documentation;
+        private boolean deprecated;
+        private boolean enumType;
+        private Set<String> enums;
+        private boolean oneOf;
+        private Set<String> oneOfTypes;
+
+        private EipOption(String name, String kind, String type, boolean required, String defaultValue, String documentation, boolean deprecated,
+                          boolean enumType, Set<String> enums, boolean oneOf, Set<String> oneOfTypes) {
+            this.name = name;
+            this.kind = kind;
+            this.type = type;
+            this.required = required;
+            this.defaultValue = defaultValue;
+            this.documentation = documentation;
+            this.deprecated = deprecated;
+            this.enumType = enumType;
+            this.enums = enums;
+            this.oneOf = oneOf;
+            this.oneOfTypes = oneOfTypes;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getKind() {
+            return kind;
+        }
+
+        public String getType() {
+            return type;
+        }
+
+        public boolean isRequired() {
+            return required;
+        }
+
+        public String getDefaultValue() {
+            return defaultValue;
+        }
+
+        public String getDocumentation() {
+            return documentation;
+        }
+
+        public boolean isDeprecated() {
+            return deprecated;
+        }
+
+        public boolean isEnumType() {
+            return enumType;
+        }
+
+        public Set<String> getEnums() {
+            return enums;
+        }
+
+        public boolean isOneOf() {
+            return oneOf;
+        }
+
+        public Set<String> getOneOfTypes() {
+            return oneOfTypes;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            EipOption that = (EipOption) o;
+
+            if (!name.equals(that.name)) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            return name.hashCode();
+        }
+    }
+
+    private static final class EipOptionComparator implements Comparator<EipOption> {
+
+        private final EipModel model;
+
+        private EipOptionComparator(EipModel model) {
+            this.model = model;
+        }
+
+        @Override
+        public int compare(EipOption o1, EipOption o2) {
+            int weigth = weigth(o1);
+            int weigth2 = weigth(o2);
+
+            if (weigth == weigth2) {
+                // keep the current order
+                return 1;
+            } else {
+                // sort according to weight
+                return weigth2 - weigth;
+            }
+        }
+
+        private int weigth(EipOption o) {
+            String name = o.getName();
+
+            // these should be first
+            if ("expression".equals(name)) {
+                return 10;
+            }
+
+            // these should be last
+            if ("description".equals(name)) {
+                return -10;
+            } else if ("id".equals(name)) {
+                return -9;
+            } else if ("pattern".equals(name) && "to".equals(model.getName())) {
+                // and pattern only for the to model
+                return -8;
+            }
+            return 0;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/8a18e284/tooling/apt/src/main/resources/META-INF/services/javax.annotation.processing.Processor
----------------------------------------------------------------------
diff --git a/tooling/apt/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/tooling/apt/src/main/resources/META-INF/services/javax.annotation.processing.Processor
index 4e19db2..065c7b0 100644
--- a/tooling/apt/src/main/resources/META-INF/services/javax.annotation.processing.Processor
+++ b/tooling/apt/src/main/resources/META-INF/services/javax.annotation.processing.Processor
@@ -14,6 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-org.apache.camel.tools.apt.EipAnnotationProcessor
+
+### only specify ModelAnnotationProcessor as it delegates to CoreEip or Spring accordingly
+org.apache.camel.tools.apt.ModelAnnotationProcessor
 org.apache.camel.tools.apt.EndpointAnnotationProcessor
-org.apache.camel.tools.apt.CamelContextAnnotationProcessor


[3/4] camel git commit: CAMEL-9482: Adjust the apt to make camel-core compile again, seems like we need to merge the core/spring into a single apt as the compiler cannot do both on camel-core for some odd reason.

Posted by da...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/8a18e284/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessor.java
----------------------------------------------------------------------
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessor.java
new file mode 100644
index 0000000..be2783f
--- /dev/null
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessor.java
@@ -0,0 +1,1127 @@
+/**
+ * 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.PrintWriter;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.ElementKind;
+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.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.tools.apt.helper.JsonSchemaHelper;
+import org.apache.camel.tools.apt.helper.Strings;
+
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findJavaDoc;
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findTypeElement;
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findTypeElementChildren;
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.hasSuperClass;
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.processFile;
+import static org.apache.camel.tools.apt.helper.JsonSchemaHelper.sanitizeDescription;
+import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
+import static org.apache.camel.tools.apt.helper.Strings.isNullOrEmpty;
+import static org.apache.camel.tools.apt.helper.Strings.safeNull;
+
+/**
+ * Process all camel-core's model classes (EIPs and DSL) and generate json schema documentation
+ */
+public class CoreEipAnnotationProcessor {
+
+    // special when using expression/predicates in the model
+    private static final String ONE_OF_TYPE_NAME = "org.apache.camel.model.ExpressionSubElementDefinition";
+    private static final String[] ONE_OF_LANGUAGES = new String[]{
+        "org.apache.camel.model.language.ExpressionDefinition",
+        "org.apache.camel.model.language.NamespaceAwareExpression"
+    };
+    // special for inputs (these classes have sub classes, so we use this to find all classes)
+    private static final String[] ONE_OF_INPUTS = new String[]{
+        "org.apache.camel.model.ProcessorDefinition",
+        "org.apache.camel.model.VerbDefinition"
+    };
+    // special for outputs (these classes have sub classes, so we use this to find all classes)
+    private static final String[] ONE_OF_OUTPUTS = new String[]{
+        "org.apache.camel.model.ProcessorDefinition",
+        "org.apache.camel.model.NoOutputDefinition",
+        "org.apache.camel.model.OutputDefinition",
+        "org.apache.camel.model.ExpressionNode",
+        "org.apache.camel.model.NoOutputExpressionNode",
+        "org.apache.camel.model.SendDefinition",
+        "org.apache.camel.model.InterceptDefinition",
+        "org.apache.camel.model.WhenDefinition",
+        "org.apache.camel.model.ToDynamicDefinition"
+    };
+    // special for verbs (these classes have sub classes, so we use this to find all classes)
+    private static final String[] ONE_OF_VERBS = new String[]{
+        "org.apache.camel.model.rest.VerbDefinition"
+    };
+
+    private boolean skipUnwanted = true;
+
+    protected void processModelClass(final ProcessingEnvironment processingEnv, final RoundEnvironment roundEnv, final TypeElement classElement) {
+        final String javaTypeName = canonicalClassName(classElement.getQualifiedName().toString());
+        String packageName = javaTypeName.substring(0, javaTypeName.lastIndexOf("."));
+
+        // skip abstract classes
+        if (classElement.getModifiers().contains(Modifier.ABSTRACT)) {
+            return;
+        }
+
+        // skip unwanted classes which are "abstract" holders
+        if (skipUnwanted) {
+            if (classElement.getQualifiedName().toString().equals(ONE_OF_TYPE_NAME)) {
+                return;
+            }
+        }
+
+        final XmlRootElement rootElement = classElement.getAnnotation(XmlRootElement.class);
+        if (rootElement == null) {
+            return;
+        }
+
+        String aName = rootElement.name();
+        if (isNullOrEmpty(aName) || "##default".equals(aName)) {
+            XmlType typeElement = classElement.getAnnotation(XmlType.class);
+            aName = typeElement.name();
+        }
+        final String name = aName;
+
+        // lets use the xsd name as the file name
+        String fileName;
+        if (isNullOrEmpty(name) || "##default".equals(name)) {
+            fileName = classElement.getSimpleName().toString() + ".json";
+        } else {
+            fileName = name + ".json";
+        }
+
+        // write json schema
+        Func1<PrintWriter, Void> handler = new Func1<PrintWriter, Void>() {
+            @Override
+            public Void call(PrintWriter writer) {
+                writeJSonSchemeDocumentation(processingEnv, writer, roundEnv, classElement, rootElement, javaTypeName, name);
+                return null;
+            }
+        };
+        processFile(processingEnv, packageName, fileName, handler);
+    }
+
+    protected void writeJSonSchemeDocumentation(ProcessingEnvironment processingEnv, PrintWriter writer, RoundEnvironment roundEnv,
+                                                TypeElement classElement, XmlRootElement rootElement,
+                                                String javaTypeName, String modelName) {
+        // gather eip information
+        EipModel eipModel = findEipModelProperties(processingEnv, roundEnv, classElement, javaTypeName, modelName);
+
+        // get endpoint information which is divided into paths and options (though there should really only be one path)
+        Set<EipOption> eipOptions = new TreeSet<EipOption>(new EipOptionComparator(eipModel));
+        findClassProperties(processingEnv, writer, roundEnv, eipOptions, classElement, classElement, "", modelName);
+
+        // after we have found all the options then figure out if the model accepts input/output
+        eipModel.setInput(hasInput(processingEnv, roundEnv, classElement));
+        eipModel.setOutput(hasOutput(eipModel, eipOptions));
+
+        String json = createParameterJsonSchema(eipModel, eipOptions);
+        writer.println(json);
+    }
+
+    public String createParameterJsonSchema(EipModel eipModel, Set<EipOption> options) {
+        StringBuilder buffer = new StringBuilder("{");
+        // eip model
+        buffer.append("\n \"model\": {");
+        buffer.append("\n    \"kind\": \"").append("model").append("\",");
+        buffer.append("\n    \"name\": \"").append(eipModel.getName()).append("\",");
+        if (eipModel.getTitle() != null) {
+            buffer.append("\n    \"title\": \"").append(eipModel.getTitle()).append("\",");
+        } else {
+            // fallback and use name as title
+            buffer.append("\n    \"title\": \"").append(asTitle(eipModel.getName())).append("\",");
+        }
+        buffer.append("\n    \"description\": \"").append(safeNull(eipModel.getDescription())).append("\",");
+        buffer.append("\n    \"javaType\": \"").append(eipModel.getJavaType()).append("\",");
+        buffer.append("\n    \"label\": \"").append(safeNull(eipModel.getLabel())).append("\",");
+        buffer.append("\n    \"input\": \"").append(eipModel.getInput()).append("\",");
+        buffer.append("\n    \"output\": \"").append(eipModel.getOutput()).append("\"");
+        buffer.append("\n  },");
+
+        buffer.append("\n  \"properties\": {");
+        boolean first = true;
+        for (EipOption entry : options) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(",");
+            }
+            buffer.append("\n    ");
+            // as its json we need to sanitize the docs
+            String doc = entry.getDocumentation();
+            doc = sanitizeDescription(doc, false);
+            buffer.append(JsonSchemaHelper.toJson(entry.getName(), entry.getKind(), entry.isRequired(), entry.getType(), entry.getDefaultValue(), doc,
+                    entry.isDeprecated(), false, null, null, entry.isEnumType(), entry.getEnums(), entry.isOneOf(), entry.getOneOfTypes(), null, null, false));
+        }
+        buffer.append("\n  }");
+
+        buffer.append("\n}\n");
+        return buffer.toString();
+    }
+
+    protected EipModel findEipModelProperties(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement classElement, String javaTypeName, String name) {
+        EipModel model = new EipModel();
+        model.setJavaType(javaTypeName);
+        model.setName(name);
+
+        Metadata metadata = classElement.getAnnotation(Metadata.class);
+        if (metadata != null) {
+            if (!Strings.isNullOrEmpty(metadata.label())) {
+                model.setLabel(metadata.label());
+            }
+            if (!Strings.isNullOrEmpty(metadata.title())) {
+                model.setTitle(metadata.title());
+            }
+        }
+
+        // favor to use class javadoc of component as description
+        if (model.getJavaType() != null) {
+            Elements elementUtils = processingEnv.getElementUtils();
+            TypeElement typeElement = findTypeElement(processingEnv, roundEnv, model.getJavaType());
+            if (typeElement != null) {
+                String doc = elementUtils.getDocComment(typeElement);
+                if (doc != null) {
+                    // need to sanitize the description first (we only want a summary)
+                    doc = sanitizeDescription(doc, true);
+                    // the javadoc may actually be empty, so only change the doc if we got something
+                    if (!Strings.isNullOrEmpty(doc)) {
+                        model.setDescription(doc);
+                    }
+                }
+            }
+        }
+
+        return model;
+    }
+
+    protected void findClassProperties(ProcessingEnvironment processingEnv, PrintWriter writer, RoundEnvironment roundEnv, Set<EipOption> eipOptions,
+                                       TypeElement originalClassType, TypeElement classElement, String prefix, String modelName) {
+        while (true) {
+            List<VariableElement> fieldElements = ElementFilter.fieldsIn(classElement.getEnclosedElements());
+            for (VariableElement fieldElement : fieldElements) {
+
+                String fieldName = fieldElement.getSimpleName().toString();
+
+                XmlAttribute attribute = fieldElement.getAnnotation(XmlAttribute.class);
+                if (attribute != null) {
+                    boolean skip = processAttribute(processingEnv, roundEnv, originalClassType, classElement, fieldElement, fieldName, attribute, eipOptions, prefix, modelName);
+                    if (skip) {
+                        continue;
+                    }
+                }
+
+                XmlValue value = fieldElement.getAnnotation(XmlValue.class);
+                if (value != null) {
+                    processValue(processingEnv, roundEnv, originalClassType, classElement, fieldElement, fieldName, value, eipOptions, prefix, modelName);
+                }
+
+                XmlElements elements = fieldElement.getAnnotation(XmlElements.class);
+                if (elements != null) {
+                    processElements(processingEnv, roundEnv, classElement, elements, fieldElement, eipOptions, prefix);
+                }
+
+                XmlElement element = fieldElement.getAnnotation(XmlElement.class);
+                if (element != null) {
+                    processElement(processingEnv, roundEnv, classElement, element, fieldElement, eipOptions, prefix);
+                }
+
+                // special for eips which has outputs or requires an expressions
+                XmlElementRef elementRef = fieldElement.getAnnotation(XmlElementRef.class);
+                if (elementRef != null) {
+
+                    // special for routes
+                    processRoutes(roundEnv, originalClassType, elementRef, fieldElement, fieldName, eipOptions, prefix);
+
+                    // special for outputs
+                    processOutputs(processingEnv, roundEnv, originalClassType, elementRef, fieldElement, fieldName, eipOptions, prefix);
+
+                    // special for when clauses (choice eip)
+                    processRefWhenClauses(processingEnv, roundEnv, originalClassType, elementRef, fieldElement, fieldName, eipOptions, prefix);
+
+                    // special for rests (rest-dsl)
+                    processRests(roundEnv, originalClassType, elementRef, fieldElement, fieldName, eipOptions, prefix);
+
+                    // special for verbs (rest-dsl)
+                    processVerbs(processingEnv, roundEnv, originalClassType, elementRef, fieldElement, fieldName, eipOptions, prefix);
+
+                    // special for expression
+                    processRefExpression(processingEnv, roundEnv, originalClassType, classElement, elementRef, fieldElement, fieldName, eipOptions, prefix);
+
+                }
+            }
+
+            // special when we process these nodes as they do not use JAXB annotations on fields, but on methods
+            if ("OptionalIdentifiedDefinition".equals(classElement.getSimpleName().toString())) {
+                processIdentified(processingEnv, roundEnv, originalClassType, classElement, eipOptions, prefix);
+            } else if ("RouteDefinition".equals(classElement.getSimpleName().toString())) {
+                processRoute(processingEnv, roundEnv, originalClassType, classElement, eipOptions, prefix);
+            }
+
+            // check super classes which may also have fields
+            TypeElement baseTypeElement = null;
+            TypeMirror superclass = classElement.getSuperclass();
+            if (superclass != null) {
+                String superClassName = canonicalClassName(superclass.toString());
+                baseTypeElement = findTypeElement(processingEnv, roundEnv, superClassName);
+            }
+            if (baseTypeElement != null) {
+                classElement = baseTypeElement;
+            } else {
+                break;
+            }
+        }
+    }
+
+    private boolean processAttribute(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement classElement, VariableElement fieldElement,
+                                     String fieldName, XmlAttribute attribute, Set<EipOption> eipOptions, String prefix, String modelName) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        String name = attribute.name();
+        if (isNullOrEmpty(name) || "##default".equals(name)) {
+            name = fieldName;
+        }
+
+        // lets skip some unwanted attributes
+        if (skipUnwanted) {
+            // we want to skip inheritErrorHandler which is only applicable for the load-balancer
+            boolean loadBalancer = "LoadBalanceDefinition".equals(originalClassType.getSimpleName().toString());
+            if (!loadBalancer && "inheritErrorHandler".equals(name)) {
+                return true;
+            }
+        }
+
+        name = prefix + name;
+        TypeMirror fieldType = fieldElement.asType();
+        String fieldTypeName = fieldType.toString();
+        TypeElement fieldTypeElement = findTypeElement(processingEnv, roundEnv, fieldTypeName);
+
+        String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
+        String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true);
+        boolean required = attribute.required();
+        // metadata may overrule element required
+        required = findRequired(fieldElement, required);
+
+        // gather enums
+        Set<String> enums = new TreeSet<String>();
+        boolean isEnum = fieldTypeElement != null && fieldTypeElement.getKind() == ElementKind.ENUM;
+        if (isEnum) {
+            TypeElement enumClass = findTypeElement(processingEnv, roundEnv, fieldTypeElement.asType().toString());
+            // find all the enum constants which has the possible enum value that can be used
+            List<VariableElement> fields = ElementFilter.fieldsIn(enumClass.getEnclosedElements());
+            for (VariableElement var : fields) {
+                if (var.getKind() == ElementKind.ENUM_CONSTANT) {
+                    String val = var.toString();
+                    enums.add(val);
+                }
+            }
+        }
+
+        boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null;
+
+        EipOption ep = new EipOption(name, "attribute", fieldTypeName, required, defaultValue, docComment, deprecated, isEnum, enums, false, null);
+        eipOptions.add(ep);
+
+        return false;
+    }
+
+    private void processValue(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement originalClassType,
+                              TypeElement classElement, VariableElement fieldElement, String fieldName, XmlValue value,
+        Set<EipOption> eipOptions, String prefix, String modelName) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        // XmlValue has no name attribute
+        String name = fieldName;
+
+        if ("method".equals(modelName) || "tokenize".equals(modelName) || "xtokenize".equals(modelName)) {
+            // skip expression attribute on these three languages as they are solely configured using attributes
+            if ("expression".equals(name)) {
+                return;
+            }
+        }
+
+        name = prefix + name;
+        TypeMirror fieldType = fieldElement.asType();
+        String fieldTypeName = fieldType.toString();
+
+        String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
+        String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true);
+        boolean required = true;
+        // metadata may overrule element required
+        required = findRequired(fieldElement, required);
+
+        boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null;
+
+        EipOption ep = new EipOption(name, "value", fieldTypeName, required, defaultValue, docComment, deprecated, false, null, false, null);
+        eipOptions.add(ep);
+    }
+
+    private void processElement(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement classElement, XmlElement element, VariableElement fieldElement,
+                                Set<EipOption> eipOptions, String prefix) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        String fieldName;
+        fieldName = fieldElement.getSimpleName().toString();
+        if (element != null) {
+
+            String kind = "element";
+            String name = element.name();
+            if (isNullOrEmpty(name) || "##default".equals(name)) {
+                name = fieldName;
+            }
+            name = prefix + name;
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+            TypeElement fieldTypeElement = findTypeElement(processingEnv, roundEnv, fieldTypeName);
+
+            String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
+            String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true);
+            boolean required = element.required();
+            // metadata may overrule element required
+            required = findRequired(fieldElement, required);
+
+            // gather enums
+            Set<String> enums = new LinkedHashSet<String>();
+            boolean isEnum = fieldTypeElement != null && fieldTypeElement.getKind() == ElementKind.ENUM;
+            if (isEnum) {
+                TypeElement enumClass = findTypeElement(processingEnv, roundEnv, fieldTypeElement.asType().toString());
+                // find all the enum constants which has the possible enum value that can be used
+                List<VariableElement> fields = ElementFilter.fieldsIn(enumClass.getEnclosedElements());
+                for (VariableElement var : fields) {
+                    if (var.getKind() == ElementKind.ENUM_CONSTANT) {
+                        String val = var.toString();
+                        enums.add(val);
+                    }
+                }
+            }
+
+            // gather oneOf expression/predicates which uses language
+            Set<String> oneOfTypes = new TreeSet<String>();
+            boolean isOneOf = ONE_OF_TYPE_NAME.equals(fieldTypeName);
+            if (isOneOf) {
+                // okay its actually an language expression, so favor using that in the eip option
+                kind = "expression";
+                for (String language : ONE_OF_LANGUAGES) {
+                    fieldTypeName = language;
+                    TypeElement languages = findTypeElement(processingEnv, roundEnv, language);
+                    String superClassName = canonicalClassName(languages.toString());
+                    // find all classes that has that superClassName
+                    Set<TypeElement> children = new LinkedHashSet<TypeElement>();
+                    findTypeElementChildren(processingEnv, roundEnv, children, superClassName);
+                    for (TypeElement child : children) {
+                        XmlRootElement rootElement = child.getAnnotation(XmlRootElement.class);
+                        if (rootElement != null) {
+                            String childName = rootElement.name();
+                            if (childName != null) {
+                                oneOfTypes.add(childName);
+                            }
+                        }
+                    }
+                }
+            }
+            // special for otherwise as we want to indicate that the element is
+            if ("otherwise".equals(name)) {
+                isOneOf = true;
+                oneOfTypes.add("otherwise");
+            }
+
+            boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null;
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, required, defaultValue, docComment, deprecated, isEnum, enums, isOneOf, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    private void processElements(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement classElement, XmlElements elements, VariableElement fieldElement,
+                                 Set<EipOption> eipOptions, String prefix) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        String fieldName;
+        fieldName = fieldElement.getSimpleName().toString();
+        if (elements != null) {
+            String kind = "element";
+            String name = fieldName;
+            name = prefix + name;
+
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+
+            String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
+            String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true);
+
+            boolean required = true;
+            required = findRequired(fieldElement, required);
+
+            // gather oneOf of the elements
+            Set<String> oneOfTypes = new TreeSet<String>();
+            for (XmlElement element : elements.value()) {
+                String child = element.name();
+                oneOfTypes.add(child);
+            }
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, required, defaultValue, docComment, false, false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    private void processRoute(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement classElement,
+                              Set<EipOption> eipOptions, String prefix) {
+
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        // group
+        String docComment = findJavaDoc(elementUtils, null, "group", null, classElement, true);
+        EipOption ep = new EipOption("group", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // group
+        docComment = findJavaDoc(elementUtils, null, "streamCache", null, classElement, true);
+        ep = new EipOption("streamCache", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // trace
+        docComment = findJavaDoc(elementUtils, null, "trace", null, classElement, true);
+        ep = new EipOption("trace", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // trace
+        docComment = findJavaDoc(elementUtils, null, "messageHistory", null, classElement, true);
+        ep = new EipOption("messageHistory", "attribute", "java.lang.String", false, "true", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // trace
+        docComment = findJavaDoc(elementUtils, null, "handleFault", null, classElement, true);
+        ep = new EipOption("handleFault", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // delayer
+        docComment = findJavaDoc(elementUtils, null, "delayer", null, classElement, true);
+        ep = new EipOption("delayer", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // autoStartup
+        docComment = findJavaDoc(elementUtils, null, "autoStartup", null, classElement, true);
+        ep = new EipOption("autoStartup", "attribute", "java.lang.String", false, "true", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // startupOrder
+        docComment = findJavaDoc(elementUtils, null, "startupOrder", null, classElement, true);
+        ep = new EipOption("startupOrder", "attribute", "java.lang.Integer", false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // errorHandlerRef
+        docComment = findJavaDoc(elementUtils, null, "errorHandlerRef", null, classElement, true);
+        ep = new EipOption("errorHandlerRef", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // routePolicyRef
+        docComment = findJavaDoc(elementUtils, null, "routePolicyRef", null, classElement, true);
+        ep = new EipOption("routePolicyRef", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // shutdownRoute
+        Set<String> enums = new LinkedHashSet<String>();
+        enums.add("Default");
+        enums.add("Defer");
+        docComment = findJavaDoc(elementUtils, null, "shutdownRoute", "Default", classElement, true);
+        ep = new EipOption("shutdownRoute", "attribute", "org.apache.camel.ShutdownRoute", false, "", docComment, false, true, enums, false, null);
+        eipOptions.add(ep);
+
+        // shutdownRunningTask
+        enums = new LinkedHashSet<String>();
+        enums.add("CompleteCurrentTaskOnly");
+        enums.add("CompleteAllTasks");
+        docComment = findJavaDoc(elementUtils, null, "shutdownRunningTask", "CompleteCurrentTaskOnly", classElement, true);
+        ep = new EipOption("shutdownRunningTask", "attribute", "org.apache.camel.ShutdownRunningTask", false, "", docComment, false, true, enums, false, null);
+        eipOptions.add(ep);
+
+        // inputs
+        Set<String> oneOfTypes = new TreeSet<String>();
+        oneOfTypes.add("from");
+        docComment = findJavaDoc(elementUtils, null, "inputs", null, classElement, true);
+        ep = new EipOption("inputs", "element", "java.util.List<org.apache.camel.model.FromDefinition>", true, "", docComment, false, false, null, true, oneOfTypes);
+        eipOptions.add(ep);
+
+        // outputs
+        // gather oneOf which extends any of the output base classes
+        oneOfTypes = new TreeSet<String>();
+        // find all classes that has that superClassName
+        Set<TypeElement> children = new LinkedHashSet<TypeElement>();
+        for (String superclass : ONE_OF_OUTPUTS) {
+            findTypeElementChildren(processingEnv, roundEnv, children, superclass);
+        }
+        for (TypeElement child : children) {
+            XmlRootElement rootElement = child.getAnnotation(XmlRootElement.class);
+            if (rootElement != null) {
+                String childName = rootElement.name();
+                if (childName != null) {
+                    oneOfTypes.add(childName);
+                }
+            }
+        }
+
+        // remove some types which are not intended as an output in eips
+        oneOfTypes.remove("route");
+
+        docComment = findJavaDoc(elementUtils, null, "outputs", null, classElement, true);
+        ep = new EipOption("outputs", "element", "java.util.List<org.apache.camel.model.ProcessorDefinition<?>>", true, "", docComment, false, false, null, true, oneOfTypes);
+        eipOptions.add(ep);
+    }
+
+    /**
+     * Special for process the OptionalIdentifiedDefinition
+     */
+    private void processIdentified(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement classElement,
+                                   Set<EipOption> eipOptions, String prefix) {
+
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        // id
+        String docComment = findJavaDoc(elementUtils, null, "id", null, classElement, true);
+        EipOption ep = new EipOption("id", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // description
+        docComment = findJavaDoc(elementUtils, null, "description", null, classElement, true);
+        ep = new EipOption("description", "element", "org.apache.camel.model.DescriptionDefinition", false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // lets skip custom id as it has no value for end users to configure
+        if (!skipUnwanted) {
+            // custom id
+            docComment = findJavaDoc(elementUtils, null, "customId", null, classElement, true);
+            ep = new EipOption("customId", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
+            eipOptions.add(ep);
+        }
+    }
+
+    /**
+     * Special for processing an @XmlElementRef routes field
+     */
+    private void processRoutes(RoundEnvironment roundEnv, TypeElement originalClassType, XmlElementRef elementRef,
+                               VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) {
+        if ("routes".equals(fieldName)) {
+
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+
+            Set<String> oneOfTypes = new TreeSet<String>();
+            oneOfTypes.add("route");
+
+            EipOption ep = new EipOption("routes", "element", fieldTypeName, false, "", "Contains the Camel routes", false, false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    /**
+     * Special for processing an @XmlElementRef rests field
+     */
+    private void processRests(RoundEnvironment roundEnv, TypeElement originalClassType, XmlElementRef elementRef,
+                               VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) {
+        if ("rests".equals(fieldName)) {
+
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+
+            Set<String> oneOfTypes = new TreeSet<String>();
+            oneOfTypes.add("rest");
+
+            EipOption ep = new EipOption("rests", "element", fieldTypeName, false, "", "Contains the rest services defined using the rest-dsl", false, false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    /**
+     * Special for processing an @XmlElementRef outputs field
+     */
+    private void processOutputs(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement originalClassType, XmlElementRef elementRef,
+                                VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) {
+        if ("outputs".equals(fieldName) && supportOutputs(originalClassType)) {
+            String kind = "element";
+            String name = elementRef.name();
+            if (isNullOrEmpty(name) || "##default".equals(name)) {
+                name = fieldName;
+            }
+            name = prefix + name;
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+
+            // gather oneOf which extends any of the output base classes
+            Set<String> oneOfTypes = new TreeSet<String>();
+            // find all classes that has that superClassName
+            Set<TypeElement> children = new LinkedHashSet<TypeElement>();
+            for (String superclass : ONE_OF_OUTPUTS) {
+                findTypeElementChildren(processingEnv, roundEnv, children, superclass);
+            }
+            for (TypeElement child : children) {
+                XmlRootElement rootElement = child.getAnnotation(XmlRootElement.class);
+                if (rootElement != null) {
+                    String childName = rootElement.name();
+                    if (childName != null) {
+                        oneOfTypes.add(childName);
+                    }
+                }
+            }
+
+            // remove some types which are not intended as an output in eips
+            oneOfTypes.remove("route");
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, true, "", "", false, false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    /**
+     * Special for processing an @XmlElementRef verbs field (rest-dsl)
+     */
+    private void processVerbs(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement originalClassType, XmlElementRef elementRef,
+                              VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) {
+
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        if ("verbs".equals(fieldName) && supportOutputs(originalClassType)) {
+            String kind = "element";
+            String name = elementRef.name();
+            if (isNullOrEmpty(name) || "##default".equals(name)) {
+                name = fieldName;
+            }
+            name = prefix + name;
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+
+            String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, originalClassType, true);
+
+            // gather oneOf which extends any of the output base classes
+            Set<String> oneOfTypes = new TreeSet<String>();
+            // find all classes that has that superClassName
+            Set<TypeElement> children = new LinkedHashSet<TypeElement>();
+            for (String superclass : ONE_OF_VERBS) {
+                findTypeElementChildren(processingEnv, roundEnv, children, superclass);
+            }
+            for (TypeElement child : children) {
+                XmlRootElement rootElement = child.getAnnotation(XmlRootElement.class);
+                if (rootElement != null) {
+                    String childName = rootElement.name();
+                    if (childName != null) {
+                        oneOfTypes.add(childName);
+                    }
+                }
+            }
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, true, "", docComment, false, false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    /**
+     * Special for processing an @XmlElementRef expression field
+     */
+    private void processRefExpression(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement classElement,
+                                      XmlElementRef elementRef, VariableElement fieldElement,
+                                      String fieldName, Set<EipOption> eipOptions, String prefix) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        if ("expression".equals(fieldName)) {
+            String kind = "expression";
+            String name = elementRef.name();
+            if (isNullOrEmpty(name) || "##default".equals(name)) {
+                name = fieldName;
+            }
+            name = prefix + name;
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+
+            // find javadoc from original class as it will override the setExpression method where we can provide the javadoc for the given EIP
+            String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, originalClassType, true);
+
+            // gather oneOf expression/predicates which uses language
+            Set<String> oneOfTypes = new TreeSet<String>();
+            for (String language : ONE_OF_LANGUAGES) {
+                TypeElement languages = findTypeElement(processingEnv, roundEnv, language);
+                String superClassName = canonicalClassName(languages.toString());
+                // find all classes that has that superClassName
+                Set<TypeElement> children = new LinkedHashSet<TypeElement>();
+                findTypeElementChildren(processingEnv, roundEnv, children, superClassName);
+                for (TypeElement child : children) {
+                    XmlRootElement rootElement = child.getAnnotation(XmlRootElement.class);
+                    if (rootElement != null) {
+                        String childName = rootElement.name();
+                        if (childName != null) {
+                            oneOfTypes.add(childName);
+                        }
+                    }
+                }
+            }
+
+            boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null;
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, true, "", docComment, deprecated, false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    /**
+     * Special for processing an @XmlElementRef when field
+     */
+    private void processRefWhenClauses(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement originalClassType, XmlElementRef elementRef,
+                                       VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        if ("whenClauses".equals(fieldName)) {
+            String kind = "element";
+            String name = elementRef.name();
+            if (isNullOrEmpty(name) || "##default".equals(name)) {
+                name = fieldName;
+            }
+            name = prefix + name;
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+
+            // find javadoc from original class as it will override the setExpression method where we can provide the javadoc for the given EIP
+            String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, originalClassType, true);
+            boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null;
+
+            // indicate that this element is one of when
+            Set<String> oneOfTypes = new HashSet<String>();
+            oneOfTypes.add("when");
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, false, "", docComment, deprecated, false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    /**
+     * Whether the class supports outputs.
+     * <p/>
+     * There are some classes which does not support outputs, even though they have a outputs element.
+     */
+    private boolean supportOutputs(TypeElement classElement) {
+        String superclass = canonicalClassName(classElement.getSuperclass().toString());
+        return !"org.apache.camel.model.NoOutputExpressionNode".equals(superclass);
+    }
+
+    private String findDefaultValue(VariableElement fieldElement, String fieldTypeName) {
+        String defaultValue = null;
+        Metadata metadata = fieldElement.getAnnotation(Metadata.class);
+        if (metadata != null) {
+            if (!Strings.isNullOrEmpty(metadata.defaultValue())) {
+                defaultValue = metadata.defaultValue();
+            }
+        }
+        if (defaultValue == null) {
+            // if its a boolean type, then we use false as the default
+            if ("boolean".equals(fieldTypeName) || "java.lang.Boolean".equals(fieldTypeName)) {
+                defaultValue = "false";
+            }
+        }
+
+        return defaultValue;
+    }
+
+    private boolean findRequired(VariableElement fieldElement, boolean defaultValue) {
+        Metadata metadata = fieldElement.getAnnotation(Metadata.class);
+        if (metadata != null) {
+            if (!Strings.isNullOrEmpty(metadata.required())) {
+                defaultValue = "true".equals(metadata.required());
+            }
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Capitializes the name as a title
+     *
+     * @param name  the name
+     * @return as a title
+     */
+    private static String asTitle(String name) {
+        StringBuilder sb = new StringBuilder();
+        for (char c : name.toCharArray()) {
+            boolean upper = Character.isUpperCase(c);
+            boolean first = sb.length() == 0;
+            if (first) {
+                sb.append(Character.toUpperCase(c));
+            } else if (upper) {
+                sb.append(' ');
+                sb.append(c);
+            } else {
+                sb.append(Character.toLowerCase(c));
+            }
+        }
+        return sb.toString().trim();
+    }
+
+    private boolean hasInput(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement classElement) {
+        for (String name : ONE_OF_INPUTS) {
+            if (hasSuperClass(processingEnv, roundEnv, classElement, name)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean hasOutput(EipModel model, Set<EipOption> options) {
+        // if we are route/rest then we accept output
+        if ("route".equals(model.getName()) || "rest".equals(model.getName())) {
+            return true;
+        }
+
+        for (EipOption option : options) {
+            if ("outputs".equals(option.getName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static final class EipModel {
+
+        private String name;
+        private String title;
+        private String javaType;
+        private String label;
+        private String description;
+        private boolean input;
+        private boolean output;
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String getTitle() {
+            return title;
+        }
+
+        public void setTitle(String title) {
+            this.title = title;
+        }
+
+        public String getJavaType() {
+            return javaType;
+        }
+
+        public void setJavaType(String javaType) {
+            this.javaType = javaType;
+        }
+
+        public String getLabel() {
+            return label;
+        }
+
+        public void setLabel(String label) {
+            this.label = label;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+
+        public void setDescription(String description) {
+            this.description = description;
+        }
+
+        public boolean isInput() {
+            return input;
+        }
+
+        public void setInput(boolean input) {
+            this.input = input;
+        }
+
+        public String getInput() {
+            return input ? "true" : "false";
+        }
+
+        public boolean isOutput() {
+            return output;
+        }
+
+        public void setOutput(boolean output) {
+            this.output = output;
+        }
+
+        public String getOutput() {
+            return output ? "true" : "false";
+        }
+
+    }
+
+    private static final class EipOption {
+
+        private String name;
+        private String kind;
+        private String type;
+        private boolean required;
+        private String defaultValue;
+        private String documentation;
+        private boolean deprecated;
+        private boolean enumType;
+        private Set<String> enums;
+        private boolean oneOf;
+        private Set<String> oneOfTypes;
+
+        private EipOption(String name, String kind, String type, boolean required, String defaultValue, String documentation, boolean deprecated,
+                          boolean enumType, Set<String> enums, boolean oneOf, Set<String> oneOfTypes) {
+            this.name = name;
+            this.kind = kind;
+            this.type = type;
+            this.required = required;
+            this.defaultValue = defaultValue;
+            this.documentation = documentation;
+            this.deprecated = deprecated;
+            this.enumType = enumType;
+            this.enums = enums;
+            this.oneOf = oneOf;
+            this.oneOfTypes = oneOfTypes;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getKind() {
+            return kind;
+        }
+
+        public String getType() {
+            return type;
+        }
+
+        public boolean isRequired() {
+            return required;
+        }
+
+        public String getDefaultValue() {
+            return defaultValue;
+        }
+
+        public String getDocumentation() {
+            return documentation;
+        }
+
+        public boolean isDeprecated() {
+            return deprecated;
+        }
+
+        public boolean isEnumType() {
+            return enumType;
+        }
+
+        public Set<String> getEnums() {
+            return enums;
+        }
+
+        public boolean isOneOf() {
+            return oneOf;
+        }
+
+        public Set<String> getOneOfTypes() {
+            return oneOfTypes;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            EipOption that = (EipOption) o;
+
+            if (!name.equals(that.name)) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            return name.hashCode();
+        }
+    }
+
+    private static final class EipOptionComparator implements Comparator<EipOption> {
+
+        private final EipModel model;
+
+        private EipOptionComparator(EipModel model) {
+            this.model = model;
+        }
+
+        @Override
+        public int compare(EipOption o1, EipOption o2) {
+            int weigth = weigth(o1);
+            int weigth2 = weigth(o2);
+
+            if (weigth == weigth2) {
+                // keep the current order
+                return 1;
+            } else {
+                // sort according to weight
+                return weigth2 - weigth;
+            }
+        }
+
+        private int weigth(EipOption o) {
+            String name = o.getName();
+
+            // these should be first
+            if ("expression".equals(name)) {
+                return 10;
+            }
+
+            // these should be last
+            if ("description".equals(name)) {
+                return -10;
+            } else if ("id".equals(name)) {
+                return -9;
+            } else if ("pattern".equals(name) && "to".equals(model.getName())) {
+                // and pattern only for the to model
+                return -8;
+            }
+            return 0;
+        }
+    }
+
+}


[4/4] camel git commit: CAMEL-9482: Adjust the apt to make camel-core compile again, seems like we need to merge the core/spring into a single apt as the compiler cannot do both on camel-core for some odd reason.

Posted by da...@apache.org.
CAMEL-9482: Adjust the apt to make camel-core compile again, seems like we need to merge the core/spring into a single apt as the compiler cannot do both on camel-core for some odd reason.


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/8a18e284
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/8a18e284
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/8a18e284

Branch: refs/heads/master
Commit: 8a18e2849b08898d51b84c59fd892691ac593a94
Parents: bbb7ff9
Author: Claus Ibsen <da...@apache.org>
Authored: Thu Aug 11 09:41:27 2016 +0200
Committer: Claus Ibsen <da...@apache.org>
Committed: Thu Aug 11 09:43:41 2016 +0200

----------------------------------------------------------------------
 .../tools/apt/AbstractAnnotationProcessor.java  |  419 -------
 .../tools/apt/AnnotationProcessorHelper.java    |  421 +++++++
 .../apt/CamelContextAnnotationProcessor.java    |  720 -----------
 .../tools/apt/CoreEipAnnotationProcessor.java   | 1127 +++++++++++++++++
 .../camel/tools/apt/EipAnnotationProcessor.java | 1148 ------------------
 .../tools/apt/EndpointAnnotationProcessor.java  |   45 +-
 .../tools/apt/ModelAnnotationProcessor.java     |   71 ++
 .../tools/apt/SpringAnnotationProcessor.java    |  689 +++++++++++
 .../javax.annotation.processing.Processor       |    5 +-
 9 files changed, 2338 insertions(+), 2307 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/8a18e284/tooling/apt/src/main/java/org/apache/camel/tools/apt/AbstractAnnotationProcessor.java
----------------------------------------------------------------------
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/AbstractAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/AbstractAnnotationProcessor.java
deleted file mode 100644
index 6159602..0000000
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/AbstractAnnotationProcessor.java
+++ /dev/null
@@ -1,419 +0,0 @@
-/**
- * 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.FileOutputStream;
-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.Collections;
-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.element.VariableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-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.helper.IOHelper.loadText;
-import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
-import static org.apache.camel.tools.apt.helper.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 VariableElement findFieldElement(TypeElement classElement, String fieldName) {
-        if (isNullOrEmpty(fieldName)) {
-            return null;
-        }
-
-        List<VariableElement> fields = ElementFilter.fieldsIn(classElement.getEnclosedElements());
-        for (VariableElement field : fields) {
-            if (fieldName.equals(field.getSimpleName().toString())) {
-                return field;
-            }
-        }
-
-        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 = getEnclosedElements(pe);
-                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;
-    }
-
-    @SuppressWarnings("unchecked")
-    private List<? extends Element> getEnclosedElements(PackageElement pe) {
-        // some components like hadoop/spark has bad classes that causes javac scanning issues
-        try {
-            return pe.getEnclosedElements();
-        } catch (Throwable e) {
-            // ignore
-        }
-        return Collections.EMPTY_LIST;
-    }
-
-    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());
-
-        // do not check the classes from JDK itself
-        if (isNullOrEmpty(aRootName) || aRootName.startsWith("java.") || aRootName.startsWith("javax.")) {
-            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;
-        }
-    }
-
-    protected boolean implementsInterface(RoundEnvironment roundEnv, TypeElement classElement, String interfaceClassName) {
-        while (true) {
-            // check if the class implements the interface
-            List<? extends TypeMirror> list = classElement.getInterfaces();
-            if (list != null) {
-                for (TypeMirror type : list) {
-                    if (type.getKind().compareTo(TypeKind.DECLARED) == 0) {
-                        String name = type.toString();
-                        if (interfaceClassName.equals(name)) {
-                            return true;
-                        }
-                    }
-                }
-            }
-
-            // check super classes which may implement the interface
-            TypeElement baseTypeElement = null;
-            TypeMirror superclass = classElement.getSuperclass();
-            if (superclass != null) {
-                String superClassName = canonicalClassName(superclass.toString());
-                baseTypeElement = findTypeElement(roundEnv, superClassName);
-            }
-            if (baseTypeElement != null) {
-                classElement = baseTypeElement;
-            } else {
-                break;
-            }
-        }
-
-        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;
-    }
-
-    protected void dumpExceptionToErrorFile(String fileName, String message, Throwable e) {
-        File file = new File(fileName);
-        try {
-            FileOutputStream fos = new FileOutputStream(file);
-            StringWriter sw = new StringWriter();
-            PrintWriter pw = new PrintWriter(sw);
-            e.printStackTrace(pw);
-            fos.write(message.getBytes());
-            fos.write("\n\n".getBytes());
-            fos.write(sw.toString().getBytes());
-            pw.close();
-            sw.close();
-            fos.close();
-        } catch (Throwable t) {
-            // ignore
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/8a18e284/tooling/apt/src/main/java/org/apache/camel/tools/apt/AnnotationProcessorHelper.java
----------------------------------------------------------------------
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/AnnotationProcessorHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/AnnotationProcessorHelper.java
new file mode 100644
index 0000000..ccbe807
--- /dev/null
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/AnnotationProcessorHelper.java
@@ -0,0 +1,421 @@
+/**
+ * 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.FileOutputStream;
+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.Collections;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.ProcessingEnvironment;
+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.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+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.helper.IOHelper.loadText;
+import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
+import static org.apache.camel.tools.apt.helper.Strings.isNullOrEmpty;
+
+/**
+ * Abstract class for Camel apt plugins.
+ */
+public final class AnnotationProcessorHelper {
+
+    private AnnotationProcessorHelper() {
+    }
+
+    public static 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;
+    }
+
+    public static 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;
+    }
+
+    public static 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;
+    }
+
+    public static VariableElement findFieldElement(TypeElement classElement, String fieldName) {
+        if (isNullOrEmpty(fieldName)) {
+            return null;
+        }
+
+        List<VariableElement> fields = ElementFilter.fieldsIn(classElement.getEnclosedElements());
+        for (VariableElement field : fields) {
+            if (fieldName.equals(field.getSimpleName().toString())) {
+                return field;
+            }
+        }
+
+        return null;
+    }
+
+    public static TypeElement findTypeElement(ProcessingEnvironment processingEnv, 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 = getEnclosedElements(pe);
+                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;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static List<? extends Element> getEnclosedElements(PackageElement pe) {
+        // some components like hadoop/spark has bad classes that causes javac scanning issues
+        try {
+            return pe.getEnclosedElements();
+        } catch (Throwable e) {
+            // ignore
+        }
+        return Collections.EMPTY_LIST;
+    }
+
+    public static void findTypeElementChildren(ProcessingEnvironment processingEnv, 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);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public static boolean hasSuperClass(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement classElement, String superClassName) {
+        String aRootName = canonicalClassName(classElement.getQualifiedName().toString());
+
+        // do not check the classes from JDK itself
+        if (isNullOrEmpty(aRootName) || aRootName.startsWith("java.") || aRootName.startsWith("javax.")) {
+            return false;
+        }
+
+        String aSuperClassName = canonicalClassName(classElement.getSuperclass().toString());
+        if (superClassName.equals(aSuperClassName)) {
+            return true;
+        }
+
+        TypeElement aSuperClass = findTypeElement(processingEnv, roundEnv, aSuperClassName);
+        if (aSuperClass != null) {
+            return hasSuperClass(processingEnv, roundEnv, aSuperClass, superClassName);
+        } else {
+            return false;
+        }
+    }
+
+    public static boolean implementsInterface(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, TypeElement classElement, String interfaceClassName) {
+        while (true) {
+            // check if the class implements the interface
+            List<? extends TypeMirror> list = classElement.getInterfaces();
+            if (list != null) {
+                for (TypeMirror type : list) {
+                    if (type.getKind().compareTo(TypeKind.DECLARED) == 0) {
+                        String name = type.toString();
+                        if (interfaceClassName.equals(name)) {
+                            return true;
+                        }
+                    }
+                }
+            }
+
+            // check super classes which may implement the interface
+            TypeElement baseTypeElement = null;
+            TypeMirror superclass = classElement.getSuperclass();
+            if (superclass != null) {
+                String superClassName = canonicalClassName(superclass.toString());
+                baseTypeElement = findTypeElement(processingEnv, roundEnv, superClassName);
+            }
+            if (baseTypeElement != null) {
+                classElement = baseTypeElement;
+            } else {
+                break;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Helper method to produce class output text file using the given handler
+     */
+    public static void processFile(ProcessingEnvironment processingEnv, 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(processingEnv, "Could not convert output directory resource URI to a file " + e);
+                }
+            }
+            if (file == null) {
+                warning(processingEnv, "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(processingEnv, e);
+        } finally {
+            if (writer != null) {
+                writer.close();
+            }
+        }
+    }
+
+    public static void log(ProcessingEnvironment processingEnv, String message) {
+        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message);
+    }
+
+    public static void warning(ProcessingEnvironment processingEnv, String message) {
+        processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, message);
+    }
+
+    public static void error(ProcessingEnvironment processingEnv, String message) {
+        processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message);
+    }
+
+    public static void log(ProcessingEnvironment processingEnv, 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());
+    }
+
+    public static String loadResource(ProcessingEnvironment processingEnv, 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(processingEnv, "Cannot load file");
+        }
+
+        return null;
+    }
+
+    public static void dumpExceptionToErrorFile(String fileName, String message, Throwable e) {
+        File file = new File(fileName);
+        try {
+            FileOutputStream fos = new FileOutputStream(file);
+            StringWriter sw = new StringWriter();
+            PrintWriter pw = new PrintWriter(sw);
+            e.printStackTrace(pw);
+            fos.write(message.getBytes());
+            fos.write("\n\n".getBytes());
+            fos.write(sw.toString().getBytes());
+            pw.close();
+            sw.close();
+            fos.close();
+        } catch (Throwable t) {
+            // ignore
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/8a18e284/tooling/apt/src/main/java/org/apache/camel/tools/apt/CamelContextAnnotationProcessor.java
----------------------------------------------------------------------
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/CamelContextAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/CamelContextAnnotationProcessor.java
deleted file mode 100644
index f8e6b71..0000000
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/CamelContextAnnotationProcessor.java
+++ /dev/null
@@ -1,720 +0,0 @@
-/**
- * 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.PrintWriter;
-import java.util.Comparator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
-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.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementFilter;
-import javax.lang.model.util.Elements;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementRef;
-import javax.xml.bind.annotation.XmlElements;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
-import org.apache.camel.spi.Metadata;
-import org.apache.camel.tools.apt.helper.JsonSchemaHelper;
-import org.apache.camel.tools.apt.helper.Strings;
-
-import static org.apache.camel.tools.apt.helper.JsonSchemaHelper.sanitizeDescription;
-import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
-import static org.apache.camel.tools.apt.helper.Strings.isNullOrEmpty;
-import static org.apache.camel.tools.apt.helper.Strings.safeNull;
-
-/**
- * Process camel-spring's <camelContext> and generate json schema documentation
- */
-@SupportedAnnotationTypes({"javax.xml.bind.annotation.*", "org.apache.camel.spi.Label"})
-@SupportedSourceVersion(SourceVersion.RELEASE_8)
-public class CamelContextAnnotationProcessor extends AbstractAnnotationProcessor {
-
-    private static final String ONE_OF_TYPE_NAME = "";
-    private boolean skipUnwanted = true;
-
-    @Override
-    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
-        try {
-            if (roundEnv.processingOver()) {
-                return true;
-            }
-
-            Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(XmlRootElement.class);
-            for (Element element : elements) {
-                if (element instanceof TypeElement) {
-                    processModelClass(roundEnv, (TypeElement) element);
-                }
-            }
-        } catch (Throwable e) {
-            dumpExceptionToErrorFile("camel-apt-error.log", "Error processing CamelContext model", e);
-        }
-        return true;
-    }
-
-    protected void processModelClass(final RoundEnvironment roundEnv, final TypeElement classElement) {
-        // must be from camel-spring or camel-core-xml
-        final String javaTypeName = canonicalClassName(classElement.getQualifiedName().toString());
-        String packageName = javaTypeName.substring(0, javaTypeName.lastIndexOf("."));
-        boolean valid = javaTypeName.startsWith("org.apache.camel.spring") || javaTypeName.startsWith("org.apache.camel.core.xml");
-        if (!valid) {
-            return;
-        }
-
-        // skip abstract classes
-        if (classElement.getModifiers().contains(Modifier.ABSTRACT)) {
-            return;
-        }
-
-        // skip unwanted classes which are "abstract" holders
-        if (skipUnwanted) {
-            if (classElement.getQualifiedName().toString().equals(ONE_OF_TYPE_NAME)) {
-                return;
-            }
-        }
-
-        final XmlRootElement rootElement = classElement.getAnnotation(XmlRootElement.class);
-        if (rootElement == null) {
-            return;
-        }
-
-        String aName = rootElement.name();
-        if (isNullOrEmpty(aName) || "##default".equals(aName)) {
-            XmlType typeElement = classElement.getAnnotation(XmlType.class);
-            aName = typeElement.name();
-        }
-        final String name = aName;
-
-        // lets use the xsd name as the file name
-        String fileName;
-        if (isNullOrEmpty(name) || "##default".equals(name)) {
-            fileName = classElement.getSimpleName().toString() + ".json";
-        } else {
-            fileName = name + ".json";
-        }
-
-        // write json schema
-        Func1<PrintWriter, Void> handler = new Func1<PrintWriter, Void>() {
-            @Override
-            public Void call(PrintWriter writer) {
-                writeJSonSchemeDocumentation(writer, roundEnv, classElement, rootElement, javaTypeName, name);
-                return null;
-            }
-        };
-        processFile(packageName, fileName, handler);
-    }
-
-    protected void writeJSonSchemeDocumentation(PrintWriter writer, RoundEnvironment roundEnv, TypeElement classElement, XmlRootElement rootElement,
-                                                String javaTypeName, String modelName) {
-        // gather eip information
-        EipModel eipModel = findEipModelProperties(roundEnv, classElement, javaTypeName, modelName);
-
-        // collect eip information
-        Set<EipOption> eipOptions = new TreeSet<EipOption>(new EipOptionComparator(eipModel));
-        findClassProperties(writer, roundEnv, eipOptions, classElement, classElement, "", modelName);
-
-        String json = createParameterJsonSchema(eipModel, eipOptions);
-        writer.println(json);
-    }
-
-    public String createParameterJsonSchema(EipModel eipModel, Set<EipOption> options) {
-        StringBuilder buffer = new StringBuilder("{");
-        // eip model
-        buffer.append("\n \"model\": {");
-        buffer.append("\n    \"kind\": \"").append("model").append("\",");
-        buffer.append("\n    \"name\": \"").append(eipModel.getName()).append("\",");
-        if (eipModel.getTitle() != null) {
-            buffer.append("\n    \"title\": \"").append(eipModel.getTitle()).append("\",");
-        } else {
-            // fallback and use name as title
-            buffer.append("\n    \"title\": \"").append(asTitle(eipModel.getName())).append("\",");
-        }
-        buffer.append("\n    \"description\": \"").append(safeNull(eipModel.getDescription())).append("\",");
-        buffer.append("\n    \"javaType\": \"").append(eipModel.getJavaType()).append("\",");
-        buffer.append("\n    \"label\": \"").append(safeNull(eipModel.getLabel())).append("\"");
-        buffer.append("\n  },");
-
-        buffer.append("\n  \"properties\": {");
-        boolean first = true;
-        for (EipOption entry : options) {
-            if (first) {
-                first = false;
-            } else {
-                buffer.append(",");
-            }
-            buffer.append("\n    ");
-            // as its json we need to sanitize the docs
-            String doc = entry.getDocumentation();
-            doc = sanitizeDescription(doc, false);
-            buffer.append(JsonSchemaHelper.toJson(entry.getName(), entry.getKind(), entry.isRequired(), entry.getType(), entry.getDefaultValue(), doc,
-                    entry.isDeprecated(), false, null, null, entry.isEnumType(), entry.getEnums(), entry.isOneOf(), entry.getOneOfTypes(), null, null, false));
-        }
-        buffer.append("\n  }");
-
-        buffer.append("\n}\n");
-        return buffer.toString();
-    }
-
-    protected EipModel findEipModelProperties(RoundEnvironment roundEnv, TypeElement classElement, String javaTypeName, String name) {
-        EipModel model = new EipModel();
-        model.setJavaType(javaTypeName);
-        model.setName(name);
-
-        Metadata metadata = classElement.getAnnotation(Metadata.class);
-        if (metadata != null) {
-            if (!Strings.isNullOrEmpty(metadata.label())) {
-                model.setLabel(metadata.label());
-            }
-            if (!Strings.isNullOrEmpty(metadata.title())) {
-                model.setTitle(metadata.title());
-            }
-        }
-
-        // favor to use class javadoc of component as description
-        if (model.getJavaType() != null) {
-            Elements elementUtils = processingEnv.getElementUtils();
-            TypeElement typeElement = findTypeElement(roundEnv, model.getJavaType());
-            if (typeElement != null) {
-                String doc = elementUtils.getDocComment(typeElement);
-                if (doc != null) {
-                    // need to sanitize the description first (we only want a summary)
-                    doc = sanitizeDescription(doc, true);
-                    // the javadoc may actually be empty, so only change the doc if we got something
-                    if (!Strings.isNullOrEmpty(doc)) {
-                        model.setDescription(doc);
-                    }
-                }
-            }
-        }
-
-        return model;
-    }
-
-    protected void findClassProperties(PrintWriter writer, RoundEnvironment roundEnv, Set<EipOption> eipOptions,
-                                       TypeElement originalClassType, TypeElement classElement, String prefix, String modelName) {
-        while (true) {
-            List<VariableElement> fieldElements = ElementFilter.fieldsIn(classElement.getEnclosedElements());
-            for (VariableElement fieldElement : fieldElements) {
-
-                String fieldName = fieldElement.getSimpleName().toString();
-
-                XmlAttribute attribute = fieldElement.getAnnotation(XmlAttribute.class);
-                if (attribute != null) {
-                    boolean skip = processAttribute(roundEnv, originalClassType, classElement, fieldElement, fieldName, attribute, eipOptions, prefix, modelName);
-                    if (skip) {
-                        continue;
-                    }
-                }
-
-                XmlElements elements = fieldElement.getAnnotation(XmlElements.class);
-                if (elements != null) {
-                    processElements(roundEnv, classElement, elements, fieldElement, eipOptions, prefix);
-                }
-
-                XmlElementRef elementRef = fieldElement.getAnnotation(XmlElementRef.class);
-                if (elementRef != null) {
-                    processElement(roundEnv, classElement, null, elementRef, fieldElement, eipOptions, prefix);
-                }
-
-                XmlElement element = fieldElement.getAnnotation(XmlElement.class);
-                if (element != null) {
-                    if ("rests".equals(fieldName)) {
-                        processRests(roundEnv, classElement, element, fieldElement, fieldName, eipOptions, prefix);
-                    } else if ("routes".equals(fieldName)) {
-                        processRoutes(roundEnv, classElement, element, fieldElement, fieldName, eipOptions, prefix);
-                    } else {
-                        processElement(roundEnv, classElement, element, null, fieldElement, eipOptions, prefix);
-                    }
-                }
-            }
-
-            // check super classes which may also have fields
-            TypeElement baseTypeElement = null;
-            TypeMirror superclass = classElement.getSuperclass();
-            if (superclass != null) {
-                String superClassName = canonicalClassName(superclass.toString());
-                baseTypeElement = findTypeElement(roundEnv, superClassName);
-            }
-            if (baseTypeElement != null) {
-                classElement = baseTypeElement;
-            } else {
-                break;
-            }
-        }
-    }
-
-    private boolean processAttribute(RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement classElement, VariableElement fieldElement,
-                                     String fieldName, XmlAttribute attribute, Set<EipOption> eipOptions, String prefix, String modelName) {
-        Elements elementUtils = processingEnv.getElementUtils();
-
-        String name = attribute.name();
-        if (isNullOrEmpty(name) || "##default".equals(name)) {
-            name = fieldName;
-        }
-
-        // lets skip some unwanted attributes
-        if (skipUnwanted) {
-        }
-
-        name = prefix + name;
-        TypeMirror fieldType = fieldElement.asType();
-        String fieldTypeName = fieldType.toString();
-        TypeElement fieldTypeElement = findTypeElement(roundEnv, fieldTypeName);
-
-        String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
-        String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true);
-        if (isNullOrEmpty(docComment)) {
-            Metadata metadata = fieldElement.getAnnotation(Metadata.class);
-            docComment = metadata != null ? metadata.description() : null;
-        }
-        boolean required = attribute.required();
-        // metadata may overrule element required
-        required = findRequired(fieldElement, required);
-
-        // gather enums
-        Set<String> enums = new TreeSet<String>();
-        boolean isEnum = fieldTypeElement != null && fieldTypeElement.getKind() == ElementKind.ENUM;
-        if (isEnum) {
-            TypeElement enumClass = findTypeElement(roundEnv, fieldTypeElement.asType().toString());
-            // find all the enum constants which has the possible enum value that can be used
-            List<VariableElement> fields = ElementFilter.fieldsIn(enumClass.getEnclosedElements());
-            for (VariableElement var : fields) {
-                if (var.getKind() == ElementKind.ENUM_CONSTANT) {
-                    String val = var.toString();
-                    enums.add(val);
-                }
-            }
-        }
-
-        boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null;
-
-        // special for id as its inherited from camel-core
-        if ("id".equals(name) && isNullOrEmpty(docComment)) {
-            if ("CamelContextFactoryBean".equals(originalClassType.getSimpleName().toString())) {
-                docComment = "Sets the id (name) of this CamelContext";
-            } else {
-                docComment = "Sets the id of this node";
-            }
-        }
-
-        EipOption ep = new EipOption(name, "attribute", fieldTypeName, required, defaultValue, docComment, deprecated, isEnum, enums, false, null);
-        eipOptions.add(ep);
-
-        return false;
-    }
-
-    /**
-     * Special for processing an @XmlElement routes field
-     */
-    private void processRoutes(RoundEnvironment roundEnv, TypeElement originalClassType, XmlElement element,
-                               VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) {
-
-        TypeMirror fieldType = fieldElement.asType();
-        String fieldTypeName = fieldType.toString();
-
-        Set<String> oneOfTypes = new TreeSet<String>();
-        oneOfTypes.add("route");
-
-        EipOption ep = new EipOption("route", "element", fieldTypeName, false, "", "Contains the Camel routes", false, false, null, true, oneOfTypes);
-        eipOptions.add(ep);
-    }
-
-    /**
-     * Special for processing an @XmlElement rests field
-     */
-    private void processRests(RoundEnvironment roundEnv, TypeElement originalClassType, XmlElement element,
-                              VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) {
-
-        TypeMirror fieldType = fieldElement.asType();
-        String fieldTypeName = fieldType.toString();
-
-        Set<String> oneOfTypes = new TreeSet<String>();
-        oneOfTypes.add("rest");
-
-        EipOption ep = new EipOption("rest", "element", fieldTypeName, false, "", "Contains the rest services defined using the rest-dsl", false, false, null, true, oneOfTypes);
-        eipOptions.add(ep);
-    }
-
-    private void processElement(RoundEnvironment roundEnv, TypeElement classElement, XmlElement element, XmlElementRef elementRef, VariableElement fieldElement,
-                                Set<EipOption> eipOptions, String prefix) {
-        Elements elementUtils = processingEnv.getElementUtils();
-
-        String fieldName;
-        fieldName = fieldElement.getSimpleName().toString();
-        if (element != null || elementRef != null) {
-
-            String kind = "element";
-            String name = element != null ? element.name() : elementRef.name();
-            if (isNullOrEmpty(name) || "##default".equals(name)) {
-                name = fieldName;
-            }
-            name = prefix + name;
-            TypeMirror fieldType = fieldElement.asType();
-            String fieldTypeName = fieldType.toString();
-            TypeElement fieldTypeElement = findTypeElement(roundEnv, fieldTypeName);
-
-            String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
-            String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true);
-            if (isNullOrEmpty(docComment)) {
-                Metadata metadata = fieldElement.getAnnotation(Metadata.class);
-                docComment = metadata != null ? metadata.description() : null;
-            }
-            boolean required = element != null ? element.required() : elementRef.required();
-            // metadata may overrule element required
-            required = findRequired(fieldElement, required);
-
-            // gather enums
-            Set<String> enums = new LinkedHashSet<String>();
-            boolean isEnum = fieldTypeElement != null && fieldTypeElement.getKind() == ElementKind.ENUM;
-            if (isEnum) {
-                TypeElement enumClass = findTypeElement(roundEnv, fieldTypeElement.asType().toString());
-                // find all the enum constants which has the possible enum value that can be used
-                List<VariableElement> fields = ElementFilter.fieldsIn(enumClass.getEnclosedElements());
-                for (VariableElement var : fields) {
-                    if (var.getKind() == ElementKind.ENUM_CONSTANT) {
-                        String val = var.toString();
-                        enums.add(val);
-                    }
-                }
-            }
-
-            // is it a definition/factory-bean type then its a oneOf
-            TreeSet oneOfTypes = new TreeSet<String>();
-            if (fieldTypeName.endsWith("Definition") || fieldTypeName.endsWith("FactoryBean")) {
-                TypeElement definitionClass = findTypeElement(roundEnv, fieldTypeElement.asType().toString());
-                if (definitionClass != null) {
-                    XmlRootElement rootElement = definitionClass.getAnnotation(XmlRootElement.class);
-                    if (rootElement != null) {
-                        String childName = rootElement.name();
-                        if (childName != null) {
-                            oneOfTypes.add(childName);
-                        }
-                    }
-                }
-            } else if (fieldTypeName.endsWith("Definition>") || fieldTypeName.endsWith("FactoryBean>")) {
-                // its a list so we need to load the generic type
-                String typeName = Strings.between(fieldTypeName, "<", ">");
-                TypeElement definitionClass = findTypeElement(roundEnv, typeName);
-                if (definitionClass != null) {
-                    XmlRootElement rootElement = definitionClass.getAnnotation(XmlRootElement.class);
-                    if (rootElement != null) {
-                        String childName = rootElement.name();
-                        if (childName != null) {
-                            oneOfTypes.add(childName);
-                        }
-                    }
-                }
-            }
-            boolean oneOf = !oneOfTypes.isEmpty();
-
-            boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null;
-
-            EipOption ep = new EipOption(name, kind, fieldTypeName, required, defaultValue, docComment, deprecated, isEnum, enums, oneOf, oneOfTypes);
-            eipOptions.add(ep);
-        }
-    }
-
-    private void processElements(RoundEnvironment roundEnv, TypeElement classElement, XmlElements elements, VariableElement fieldElement,
-                                 Set<EipOption> eipOptions, String prefix) {
-        Elements elementUtils = processingEnv.getElementUtils();
-
-        String fieldName;
-        fieldName = fieldElement.getSimpleName().toString();
-        if (elements != null) {
-            String kind = "element";
-            String name = fieldName;
-            name = prefix + name;
-
-            TypeMirror fieldType = fieldElement.asType();
-            String fieldTypeName = fieldType.toString();
-
-            String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
-            String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true);
-            if (isNullOrEmpty(docComment)) {
-                Metadata metadata = fieldElement.getAnnotation(Metadata.class);
-                docComment = metadata != null ? metadata.description() : null;
-            }
-            boolean required = false;
-            required = findRequired(fieldElement, required);
-
-            // gather oneOf of the elements
-            Set<String> oneOfTypes = new TreeSet<String>();
-            for (XmlElement element : elements.value()) {
-                String child = element.name();
-                oneOfTypes.add(child);
-            }
-
-            EipOption ep = new EipOption(name, kind, fieldTypeName, required, defaultValue, docComment, false, false, null, true, oneOfTypes);
-            eipOptions.add(ep);
-        }
-    }
-
-    private String findDefaultValue(VariableElement fieldElement, String fieldTypeName) {
-        String defaultValue = null;
-        Metadata metadata = fieldElement.getAnnotation(Metadata.class);
-        if (metadata != null) {
-            if (!Strings.isNullOrEmpty(metadata.defaultValue())) {
-                defaultValue = metadata.defaultValue();
-            }
-        }
-        if (defaultValue == null) {
-            // if its a boolean type, then we use false as the default
-            if ("boolean".equals(fieldTypeName) || "java.lang.Boolean".equals(fieldTypeName)) {
-                defaultValue = "false";
-            }
-        }
-
-        return defaultValue;
-    }
-
-    private boolean findRequired(VariableElement fieldElement, boolean defaultValue) {
-        Metadata metadata = fieldElement.getAnnotation(Metadata.class);
-        if (metadata != null) {
-            if (!Strings.isNullOrEmpty(metadata.required())) {
-                defaultValue = "true".equals(metadata.required());
-            }
-        }
-        return defaultValue;
-    }
-
-    /**
-     * Capitializes the name as a title
-     *
-     * @param name  the name
-     * @return as a title
-     */
-    private static String asTitle(String name) {
-        StringBuilder sb = new StringBuilder();
-        for (char c : name.toCharArray()) {
-            boolean upper = Character.isUpperCase(c);
-            boolean first = sb.length() == 0;
-            if (first) {
-                sb.append(Character.toUpperCase(c));
-            } else if (upper) {
-                sb.append(' ');
-                sb.append(c);
-            } else {
-                sb.append(Character.toLowerCase(c));
-            }
-        }
-        return sb.toString().trim();
-    }
-
-    private static final class EipModel {
-
-        private String name;
-        private String title;
-        private String javaType;
-        private String label;
-        private String description;
-
-        public String getName() {
-            return name;
-        }
-
-        public void setName(String name) {
-            this.name = name;
-        }
-
-        public String getTitle() {
-            return title;
-        }
-
-        public void setTitle(String title) {
-            this.title = title;
-        }
-
-        public String getJavaType() {
-            return javaType;
-        }
-
-        public void setJavaType(String javaType) {
-            this.javaType = javaType;
-        }
-
-        public String getLabel() {
-            return label;
-        }
-
-        public void setLabel(String label) {
-            this.label = label;
-        }
-
-        public String getDescription() {
-            return description;
-        }
-
-        public void setDescription(String description) {
-            this.description = description;
-        }
-
-    }
-
-    private static final class EipOption {
-
-        private String name;
-        private String kind;
-        private String type;
-        private boolean required;
-        private String defaultValue;
-        private String documentation;
-        private boolean deprecated;
-        private boolean enumType;
-        private Set<String> enums;
-        private boolean oneOf;
-        private Set<String> oneOfTypes;
-
-        private EipOption(String name, String kind, String type, boolean required, String defaultValue, String documentation, boolean deprecated,
-                          boolean enumType, Set<String> enums, boolean oneOf, Set<String> oneOfTypes) {
-            this.name = name;
-            this.kind = kind;
-            this.type = type;
-            this.required = required;
-            this.defaultValue = defaultValue;
-            this.documentation = documentation;
-            this.deprecated = deprecated;
-            this.enumType = enumType;
-            this.enums = enums;
-            this.oneOf = oneOf;
-            this.oneOfTypes = oneOfTypes;
-        }
-
-        public String getName() {
-            return name;
-        }
-
-        public String getKind() {
-            return kind;
-        }
-
-        public String getType() {
-            return type;
-        }
-
-        public boolean isRequired() {
-            return required;
-        }
-
-        public String getDefaultValue() {
-            return defaultValue;
-        }
-
-        public String getDocumentation() {
-            return documentation;
-        }
-
-        public boolean isDeprecated() {
-            return deprecated;
-        }
-
-        public boolean isEnumType() {
-            return enumType;
-        }
-
-        public Set<String> getEnums() {
-            return enums;
-        }
-
-        public boolean isOneOf() {
-            return oneOf;
-        }
-
-        public Set<String> getOneOfTypes() {
-            return oneOfTypes;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-            if (o == null || getClass() != o.getClass()) {
-                return false;
-            }
-
-            EipOption that = (EipOption) o;
-
-            if (!name.equals(that.name)) {
-                return false;
-            }
-
-            return true;
-        }
-
-        @Override
-        public int hashCode() {
-            return name.hashCode();
-        }
-    }
-
-    private static final class EipOptionComparator implements Comparator<EipOption> {
-
-        private final EipModel model;
-
-        private EipOptionComparator(EipModel model) {
-            this.model = model;
-        }
-
-        @Override
-        public int compare(EipOption o1, EipOption o2) {
-            int weigth = weigth(o1);
-            int weigth2 = weigth(o2);
-
-            if (weigth == weigth2) {
-                // keep the current order
-                return 1;
-            } else {
-                // sort according to weight
-                return weigth2 - weigth;
-            }
-        }
-
-        private int weigth(EipOption o) {
-            String name = o.getName();
-
-            // these should be first
-            if ("expression".equals(name)) {
-                return 10;
-            }
-
-            // these should be last
-            if ("description".equals(name)) {
-                return -10;
-            } else if ("id".equals(name)) {
-                return -9;
-            } else if ("pattern".equals(name) && "to".equals(model.getName())) {
-                // and pattern only for the to model
-                return -8;
-            }
-            return 0;
-        }
-    }
-
-}


[2/4] camel git commit: CAMEL-9482: Adjust the apt to make camel-core compile again, seems like we need to merge the core/spring into a single apt as the compiler cannot do both on camel-core for some odd reason.

Posted by da...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/8a18e284/tooling/apt/src/main/java/org/apache/camel/tools/apt/EipAnnotationProcessor.java
----------------------------------------------------------------------
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EipAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EipAnnotationProcessor.java
deleted file mode 100644
index 253e37f..0000000
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EipAnnotationProcessor.java
+++ /dev/null
@@ -1,1148 +0,0 @@
-/**
- * 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.PrintWriter;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
-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.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementFilter;
-import javax.lang.model.util.Elements;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementRef;
-import javax.xml.bind.annotation.XmlElements;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-import org.apache.camel.spi.Metadata;
-import org.apache.camel.tools.apt.helper.JsonSchemaHelper;
-import org.apache.camel.tools.apt.helper.Strings;
-
-import static org.apache.camel.tools.apt.helper.JsonSchemaHelper.sanitizeDescription;
-import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
-import static org.apache.camel.tools.apt.helper.Strings.isNullOrEmpty;
-import static org.apache.camel.tools.apt.helper.Strings.safeNull;
-
-/**
- * Process all camel-core's model classes (EIPs and DSL) and generate json schema documentation
- */
-@SupportedAnnotationTypes({"javax.xml.bind.annotation.*", "org.apache.camel.spi.Label"})
-@SupportedSourceVersion(SourceVersion.RELEASE_8)
-public class EipAnnotationProcessor extends AbstractAnnotationProcessor {
-
-    // special when using expression/predicates in the model
-    private static final String ONE_OF_TYPE_NAME = "org.apache.camel.model.ExpressionSubElementDefinition";
-    private static final String[] ONE_OF_LANGUAGES = new String[]{
-        "org.apache.camel.model.language.ExpressionDefinition",
-        "org.apache.camel.model.language.NamespaceAwareExpression"
-    };
-    // special for inputs (these classes have sub classes, so we use this to find all classes)
-    private static final String[] ONE_OF_INPUTS = new String[]{
-        "org.apache.camel.model.ProcessorDefinition",
-        "org.apache.camel.model.VerbDefinition"
-    };
-    // special for outputs (these classes have sub classes, so we use this to find all classes)
-    private static final String[] ONE_OF_OUTPUTS = new String[]{
-        "org.apache.camel.model.ProcessorDefinition",
-        "org.apache.camel.model.NoOutputDefinition",
-        "org.apache.camel.model.OutputDefinition",
-        "org.apache.camel.model.ExpressionNode",
-        "org.apache.camel.model.NoOutputExpressionNode",
-        "org.apache.camel.model.SendDefinition",
-        "org.apache.camel.model.InterceptDefinition",
-        "org.apache.camel.model.WhenDefinition",
-        "org.apache.camel.model.ToDynamicDefinition"
-    };
-    // special for verbs (these classes have sub classes, so we use this to find all classes)
-    private static final String[] ONE_OF_VERBS = new String[]{
-        "org.apache.camel.model.rest.VerbDefinition"
-    };
-
-    private boolean skipUnwanted = true;
-
-    @Override
-    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
-        try {
-            if (roundEnv.processingOver()) {
-                return true;
-            }
-
-            Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(XmlRootElement.class);
-            for (Element element : elements) {
-                if (element instanceof TypeElement) {
-                    processModelClass(roundEnv, (TypeElement) element);
-                }
-            }
-        } catch (Throwable e) {
-            dumpExceptionToErrorFile("camel-apt-error.log", "Error processing EIP model", e);
-        }
-        return true;
-    }
-
-    protected void processModelClass(final RoundEnvironment roundEnv, final TypeElement classElement) {
-        // must be from org.apache.camel.model
-        final String javaTypeName = canonicalClassName(classElement.getQualifiedName().toString());
-        String packageName = javaTypeName.substring(0, javaTypeName.lastIndexOf("."));
-        if (!javaTypeName.startsWith("org.apache.camel.model")) {
-            return;
-        }
-
-        // skip abstract classes
-        if (classElement.getModifiers().contains(Modifier.ABSTRACT)) {
-            return;
-        }
-
-        // skip unwanted classes which are "abstract" holders
-        if (skipUnwanted) {
-            if (classElement.getQualifiedName().toString().equals(ONE_OF_TYPE_NAME)) {
-                return;
-            }
-        }
-
-        final XmlRootElement rootElement = classElement.getAnnotation(XmlRootElement.class);
-        if (rootElement == null) {
-            return;
-        }
-
-        String aName = rootElement.name();
-        if (isNullOrEmpty(aName) || "##default".equals(aName)) {
-            XmlType typeElement = classElement.getAnnotation(XmlType.class);
-            aName = typeElement.name();
-        }
-        final String name = aName;
-
-        // lets use the xsd name as the file name
-        String fileName;
-        if (isNullOrEmpty(name) || "##default".equals(name)) {
-            fileName = classElement.getSimpleName().toString() + ".json";
-        } else {
-            fileName = name + ".json";
-        }
-
-        // write json schema
-        Func1<PrintWriter, Void> handler = new Func1<PrintWriter, Void>() {
-            @Override
-            public Void call(PrintWriter writer) {
-                writeJSonSchemeDocumentation(writer, roundEnv, classElement, rootElement, javaTypeName, name);
-                return null;
-            }
-        };
-        processFile(packageName, fileName, handler);
-    }
-
-    protected void writeJSonSchemeDocumentation(PrintWriter writer, RoundEnvironment roundEnv, TypeElement classElement, XmlRootElement rootElement,
-                                                String javaTypeName, String modelName) {
-        // gather eip information
-        EipModel eipModel = findEipModelProperties(roundEnv, classElement, javaTypeName, modelName);
-
-        // get endpoint information which is divided into paths and options (though there should really only be one path)
-        Set<EipOption> eipOptions = new TreeSet<EipOption>(new EipOptionComparator(eipModel));
-        findClassProperties(writer, roundEnv, eipOptions, classElement, classElement, "", modelName);
-
-        // after we have found all the options then figure out if the model accepts input/output
-        eipModel.setInput(hasInput(roundEnv, classElement));
-        eipModel.setOutput(hasOutput(eipModel, eipOptions));
-
-        String json = createParameterJsonSchema(eipModel, eipOptions);
-        writer.println(json);
-    }
-
-    public String createParameterJsonSchema(EipModel eipModel, Set<EipOption> options) {
-        StringBuilder buffer = new StringBuilder("{");
-        // eip model
-        buffer.append("\n \"model\": {");
-        buffer.append("\n    \"kind\": \"").append("model").append("\",");
-        buffer.append("\n    \"name\": \"").append(eipModel.getName()).append("\",");
-        if (eipModel.getTitle() != null) {
-            buffer.append("\n    \"title\": \"").append(eipModel.getTitle()).append("\",");
-        } else {
-            // fallback and use name as title
-            buffer.append("\n    \"title\": \"").append(asTitle(eipModel.getName())).append("\",");
-        }
-        buffer.append("\n    \"description\": \"").append(safeNull(eipModel.getDescription())).append("\",");
-        buffer.append("\n    \"javaType\": \"").append(eipModel.getJavaType()).append("\",");
-        buffer.append("\n    \"label\": \"").append(safeNull(eipModel.getLabel())).append("\",");
-        buffer.append("\n    \"input\": \"").append(eipModel.getInput()).append("\",");
-        buffer.append("\n    \"output\": \"").append(eipModel.getOutput()).append("\"");
-        buffer.append("\n  },");
-
-        buffer.append("\n  \"properties\": {");
-        boolean first = true;
-        for (EipOption entry : options) {
-            if (first) {
-                first = false;
-            } else {
-                buffer.append(",");
-            }
-            buffer.append("\n    ");
-            // as its json we need to sanitize the docs
-            String doc = entry.getDocumentation();
-            doc = sanitizeDescription(doc, false);
-            buffer.append(JsonSchemaHelper.toJson(entry.getName(), entry.getKind(), entry.isRequired(), entry.getType(), entry.getDefaultValue(), doc,
-                    entry.isDeprecated(), false, null, null, entry.isEnumType(), entry.getEnums(), entry.isOneOf(), entry.getOneOfTypes(), null, null, false));
-        }
-        buffer.append("\n  }");
-
-        buffer.append("\n}\n");
-        return buffer.toString();
-    }
-
-    protected EipModel findEipModelProperties(RoundEnvironment roundEnv, TypeElement classElement, String javaTypeName, String name) {
-        EipModel model = new EipModel();
-        model.setJavaType(javaTypeName);
-        model.setName(name);
-
-        Metadata metadata = classElement.getAnnotation(Metadata.class);
-        if (metadata != null) {
-            if (!Strings.isNullOrEmpty(metadata.label())) {
-                model.setLabel(metadata.label());
-            }
-            if (!Strings.isNullOrEmpty(metadata.title())) {
-                model.setTitle(metadata.title());
-            }
-        }
-
-        // favor to use class javadoc of component as description
-        if (model.getJavaType() != null) {
-            Elements elementUtils = processingEnv.getElementUtils();
-            TypeElement typeElement = findTypeElement(roundEnv, model.getJavaType());
-            if (typeElement != null) {
-                String doc = elementUtils.getDocComment(typeElement);
-                if (doc != null) {
-                    // need to sanitize the description first (we only want a summary)
-                    doc = sanitizeDescription(doc, true);
-                    // the javadoc may actually be empty, so only change the doc if we got something
-                    if (!Strings.isNullOrEmpty(doc)) {
-                        model.setDescription(doc);
-                    }
-                }
-            }
-        }
-
-        return model;
-    }
-
-    protected void findClassProperties(PrintWriter writer, RoundEnvironment roundEnv, Set<EipOption> eipOptions,
-                                       TypeElement originalClassType, TypeElement classElement, String prefix, String modelName) {
-        while (true) {
-            List<VariableElement> fieldElements = ElementFilter.fieldsIn(classElement.getEnclosedElements());
-            for (VariableElement fieldElement : fieldElements) {
-
-                String fieldName = fieldElement.getSimpleName().toString();
-
-                XmlAttribute attribute = fieldElement.getAnnotation(XmlAttribute.class);
-                if (attribute != null) {
-                    boolean skip = processAttribute(roundEnv, originalClassType, classElement, fieldElement, fieldName, attribute, eipOptions, prefix, modelName);
-                    if (skip) {
-                        continue;
-                    }
-                }
-
-                XmlValue value = fieldElement.getAnnotation(XmlValue.class);
-                if (value != null) {
-                    processValue(roundEnv, originalClassType, classElement, fieldElement, fieldName, value, eipOptions, prefix, modelName);
-                }
-
-                XmlElements elements = fieldElement.getAnnotation(XmlElements.class);
-                if (elements != null) {
-                    processElements(roundEnv, classElement, elements, fieldElement, eipOptions, prefix);
-                }
-
-                XmlElement element = fieldElement.getAnnotation(XmlElement.class);
-                if (element != null) {
-                    processElement(roundEnv, classElement, element, fieldElement, eipOptions, prefix);
-                }
-
-                // special for eips which has outputs or requires an expressions
-                XmlElementRef elementRef = fieldElement.getAnnotation(XmlElementRef.class);
-                if (elementRef != null) {
-
-                    // special for routes
-                    processRoutes(roundEnv, originalClassType, elementRef, fieldElement, fieldName, eipOptions, prefix);
-
-                    // special for outputs
-                    processOutputs(roundEnv, originalClassType, elementRef, fieldElement, fieldName, eipOptions, prefix);
-
-                    // special for when clauses (choice eip)
-                    processRefWhenClauses(roundEnv, originalClassType, elementRef, fieldElement, fieldName, eipOptions, prefix);
-
-                    // special for rests (rest-dsl)
-                    processRests(roundEnv, originalClassType, elementRef, fieldElement, fieldName, eipOptions, prefix);
-
-                    // special for verbs (rest-dsl)
-                    processVerbs(roundEnv, originalClassType, elementRef, fieldElement, fieldName, eipOptions, prefix);
-
-                    // special for expression
-                    processRefExpression(roundEnv, originalClassType, classElement, elementRef, fieldElement, fieldName, eipOptions, prefix);
-
-                }
-            }
-
-            // special when we process these nodes as they do not use JAXB annotations on fields, but on methods
-            if ("OptionalIdentifiedDefinition".equals(classElement.getSimpleName().toString())) {
-                processIdentified(roundEnv, originalClassType, classElement, eipOptions, prefix);
-            } else if ("RouteDefinition".equals(classElement.getSimpleName().toString())) {
-                processRoute(roundEnv, originalClassType, classElement, eipOptions, prefix);
-            }
-
-            // check super classes which may also have fields
-            TypeElement baseTypeElement = null;
-            TypeMirror superclass = classElement.getSuperclass();
-            if (superclass != null) {
-                String superClassName = canonicalClassName(superclass.toString());
-                baseTypeElement = findTypeElement(roundEnv, superClassName);
-            }
-            if (baseTypeElement != null) {
-                classElement = baseTypeElement;
-            } else {
-                break;
-            }
-        }
-    }
-
-    private boolean processAttribute(RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement classElement, VariableElement fieldElement,
-                                     String fieldName, XmlAttribute attribute, Set<EipOption> eipOptions, String prefix, String modelName) {
-        Elements elementUtils = processingEnv.getElementUtils();
-
-        String name = attribute.name();
-        if (isNullOrEmpty(name) || "##default".equals(name)) {
-            name = fieldName;
-        }
-
-        // lets skip some unwanted attributes
-        if (skipUnwanted) {
-            // we want to skip inheritErrorHandler which is only applicable for the load-balancer
-            boolean loadBalancer = "LoadBalanceDefinition".equals(originalClassType.getSimpleName().toString());
-            if (!loadBalancer && "inheritErrorHandler".equals(name)) {
-                return true;
-            }
-        }
-
-        name = prefix + name;
-        TypeMirror fieldType = fieldElement.asType();
-        String fieldTypeName = fieldType.toString();
-        TypeElement fieldTypeElement = findTypeElement(roundEnv, fieldTypeName);
-
-        String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
-        String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true);
-        boolean required = attribute.required();
-        // metadata may overrule element required
-        required = findRequired(fieldElement, required);
-
-        // gather enums
-        Set<String> enums = new TreeSet<String>();
-        boolean isEnum = fieldTypeElement != null && fieldTypeElement.getKind() == ElementKind.ENUM;
-        if (isEnum) {
-            TypeElement enumClass = findTypeElement(roundEnv, fieldTypeElement.asType().toString());
-            // find all the enum constants which has the possible enum value that can be used
-            List<VariableElement> fields = ElementFilter.fieldsIn(enumClass.getEnclosedElements());
-            for (VariableElement var : fields) {
-                if (var.getKind() == ElementKind.ENUM_CONSTANT) {
-                    String val = var.toString();
-                    enums.add(val);
-                }
-            }
-        }
-
-        boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null;
-
-        EipOption ep = new EipOption(name, "attribute", fieldTypeName, required, defaultValue, docComment, deprecated, isEnum, enums, false, null);
-        eipOptions.add(ep);
-
-        return false;
-    }
-
-    private void processValue(RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement classElement, VariableElement fieldElement, String fieldName, XmlValue value,
-        Set<EipOption> eipOptions, String prefix, String modelName) {
-        Elements elementUtils = processingEnv.getElementUtils();
-
-        // XmlValue has no name attribute
-        String name = fieldName;
-
-        if ("method".equals(modelName) || "tokenize".equals(modelName) || "xtokenize".equals(modelName)) {
-            // skip expression attribute on these three languages as they are solely configured using attributes
-            if ("expression".equals(name)) {
-                return;
-            }
-        }
-
-        name = prefix + name;
-        TypeMirror fieldType = fieldElement.asType();
-        String fieldTypeName = fieldType.toString();
-
-        String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
-        String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true);
-        boolean required = true;
-        // metadata may overrule element required
-        required = findRequired(fieldElement, required);
-
-        boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null;
-
-        EipOption ep = new EipOption(name, "value", fieldTypeName, required, defaultValue, docComment, deprecated, false, null, false, null);
-        eipOptions.add(ep);
-    }
-
-    private void processElement(RoundEnvironment roundEnv, TypeElement classElement, XmlElement element, VariableElement fieldElement,
-                                Set<EipOption> eipOptions, String prefix) {
-        Elements elementUtils = processingEnv.getElementUtils();
-
-        String fieldName;
-        fieldName = fieldElement.getSimpleName().toString();
-        if (element != null) {
-
-            String kind = "element";
-            String name = element.name();
-            if (isNullOrEmpty(name) || "##default".equals(name)) {
-                name = fieldName;
-            }
-            name = prefix + name;
-            TypeMirror fieldType = fieldElement.asType();
-            String fieldTypeName = fieldType.toString();
-            TypeElement fieldTypeElement = findTypeElement(roundEnv, fieldTypeName);
-
-            String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
-            String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true);
-            boolean required = element.required();
-            // metadata may overrule element required
-            required = findRequired(fieldElement, required);
-
-            // gather enums
-            Set<String> enums = new LinkedHashSet<String>();
-            boolean isEnum = fieldTypeElement != null && fieldTypeElement.getKind() == ElementKind.ENUM;
-            if (isEnum) {
-                TypeElement enumClass = findTypeElement(roundEnv, fieldTypeElement.asType().toString());
-                // find all the enum constants which has the possible enum value that can be used
-                List<VariableElement> fields = ElementFilter.fieldsIn(enumClass.getEnclosedElements());
-                for (VariableElement var : fields) {
-                    if (var.getKind() == ElementKind.ENUM_CONSTANT) {
-                        String val = var.toString();
-                        enums.add(val);
-                    }
-                }
-            }
-
-            // gather oneOf expression/predicates which uses language
-            Set<String> oneOfTypes = new TreeSet<String>();
-            boolean isOneOf = ONE_OF_TYPE_NAME.equals(fieldTypeName);
-            if (isOneOf) {
-                // okay its actually an language expression, so favor using that in the eip option
-                kind = "expression";
-                for (String language : ONE_OF_LANGUAGES) {
-                    fieldTypeName = language;
-                    TypeElement languages = findTypeElement(roundEnv, language);
-                    String superClassName = canonicalClassName(languages.toString());
-                    // find all classes that has that superClassName
-                    Set<TypeElement> children = new LinkedHashSet<TypeElement>();
-                    findTypeElementChildren(roundEnv, children, superClassName);
-                    for (TypeElement child : children) {
-                        XmlRootElement rootElement = child.getAnnotation(XmlRootElement.class);
-                        if (rootElement != null) {
-                            String childName = rootElement.name();
-                            if (childName != null) {
-                                oneOfTypes.add(childName);
-                            }
-                        }
-                    }
-                }
-            }
-            // special for otherwise as we want to indicate that the element is
-            if ("otherwise".equals(name)) {
-                isOneOf = true;
-                oneOfTypes.add("otherwise");
-            }
-
-            boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null;
-
-            EipOption ep = new EipOption(name, kind, fieldTypeName, required, defaultValue, docComment, deprecated, isEnum, enums, isOneOf, oneOfTypes);
-            eipOptions.add(ep);
-        }
-    }
-
-    private void processElements(RoundEnvironment roundEnv, TypeElement classElement, XmlElements elements, VariableElement fieldElement,
-                                 Set<EipOption> eipOptions, String prefix) {
-        Elements elementUtils = processingEnv.getElementUtils();
-
-        String fieldName;
-        fieldName = fieldElement.getSimpleName().toString();
-        if (elements != null) {
-            String kind = "element";
-            String name = fieldName;
-            name = prefix + name;
-
-            TypeMirror fieldType = fieldElement.asType();
-            String fieldTypeName = fieldType.toString();
-
-            String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
-            String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true);
-
-            boolean required = true;
-            required = findRequired(fieldElement, required);
-
-            // gather oneOf of the elements
-            Set<String> oneOfTypes = new TreeSet<String>();
-            for (XmlElement element : elements.value()) {
-                String child = element.name();
-                oneOfTypes.add(child);
-            }
-
-            EipOption ep = new EipOption(name, kind, fieldTypeName, required, defaultValue, docComment, false, false, null, true, oneOfTypes);
-            eipOptions.add(ep);
-        }
-    }
-
-    private void processRoute(RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement classElement,
-                              Set<EipOption> eipOptions, String prefix) {
-
-        Elements elementUtils = processingEnv.getElementUtils();
-
-        // group
-        String docComment = findJavaDoc(elementUtils, null, "group", null, classElement, true);
-        EipOption ep = new EipOption("group", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
-        eipOptions.add(ep);
-
-        // group
-        docComment = findJavaDoc(elementUtils, null, "streamCache", null, classElement, true);
-        ep = new EipOption("streamCache", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
-        eipOptions.add(ep);
-
-        // trace
-        docComment = findJavaDoc(elementUtils, null, "trace", null, classElement, true);
-        ep = new EipOption("trace", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
-        eipOptions.add(ep);
-
-        // trace
-        docComment = findJavaDoc(elementUtils, null, "messageHistory", null, classElement, true);
-        ep = new EipOption("messageHistory", "attribute", "java.lang.String", false, "true", docComment, false, false, null, false, null);
-        eipOptions.add(ep);
-
-        // trace
-        docComment = findJavaDoc(elementUtils, null, "handleFault", null, classElement, true);
-        ep = new EipOption("handleFault", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
-        eipOptions.add(ep);
-
-        // delayer
-        docComment = findJavaDoc(elementUtils, null, "delayer", null, classElement, true);
-        ep = new EipOption("delayer", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
-        eipOptions.add(ep);
-
-        // autoStartup
-        docComment = findJavaDoc(elementUtils, null, "autoStartup", null, classElement, true);
-        ep = new EipOption("autoStartup", "attribute", "java.lang.String", false, "true", docComment, false, false, null, false, null);
-        eipOptions.add(ep);
-
-        // startupOrder
-        docComment = findJavaDoc(elementUtils, null, "startupOrder", null, classElement, true);
-        ep = new EipOption("startupOrder", "attribute", "java.lang.Integer", false, "", docComment, false, false, null, false, null);
-        eipOptions.add(ep);
-
-        // errorHandlerRef
-        docComment = findJavaDoc(elementUtils, null, "errorHandlerRef", null, classElement, true);
-        ep = new EipOption("errorHandlerRef", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
-        eipOptions.add(ep);
-
-        // routePolicyRef
-        docComment = findJavaDoc(elementUtils, null, "routePolicyRef", null, classElement, true);
-        ep = new EipOption("routePolicyRef", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
-        eipOptions.add(ep);
-
-        // shutdownRoute
-        Set<String> enums = new LinkedHashSet<String>();
-        enums.add("Default");
-        enums.add("Defer");
-        docComment = findJavaDoc(elementUtils, null, "shutdownRoute", "Default", classElement, true);
-        ep = new EipOption("shutdownRoute", "attribute", "org.apache.camel.ShutdownRoute", false, "", docComment, false, true, enums, false, null);
-        eipOptions.add(ep);
-
-        // shutdownRunningTask
-        enums = new LinkedHashSet<String>();
-        enums.add("CompleteCurrentTaskOnly");
-        enums.add("CompleteAllTasks");
-        docComment = findJavaDoc(elementUtils, null, "shutdownRunningTask", "CompleteCurrentTaskOnly", classElement, true);
-        ep = new EipOption("shutdownRunningTask", "attribute", "org.apache.camel.ShutdownRunningTask", false, "", docComment, false, true, enums, false, null);
-        eipOptions.add(ep);
-
-        // inputs
-        Set<String> oneOfTypes = new TreeSet<String>();
-        oneOfTypes.add("from");
-        docComment = findJavaDoc(elementUtils, null, "inputs", null, classElement, true);
-        ep = new EipOption("inputs", "element", "java.util.List<org.apache.camel.model.FromDefinition>", true, "", docComment, false, false, null, true, oneOfTypes);
-        eipOptions.add(ep);
-
-        // outputs
-        // gather oneOf which extends any of the output base classes
-        oneOfTypes = new TreeSet<String>();
-        // find all classes that has that superClassName
-        Set<TypeElement> children = new LinkedHashSet<TypeElement>();
-        for (String superclass : ONE_OF_OUTPUTS) {
-            findTypeElementChildren(roundEnv, children, superclass);
-        }
-        for (TypeElement child : children) {
-            XmlRootElement rootElement = child.getAnnotation(XmlRootElement.class);
-            if (rootElement != null) {
-                String childName = rootElement.name();
-                if (childName != null) {
-                    oneOfTypes.add(childName);
-                }
-            }
-        }
-
-        // remove some types which are not intended as an output in eips
-        oneOfTypes.remove("route");
-
-        docComment = findJavaDoc(elementUtils, null, "outputs", null, classElement, true);
-        ep = new EipOption("outputs", "element", "java.util.List<org.apache.camel.model.ProcessorDefinition<?>>", true, "", docComment, false, false, null, true, oneOfTypes);
-        eipOptions.add(ep);
-    }
-
-    /**
-     * Special for process the OptionalIdentifiedDefinition
-     */
-    private void processIdentified(RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement classElement,
-                                   Set<EipOption> eipOptions, String prefix) {
-
-        Elements elementUtils = processingEnv.getElementUtils();
-
-        // id
-        String docComment = findJavaDoc(elementUtils, null, "id", null, classElement, true);
-        EipOption ep = new EipOption("id", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
-        eipOptions.add(ep);
-
-        // description
-        docComment = findJavaDoc(elementUtils, null, "description", null, classElement, true);
-        ep = new EipOption("description", "element", "org.apache.camel.model.DescriptionDefinition", false, "", docComment, false, false, null, false, null);
-        eipOptions.add(ep);
-
-        // lets skip custom id as it has no value for end users to configure
-        if (!skipUnwanted) {
-            // custom id
-            docComment = findJavaDoc(elementUtils, null, "customId", null, classElement, true);
-            ep = new EipOption("customId", "attribute", "java.lang.String", false, "", docComment, false, false, null, false, null);
-            eipOptions.add(ep);
-        }
-    }
-
-    /**
-     * Special for processing an @XmlElementRef routes field
-     */
-    private void processRoutes(RoundEnvironment roundEnv, TypeElement originalClassType, XmlElementRef elementRef,
-                               VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) {
-        if ("routes".equals(fieldName)) {
-
-            TypeMirror fieldType = fieldElement.asType();
-            String fieldTypeName = fieldType.toString();
-
-            Set<String> oneOfTypes = new TreeSet<String>();
-            oneOfTypes.add("route");
-
-            EipOption ep = new EipOption("routes", "element", fieldTypeName, false, "", "Contains the Camel routes", false, false, null, true, oneOfTypes);
-            eipOptions.add(ep);
-        }
-    }
-
-    /**
-     * Special for processing an @XmlElementRef rests field
-     */
-    private void processRests(RoundEnvironment roundEnv, TypeElement originalClassType, XmlElementRef elementRef,
-                               VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) {
-        if ("rests".equals(fieldName)) {
-
-            TypeMirror fieldType = fieldElement.asType();
-            String fieldTypeName = fieldType.toString();
-
-            Set<String> oneOfTypes = new TreeSet<String>();
-            oneOfTypes.add("rest");
-
-            EipOption ep = new EipOption("rests", "element", fieldTypeName, false, "", "Contains the rest services defined using the rest-dsl", false, false, null, true, oneOfTypes);
-            eipOptions.add(ep);
-        }
-    }
-
-    /**
-     * Special for processing an @XmlElementRef outputs field
-     */
-    private void processOutputs(RoundEnvironment roundEnv, TypeElement originalClassType, XmlElementRef elementRef,
-                                VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) {
-        if ("outputs".equals(fieldName) && supportOutputs(originalClassType)) {
-            String kind = "element";
-            String name = elementRef.name();
-            if (isNullOrEmpty(name) || "##default".equals(name)) {
-                name = fieldName;
-            }
-            name = prefix + name;
-            TypeMirror fieldType = fieldElement.asType();
-            String fieldTypeName = fieldType.toString();
-
-            // gather oneOf which extends any of the output base classes
-            Set<String> oneOfTypes = new TreeSet<String>();
-            // find all classes that has that superClassName
-            Set<TypeElement> children = new LinkedHashSet<TypeElement>();
-            for (String superclass : ONE_OF_OUTPUTS) {
-                findTypeElementChildren(roundEnv, children, superclass);
-            }
-            for (TypeElement child : children) {
-                XmlRootElement rootElement = child.getAnnotation(XmlRootElement.class);
-                if (rootElement != null) {
-                    String childName = rootElement.name();
-                    if (childName != null) {
-                        oneOfTypes.add(childName);
-                    }
-                }
-            }
-
-            // remove some types which are not intended as an output in eips
-            oneOfTypes.remove("route");
-
-            EipOption ep = new EipOption(name, kind, fieldTypeName, true, "", "", false, false, null, true, oneOfTypes);
-            eipOptions.add(ep);
-        }
-    }
-
-    /**
-     * Special for processing an @XmlElementRef verbs field (rest-dsl)
-     */
-    private void processVerbs(RoundEnvironment roundEnv, TypeElement originalClassType, XmlElementRef elementRef,
-                              VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) {
-
-        Elements elementUtils = processingEnv.getElementUtils();
-
-        if ("verbs".equals(fieldName) && supportOutputs(originalClassType)) {
-            String kind = "element";
-            String name = elementRef.name();
-            if (isNullOrEmpty(name) || "##default".equals(name)) {
-                name = fieldName;
-            }
-            name = prefix + name;
-            TypeMirror fieldType = fieldElement.asType();
-            String fieldTypeName = fieldType.toString();
-
-            String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, originalClassType, true);
-
-            // gather oneOf which extends any of the output base classes
-            Set<String> oneOfTypes = new TreeSet<String>();
-            // find all classes that has that superClassName
-            Set<TypeElement> children = new LinkedHashSet<TypeElement>();
-            for (String superclass : ONE_OF_VERBS) {
-                findTypeElementChildren(roundEnv, children, superclass);
-            }
-            for (TypeElement child : children) {
-                XmlRootElement rootElement = child.getAnnotation(XmlRootElement.class);
-                if (rootElement != null) {
-                    String childName = rootElement.name();
-                    if (childName != null) {
-                        oneOfTypes.add(childName);
-                    }
-                }
-            }
-
-            EipOption ep = new EipOption(name, kind, fieldTypeName, true, "", docComment, false, false, null, true, oneOfTypes);
-            eipOptions.add(ep);
-        }
-    }
-
-    /**
-     * Special for processing an @XmlElementRef expression field
-     */
-    private void processRefExpression(RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement classElement,
-                                      XmlElementRef elementRef, VariableElement fieldElement,
-                                      String fieldName, Set<EipOption> eipOptions, String prefix) {
-        Elements elementUtils = processingEnv.getElementUtils();
-
-        if ("expression".equals(fieldName)) {
-            String kind = "expression";
-            String name = elementRef.name();
-            if (isNullOrEmpty(name) || "##default".equals(name)) {
-                name = fieldName;
-            }
-            name = prefix + name;
-            TypeMirror fieldType = fieldElement.asType();
-            String fieldTypeName = fieldType.toString();
-
-            // find javadoc from original class as it will override the setExpression method where we can provide the javadoc for the given EIP
-            String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, originalClassType, true);
-
-            // gather oneOf expression/predicates which uses language
-            Set<String> oneOfTypes = new TreeSet<String>();
-            for (String language : ONE_OF_LANGUAGES) {
-                TypeElement languages = findTypeElement(roundEnv, language);
-                String superClassName = canonicalClassName(languages.toString());
-                // find all classes that has that superClassName
-                Set<TypeElement> children = new LinkedHashSet<TypeElement>();
-                findTypeElementChildren(roundEnv, children, superClassName);
-                for (TypeElement child : children) {
-                    XmlRootElement rootElement = child.getAnnotation(XmlRootElement.class);
-                    if (rootElement != null) {
-                        String childName = rootElement.name();
-                        if (childName != null) {
-                            oneOfTypes.add(childName);
-                        }
-                    }
-                }
-            }
-
-            boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null;
-
-            EipOption ep = new EipOption(name, kind, fieldTypeName, true, "", docComment, deprecated, false, null, true, oneOfTypes);
-            eipOptions.add(ep);
-        }
-    }
-
-    /**
-     * Special for processing an @XmlElementRef when field
-     */
-    private void processRefWhenClauses(RoundEnvironment roundEnv, TypeElement originalClassType, XmlElementRef elementRef,
-                                       VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) {
-        Elements elementUtils = processingEnv.getElementUtils();
-
-        if ("whenClauses".equals(fieldName)) {
-            String kind = "element";
-            String name = elementRef.name();
-            if (isNullOrEmpty(name) || "##default".equals(name)) {
-                name = fieldName;
-            }
-            name = prefix + name;
-            TypeMirror fieldType = fieldElement.asType();
-            String fieldTypeName = fieldType.toString();
-
-            // find javadoc from original class as it will override the setExpression method where we can provide the javadoc for the given EIP
-            String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, originalClassType, true);
-            boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null;
-
-            // indicate that this element is one of when
-            Set<String> oneOfTypes = new HashSet<String>();
-            oneOfTypes.add("when");
-
-            EipOption ep = new EipOption(name, kind, fieldTypeName, false, "", docComment, deprecated, false, null, true, oneOfTypes);
-            eipOptions.add(ep);
-        }
-    }
-
-    /**
-     * Whether the class supports outputs.
-     * <p/>
-     * There are some classes which does not support outputs, even though they have a outputs element.
-     */
-    private boolean supportOutputs(TypeElement classElement) {
-        String superclass = canonicalClassName(classElement.getSuperclass().toString());
-        return !"org.apache.camel.model.NoOutputExpressionNode".equals(superclass);
-    }
-
-    private String findDefaultValue(VariableElement fieldElement, String fieldTypeName) {
-        String defaultValue = null;
-        Metadata metadata = fieldElement.getAnnotation(Metadata.class);
-        if (metadata != null) {
-            if (!Strings.isNullOrEmpty(metadata.defaultValue())) {
-                defaultValue = metadata.defaultValue();
-            }
-        }
-        if (defaultValue == null) {
-            // if its a boolean type, then we use false as the default
-            if ("boolean".equals(fieldTypeName) || "java.lang.Boolean".equals(fieldTypeName)) {
-                defaultValue = "false";
-            }
-        }
-
-        return defaultValue;
-    }
-
-    private boolean findRequired(VariableElement fieldElement, boolean defaultValue) {
-        Metadata metadata = fieldElement.getAnnotation(Metadata.class);
-        if (metadata != null) {
-            if (!Strings.isNullOrEmpty(metadata.required())) {
-                defaultValue = "true".equals(metadata.required());
-            }
-        }
-        return defaultValue;
-    }
-
-    /**
-     * Capitializes the name as a title
-     *
-     * @param name  the name
-     * @return as a title
-     */
-    private static String asTitle(String name) {
-        StringBuilder sb = new StringBuilder();
-        for (char c : name.toCharArray()) {
-            boolean upper = Character.isUpperCase(c);
-            boolean first = sb.length() == 0;
-            if (first) {
-                sb.append(Character.toUpperCase(c));
-            } else if (upper) {
-                sb.append(' ');
-                sb.append(c);
-            } else {
-                sb.append(Character.toLowerCase(c));
-            }
-        }
-        return sb.toString().trim();
-    }
-
-    private boolean hasInput(RoundEnvironment roundEnv, TypeElement classElement) {
-        for (String name : ONE_OF_INPUTS) {
-            if (hasSuperClass(roundEnv, classElement, name)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean hasOutput(EipModel model, Set<EipOption> options) {
-        // if we are route/rest then we accept output
-        if ("route".equals(model.getName()) || "rest".equals(model.getName())) {
-            return true;
-        }
-
-        for (EipOption option : options) {
-            if ("outputs".equals(option.getName())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private static final class EipModel {
-
-        private String name;
-        private String title;
-        private String javaType;
-        private String label;
-        private String description;
-        private boolean input;
-        private boolean output;
-
-        public String getName() {
-            return name;
-        }
-
-        public void setName(String name) {
-            this.name = name;
-        }
-
-        public String getTitle() {
-            return title;
-        }
-
-        public void setTitle(String title) {
-            this.title = title;
-        }
-
-        public String getJavaType() {
-            return javaType;
-        }
-
-        public void setJavaType(String javaType) {
-            this.javaType = javaType;
-        }
-
-        public String getLabel() {
-            return label;
-        }
-
-        public void setLabel(String label) {
-            this.label = label;
-        }
-
-        public String getDescription() {
-            return description;
-        }
-
-        public void setDescription(String description) {
-            this.description = description;
-        }
-
-        public boolean isInput() {
-            return input;
-        }
-
-        public void setInput(boolean input) {
-            this.input = input;
-        }
-
-        public String getInput() {
-            return input ? "true" : "false";
-        }
-
-        public boolean isOutput() {
-            return output;
-        }
-
-        public void setOutput(boolean output) {
-            this.output = output;
-        }
-
-        public String getOutput() {
-            return output ? "true" : "false";
-        }
-
-    }
-
-    private static final class EipOption {
-
-        private String name;
-        private String kind;
-        private String type;
-        private boolean required;
-        private String defaultValue;
-        private String documentation;
-        private boolean deprecated;
-        private boolean enumType;
-        private Set<String> enums;
-        private boolean oneOf;
-        private Set<String> oneOfTypes;
-
-        private EipOption(String name, String kind, String type, boolean required, String defaultValue, String documentation, boolean deprecated,
-                          boolean enumType, Set<String> enums, boolean oneOf, Set<String> oneOfTypes) {
-            this.name = name;
-            this.kind = kind;
-            this.type = type;
-            this.required = required;
-            this.defaultValue = defaultValue;
-            this.documentation = documentation;
-            this.deprecated = deprecated;
-            this.enumType = enumType;
-            this.enums = enums;
-            this.oneOf = oneOf;
-            this.oneOfTypes = oneOfTypes;
-        }
-
-        public String getName() {
-            return name;
-        }
-
-        public String getKind() {
-            return kind;
-        }
-
-        public String getType() {
-            return type;
-        }
-
-        public boolean isRequired() {
-            return required;
-        }
-
-        public String getDefaultValue() {
-            return defaultValue;
-        }
-
-        public String getDocumentation() {
-            return documentation;
-        }
-
-        public boolean isDeprecated() {
-            return deprecated;
-        }
-
-        public boolean isEnumType() {
-            return enumType;
-        }
-
-        public Set<String> getEnums() {
-            return enums;
-        }
-
-        public boolean isOneOf() {
-            return oneOf;
-        }
-
-        public Set<String> getOneOfTypes() {
-            return oneOfTypes;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-            if (o == null || getClass() != o.getClass()) {
-                return false;
-            }
-
-            EipOption that = (EipOption) o;
-
-            if (!name.equals(that.name)) {
-                return false;
-            }
-
-            return true;
-        }
-
-        @Override
-        public int hashCode() {
-            return name.hashCode();
-        }
-    }
-
-    private static final class EipOptionComparator implements Comparator<EipOption> {
-
-        private final EipModel model;
-
-        private EipOptionComparator(EipModel model) {
-            this.model = model;
-        }
-
-        @Override
-        public int compare(EipOption o1, EipOption o2) {
-            int weigth = weigth(o1);
-            int weigth2 = weigth(o2);
-
-            if (weigth == weigth2) {
-                // keep the current order
-                return 1;
-            } else {
-                // sort according to weight
-                return weigth2 - weigth;
-            }
-        }
-
-        private int weigth(EipOption o) {
-            String name = o.getName();
-
-            // these should be first
-            if ("expression".equals(name)) {
-                return 10;
-            }
-
-            // these should be last
-            if ("description".equals(name)) {
-                return -10;
-            } else if ("id".equals(name)) {
-                return -9;
-            } else if ("pattern".equals(name) && "to".equals(model.getName())) {
-                // and pattern only for the to model
-                return -8;
-            }
-            return 0;
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/8a18e284/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java
----------------------------------------------------------------------
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java
index 79bf935..ffeb73b 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java
@@ -24,6 +24,7 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import javax.annotation.processing.AbstractProcessor;
 import javax.annotation.processing.RoundEnvironment;
 import javax.annotation.processing.SupportedAnnotationTypes;
 import javax.annotation.processing.SupportedSourceVersion;
@@ -52,6 +53,14 @@ import org.apache.camel.tools.apt.model.ComponentOption;
 import org.apache.camel.tools.apt.model.EndpointOption;
 import org.apache.camel.tools.apt.model.EndpointPath;
 
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.dumpExceptionToErrorFile;
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findFieldElement;
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findJavaDoc;
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findTypeElement;
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.implementsInterface;
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.loadResource;
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.processFile;
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.warning;
 import static org.apache.camel.tools.apt.helper.JsonSchemaHelper.sanitizeDescription;
 import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
 import static org.apache.camel.tools.apt.helper.Strings.getOrElse;
@@ -63,7 +72,7 @@ import static org.apache.camel.tools.apt.helper.Strings.safeNull;
  */
 @SupportedAnnotationTypes({"org.apache.camel.spi.*"})
 @SupportedSourceVersion(SourceVersion.RELEASE_8)
-public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
+public class EndpointAnnotationProcessor extends AbstractProcessor {
 
     // CHECKSTYLE:OFF
 
@@ -114,7 +123,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
                             return null;
                         }
                     };
-                    processFile(packageName, fileName, handler);
+                    processFile(processingEnv, packageName, fileName, handler);
 
                     // write json schema
                     fileName = alias + ".json";
@@ -125,7 +134,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
                             return null;
                         }
                     };
-                    processFile(packageName, fileName, handler);
+                    processFile(processingEnv, packageName, fileName, handler);
                 }
             }
         }
@@ -177,7 +186,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
         String consumerPrefix = getOrElse(uriEndpoint.consumerPrefix(), "");
         if (consumerType != null) {
             consumerClassName = consumerType.toString();
-            TypeElement consumerElement = findTypeElement(roundEnv, consumerClassName);
+            TypeElement consumerElement = findTypeElement(processingEnv, roundEnv, consumerClassName);
             if (consumerElement != null) {
                 writer.println("<h2>" + scheme + " consumer" + "</h2>");
                 writeHtmlDocumentationAndFieldInjections(writer, roundEnv, componentModel, consumerElement, consumerPrefix, uriEndpoint.excludeProperties());
@@ -185,7 +194,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
             }
         }
         if (!found && consumerClassName != null) {
-            warning("APT could not find consumer class " + consumerClassName);
+            warning(processingEnv, "APT could not find consumer class " + consumerClassName);
         }
         writer.println("</body>");
         writer.println("</html>");
@@ -201,7 +210,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
         Set<EndpointOption> endpointOptions = new LinkedHashSet<EndpointOption>();
         Set<ComponentOption> componentOptions = new LinkedHashSet<ComponentOption>();
 
-        TypeElement componentClassElement = findTypeElement(roundEnv, componentModel.getJavaType());
+        TypeElement componentClassElement = findTypeElement(processingEnv, roundEnv, componentModel.getJavaType());
         if (componentClassElement != null) {
             findComponentClassProperties(writer, roundEnv, componentModel, componentOptions, componentClassElement, "");
         }
@@ -462,15 +471,15 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
         model.setConsumerOnly(uriEndpoint.consumerOnly());
         model.setProducerOnly(uriEndpoint.producerOnly());
         model.setLenientProperties(uriEndpoint.lenientProperties());
-        model.setAsync(implementsInterface(roundEnv, endpointClassElement, "org.apache.camel.AsyncEndpoint"));
+        model.setAsync(implementsInterface(processingEnv, roundEnv, endpointClassElement, "org.apache.camel.AsyncEndpoint"));
 
-        String data = loadResource("META-INF/services/org/apache/camel/component", scheme);
+        String data = loadResource(processingEnv, "META-INF/services/org/apache/camel/component", scheme);
         if (data != null) {
             Map<String, String> map = parseAsMap(data);
             model.setJavaType(map.get("class"));
         }
 
-        data = loadResource("META-INF/services/org/apache/camel", "component.properties");
+        data = loadResource(processingEnv, "META-INF/services/org/apache/camel", "component.properties");
         if (data != null) {
             Map<String, String> map = parseAsMap(data);
             // now we have a lot more data, so we need to load it as key/value
@@ -510,7 +519,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
 
         // favor to use endpoint class javadoc as description
         Elements elementUtils = processingEnv.getElementUtils();
-        TypeElement typeElement = findTypeElement(roundEnv, endpointClassElement.getQualifiedName().toString());
+        TypeElement typeElement = findTypeElement(processingEnv, roundEnv, endpointClassElement.getQualifiedName().toString());
         if (typeElement != null) {
             String doc = elementUtils.getDocComment(typeElement);
             if (doc != null) {
@@ -571,7 +580,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
                 name = prefix + name;
                 TypeMirror fieldType = setter.getParameters().get(0).asType();
                 String fieldTypeName = fieldType.toString();
-                TypeElement fieldTypeElement = findTypeElement(roundEnv, fieldTypeName);
+                TypeElement fieldTypeElement = findTypeElement(processingEnv, roundEnv, fieldTypeName);
 
                 String docComment = findJavaDoc(elementUtils, method, fieldName, name, classElement, false);
                 if (isNullOrEmpty(docComment)) {
@@ -590,7 +599,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
                 Set<String> enums = new LinkedHashSet<String>();
                 boolean isEnum = fieldTypeElement != null && fieldTypeElement.getKind() == ElementKind.ENUM;
                 if (isEnum) {
-                    TypeElement enumClass = findTypeElement(roundEnv, fieldTypeElement.asType().toString());
+                    TypeElement enumClass = findTypeElement(processingEnv, roundEnv, fieldTypeElement.asType().toString());
                     // find all the enum constants which has the possible enum value that can be used
                     List<VariableElement> fields = ElementFilter.fieldsIn(enumClass.getEnclosedElements());
                     for (VariableElement var : fields) {
@@ -612,7 +621,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
             TypeMirror superclass = classElement.getSuperclass();
             if (superclass != null) {
                 String superClassName = canonicalClassName(superclass.toString());
-                baseTypeElement = findTypeElement(roundEnv, superClassName);
+                baseTypeElement = findTypeElement(processingEnv, roundEnv, superClassName);
             }
             if (baseTypeElement != null) {
                 classElement = baseTypeElement;
@@ -661,7 +670,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
 
                     TypeMirror fieldType = fieldElement.asType();
                     String fieldTypeName = fieldType.toString();
-                    TypeElement fieldTypeElement = findTypeElement(roundEnv, fieldTypeName);
+                    TypeElement fieldTypeElement = findTypeElement(processingEnv, roundEnv, fieldTypeName);
 
                     String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, false);
                     if (isNullOrEmpty(docComment)) {
@@ -681,7 +690,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
                     } else {
                         isEnum = fieldTypeElement != null && fieldTypeElement.getKind() == ElementKind.ENUM;
                         if (isEnum) {
-                            TypeElement enumClass = findTypeElement(roundEnv, fieldTypeElement.asType().toString());
+                            TypeElement enumClass = findTypeElement(processingEnv, roundEnv, fieldTypeElement.asType().toString());
                             // find all the enum constants which has the possible enum value that can be used
                             List<VariableElement> fields = ElementFilter.fieldsIn(enumClass.getEnclosedElements());
                             for (VariableElement var : fields) {
@@ -735,7 +744,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
                     // if the field type is a nested parameter then iterate through its fields
                     TypeMirror fieldType = fieldElement.asType();
                     String fieldTypeName = fieldType.toString();
-                    TypeElement fieldTypeElement = findTypeElement(roundEnv, fieldTypeName);
+                    TypeElement fieldTypeElement = findTypeElement(processingEnv, roundEnv, fieldTypeName);
                     UriParams fieldParams = null;
                     if (fieldTypeElement != null) {
                         fieldParams = fieldTypeElement.getAnnotation(UriParams.class);
@@ -769,7 +778,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
                         } else {
                             isEnum = fieldTypeElement != null && fieldTypeElement.getKind() == ElementKind.ENUM;
                             if (isEnum) {
-                                TypeElement enumClass = findTypeElement(roundEnv, fieldTypeElement.asType().toString());
+                                TypeElement enumClass = findTypeElement(processingEnv, roundEnv, fieldTypeElement.asType().toString());
                                 // find all the enum constants which has the possible enum value that can be used
                                 List<VariableElement> fields = ElementFilter.fieldsIn(enumClass.getEnclosedElements());
                                 for (VariableElement var : fields) {
@@ -800,7 +809,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
             TypeMirror superclass = classElement.getSuperclass();
             if (superclass != null) {
                 String superClassName = canonicalClassName(superclass.toString());
-                baseTypeElement = findTypeElement(roundEnv, superClassName);
+                baseTypeElement = findTypeElement(processingEnv, roundEnv, superClassName);
             }
             if (baseTypeElement != null) {
                 classElement = baseTypeElement;

http://git-wip-us.apache.org/repos/asf/camel/blob/8a18e284/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelAnnotationProcessor.java
----------------------------------------------------------------------
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelAnnotationProcessor.java
new file mode 100644
index 0000000..c56fafc
--- /dev/null
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelAnnotationProcessor.java
@@ -0,0 +1,71 @@
+/**
+ * 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.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.TypeElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.dumpExceptionToErrorFile;
+import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName;
+
+/**
+ * APT compiler plugin to generate JSon Schema for all EIP models and camel-spring's <camelContext> types.
+ */
+@SupportedAnnotationTypes({"javax.xml.bind.annotation.*", "org.apache.camel.spi.Label"})
+@SupportedSourceVersion(SourceVersion.RELEASE_8)
+public class ModelAnnotationProcessor extends AbstractProcessor {
+
+    CoreEipAnnotationProcessor coreProcessor = new CoreEipAnnotationProcessor();
+    SpringAnnotationProcessor springProcessor = new SpringAnnotationProcessor();
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        try {
+            if (roundEnv.processingOver()) {
+                return true;
+            }
+
+            Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(XmlRootElement.class);
+            for (Element element : elements) {
+                if (element instanceof TypeElement) {
+                    TypeElement classElement = (TypeElement) element;
+
+                    final String javaTypeName = canonicalClassName(classElement.getQualifiedName().toString());
+                    boolean core = javaTypeName.startsWith("org.apache.camel.model");
+                    boolean spring = javaTypeName.startsWith("org.apache.camel.spring") || javaTypeName.startsWith("org.apache.camel.core.xml");
+                    if (core) {
+                        coreProcessor.processModelClass(processingEnv, roundEnv, classElement);
+                    } else if (spring) {
+                        springProcessor.processModelClass(processingEnv, roundEnv, classElement);
+                    }
+                }
+            }
+        } catch (Throwable e) {
+            dumpExceptionToErrorFile("camel-apt-error.log", "Error processing", e);
+        }
+
+        return true;
+    }
+
+}
\ No newline at end of file