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 2014/12/31 08:59:31 UTC

[1/2] camel git commit: CAMEL-7999: apt compiler to generate json schema documentation for the model, whcih we later use to enrich the xml xsd to include documentation. Work in progress.

Repository: camel
Updated Branches:
  refs/heads/master 4c130488c -> 92a351e34


CAMEL-7999: apt compiler to generate json schema documentation for the model, whcih we later use to enrich the xml xsd to include documentation. Work in progress.


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

Branch: refs/heads/master
Commit: e5bdc179bf7887dff79f814f91791c1a9bb593b9
Parents: 4c13048
Author: Claus Ibsen <da...@apache.org>
Authored: Wed Dec 31 08:35:16 2014 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Wed Dec 31 08:35:16 2014 +0100

----------------------------------------------------------------------
 .../camel/tools/apt/EipAnnotationProcessor.java | 708 +++++++++++++++++++
 .../ModelDocumentationAnnotationProcessor.java  | 708 -------------------
 .../javax.annotation.processing.Processor       |   2 +-
 3 files changed, 709 insertions(+), 709 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/e5bdc179/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
new file mode 100644
index 0000000..8805c1b
--- /dev/null
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EipAnnotationProcessor.java
@@ -0,0 +1,708 @@
+/**
+ * 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.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.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.camel.spi.Label;
+
+import static org.apache.camel.tools.apt.JsonSchemaHelper.sanitizeDescription;
+import static org.apache.camel.tools.apt.Strings.canonicalClassName;
+import static org.apache.camel.tools.apt.Strings.isNullOrEmpty;
+import static org.apache.camel.tools.apt.Strings.safeNull;
+
+// TODO: figure out a way to specify default value in the model classes which this APT can read
+
+// TODO: add support for @XmlElements which a few EIPs uses such as resequence
+//@XmlElements({
+//        @XmlElement(name = "batch-config", type = BatchResequencerConfig.class),
+//        @XmlElement(name = "stream-config", type = StreamResequencerConfig.class)}
+//)
+
+
+/**
+ * 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_7)
+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 = "org.apache.camel.model.language.ExpressionDefinition";
+    // 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",
+    };
+
+    private boolean skipUnwanted = true;
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        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);
+            }
+        }
+        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);
+        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 name) {
+        // gather eip information
+        EipModel eipModel = findEipModelProperties(roundEnv, classElement, javaTypeName, name);
+
+        // get endpoint information which is divided into paths and options (though there should really only be one path)
+        Set<EipOption> eipOptions = new LinkedHashSet<EipOption>();
+        findClassProperties(writer, roundEnv, eipOptions, classElement, classElement, "");
+
+        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    \"name\": \"").append(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.isEnumType(), entry.getEnums(), entry.isOneOf(), entry.getOneOfTypes()));
+        }
+        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);
+
+        Label label = classElement.getAnnotation(Label.class);
+        if (label != null) {
+            model.setLabel(label.value());
+        }
+
+        // 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) {
+        Elements elementUtils = processingEnv.getElementUtils();
+        while (true) {
+            List<VariableElement> fieldElements = ElementFilter.fieldsIn(classElement.getEnclosedElements());
+            for (VariableElement fieldElement : fieldElements) {
+
+                XmlAttribute attribute = fieldElement.getAnnotation(XmlAttribute.class);
+                String fieldName = fieldElement.getSimpleName().toString();
+                if (attribute != null) {
+                    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)) {
+                            continue;
+                        }
+                    }
+
+                    name = prefix + name;
+                    TypeMirror fieldType = fieldElement.asType();
+                    String fieldTypeName = fieldType.toString();
+                    TypeElement fieldTypeElement = findTypeElement(roundEnv, fieldTypeName);
+
+                    String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement, true);
+                    boolean required = attribute.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);
+                            }
+                        }
+                    }
+
+                    EipOption ep = new EipOption(name, "attribute", fieldTypeName, required, "", docComment, isEnum, enums, false, null);
+                    eipOptions.add(ep);
+                }
+
+                XmlElement element = fieldElement.getAnnotation(XmlElement.class);
+                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 docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement, true);
+                    boolean required = element.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) {
+                        TypeElement languages = findTypeElement(roundEnv, ONE_OF_LANGUAGES);
+                        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);
+                                }
+                            }
+                        }
+                    }
+
+                    EipOption ep = new EipOption(name, kind, fieldTypeName, required, "", docComment, isEnum, enums, isOneOf, oneOfTypes);
+                    eipOptions.add(ep);
+                }
+
+                // special for eips which has outputs or requires an expressions
+                XmlElementRef elementRef = fieldElement.getAnnotation(XmlElementRef.class);
+                fieldName = fieldElement.getSimpleName().toString();
+                if (elementRef != null) {
+
+                    // special for outputs
+                    processOutputs(roundEnv, originalClassType, elementRef, fieldElement, fieldName, eipOptions, prefix);
+
+                    // special for expression
+                    processExpression(roundEnv, 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 void processRoute(RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement classElement,
+                              Set<EipOption> eipOptions, String prefix) {
+
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        // group
+        String docComment = findJavaDoc(elementUtils, null, "group", classElement, true);
+        EipOption ep = new EipOption("group", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
+        eipOptions.add(ep);
+
+        // group
+        docComment = findJavaDoc(elementUtils, null, "streamCache", classElement, true);
+        ep = new EipOption("streamCache", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
+        eipOptions.add(ep);
+
+        // trace
+        docComment = findJavaDoc(elementUtils, null, "trace", classElement, true);
+        ep = new EipOption("trace", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
+        eipOptions.add(ep);
+
+        // trace
+        docComment = findJavaDoc(elementUtils, null, "messageHistory", classElement, true);
+        ep = new EipOption("messageHistory", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
+        eipOptions.add(ep);
+
+        // trace
+        docComment = findJavaDoc(elementUtils, null, "handleFault", classElement, true);
+        ep = new EipOption("handleFault", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
+        eipOptions.add(ep);
+
+        // delayer
+        docComment = findJavaDoc(elementUtils, null, "delayer", classElement, true);
+        ep = new EipOption("delayer", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
+        eipOptions.add(ep);
+
+        // autoStartup
+        docComment = findJavaDoc(elementUtils, null, "autoStartup", classElement, true);
+        ep = new EipOption("autoStartup", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
+        eipOptions.add(ep);
+
+        // startupOrder
+        docComment = findJavaDoc(elementUtils, null, "startupOrder", classElement, true);
+        ep = new EipOption("startupOrder", "attribute", "java.lang.Integer", false, "", docComment, false, null, false, null);
+        eipOptions.add(ep);
+
+        // errorHandlerRef
+        docComment = findJavaDoc(elementUtils, null, "errorHandlerRef", classElement, true);
+        ep = new EipOption("errorHandlerRef", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
+        eipOptions.add(ep);
+
+        // routePolicyRef
+        docComment = findJavaDoc(elementUtils, null, "routePolicyRef", classElement, true);
+        ep = new EipOption("routePolicyRef", "attribute", "java.lang.String", false, "", docComment, 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", classElement, true);
+        ep = new EipOption("shutdownRoute", "attribute", "org.apache.camel.ShutdownRoute", false, "", docComment, true, enums, false, null);
+        eipOptions.add(ep);
+
+        // shutdownRunningTask
+        enums = new LinkedHashSet<String>();
+        enums.add("CompleteCurrentTaskOnly");
+        enums.add("CompleteAllTasks");
+        docComment = findJavaDoc(elementUtils, null, "shutdownRunningTask", classElement, true);
+        ep = new EipOption("shutdownRunningTask", "attribute", "org.apache.camel.ShutdownRunningTask", false, "", docComment, true, enums, false, null);
+        eipOptions.add(ep);
+
+        // inputs
+        Set<String> oneOfTypes = new TreeSet<String>();
+        oneOfTypes.add("from");
+        docComment = findJavaDoc(elementUtils, null, "inputs", classElement, true);
+        ep = new EipOption("inputs", "element", "java.util.List<org.apache.camel.model.FromDefinition>", true, "", docComment, 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", classElement, true);
+        ep = new EipOption("outputs", "element", "java.util.List<org.apache.camel.model.ProcessorDefinition<?>>", true, "", docComment, 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", classElement, true);
+        EipOption ep = new EipOption("id", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
+        eipOptions.add(ep);
+
+        // description
+        docComment = findJavaDoc(elementUtils, null, "description", classElement, true);
+        ep = new EipOption("description", "element", "org.apache.camel.model.DescriptionDefinition", false, "", docComment, 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", classElement, true);
+            ep = new EipOption("customId", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
+            eipOptions.add(ep);
+        }
+    }
+
+    /**
+     * Special for processing an @XmlElementRef expression field
+     */
+    private void processExpression(RoundEnvironment roundEnv, XmlElementRef elementRef, VariableElement fieldElement,
+                                   String fieldName, Set<EipOption> eipOptions, String prefix) {
+        if ("expression".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();
+
+            // gather oneOf expression/predicates which uses language
+            Set<String> oneOfTypes = new TreeSet<String>();
+            TypeElement languages = findTypeElement(roundEnv, ONE_OF_LANGUAGES);
+            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);
+                    }
+                }
+            }
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, true, "", "", 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, 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 static final class EipModel {
+
+        private String name;
+        private String javaType;
+        private String label;
+        private String description;
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        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 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 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.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 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();
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e5bdc179/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelDocumentationAnnotationProcessor.java
----------------------------------------------------------------------
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelDocumentationAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelDocumentationAnnotationProcessor.java
deleted file mode 100644
index 7015061..0000000
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelDocumentationAnnotationProcessor.java
+++ /dev/null
@@ -1,708 +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.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.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
-import org.apache.camel.spi.Label;
-
-import static org.apache.camel.tools.apt.JsonSchemaHelper.sanitizeDescription;
-import static org.apache.camel.tools.apt.Strings.canonicalClassName;
-import static org.apache.camel.tools.apt.Strings.isNullOrEmpty;
-import static org.apache.camel.tools.apt.Strings.safeNull;
-
-// TODO: figure out a way to specify default value in the model classes which this APT can read
-
-// TODO: add support for @XmlElements which a few EIPs uses such as resequence
-//@XmlElements({
-//        @XmlElement(name = "batch-config", type = BatchResequencerConfig.class),
-//        @XmlElement(name = "stream-config", type = StreamResequencerConfig.class)}
-//)
-
-
-/**
- * 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_7)
-public class ModelDocumentationAnnotationProcessor 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 = "org.apache.camel.model.language.ExpressionDefinition";
-    // 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",
-    };
-
-    private boolean skipUnwanted = true;
-
-    @Override
-    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
-        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);
-            }
-        }
-        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);
-        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 name) {
-        // gather eip information
-        EipModel eipModel = findEipModelProperties(roundEnv, classElement, javaTypeName, name);
-
-        // get endpoint information which is divided into paths and options (though there should really only be one path)
-        Set<EipOption> eipOptions = new LinkedHashSet<EipOption>();
-        findClassProperties(writer, roundEnv, eipOptions, classElement, classElement, "");
-
-        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    \"name\": \"").append(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.isEnumType(), entry.getEnums(), entry.isOneOf(), entry.getOneOfTypes()));
-        }
-        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);
-
-        Label label = classElement.getAnnotation(Label.class);
-        if (label != null) {
-            model.setLabel(label.value());
-        }
-
-        // 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) {
-        Elements elementUtils = processingEnv.getElementUtils();
-        while (true) {
-            List<VariableElement> fieldElements = ElementFilter.fieldsIn(classElement.getEnclosedElements());
-            for (VariableElement fieldElement : fieldElements) {
-
-                XmlAttribute attribute = fieldElement.getAnnotation(XmlAttribute.class);
-                String fieldName = fieldElement.getSimpleName().toString();
-                if (attribute != null) {
-                    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)) {
-                            continue;
-                        }
-                    }
-
-                    name = prefix + name;
-                    TypeMirror fieldType = fieldElement.asType();
-                    String fieldTypeName = fieldType.toString();
-                    TypeElement fieldTypeElement = findTypeElement(roundEnv, fieldTypeName);
-
-                    String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement, true);
-                    boolean required = attribute.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);
-                            }
-                        }
-                    }
-
-                    EipOption ep = new EipOption(name, "attribute", fieldTypeName, required, "", docComment, isEnum, enums, false, null);
-                    eipOptions.add(ep);
-                }
-
-                XmlElement element = fieldElement.getAnnotation(XmlElement.class);
-                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 docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement, true);
-                    boolean required = element.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) {
-                        TypeElement languages = findTypeElement(roundEnv, ONE_OF_LANGUAGES);
-                        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);
-                                }
-                            }
-                        }
-                    }
-
-                    EipOption ep = new EipOption(name, kind, fieldTypeName, required, "", docComment, isEnum, enums, isOneOf, oneOfTypes);
-                    eipOptions.add(ep);
-                }
-
-                // special for eips which has outputs or requires an expressions
-                XmlElementRef elementRef = fieldElement.getAnnotation(XmlElementRef.class);
-                fieldName = fieldElement.getSimpleName().toString();
-                if (elementRef != null) {
-
-                    // special for outputs
-                    processOutputs(roundEnv, originalClassType, elementRef, fieldElement, fieldName, eipOptions, prefix);
-
-                    // special for expression
-                    processExpression(roundEnv, 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 void processRoute(RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement classElement,
-                              Set<EipOption> eipOptions, String prefix) {
-
-        Elements elementUtils = processingEnv.getElementUtils();
-
-        // group
-        String docComment = findJavaDoc(elementUtils, null, "group", classElement, true);
-        EipOption ep = new EipOption("group", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
-        eipOptions.add(ep);
-
-        // group
-        docComment = findJavaDoc(elementUtils, null, "streamCache", classElement, true);
-        ep = new EipOption("streamCache", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
-        eipOptions.add(ep);
-
-        // trace
-        docComment = findJavaDoc(elementUtils, null, "trace", classElement, true);
-        ep = new EipOption("trace", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
-        eipOptions.add(ep);
-
-        // trace
-        docComment = findJavaDoc(elementUtils, null, "messageHistory", classElement, true);
-        ep = new EipOption("messageHistory", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
-        eipOptions.add(ep);
-
-        // trace
-        docComment = findJavaDoc(elementUtils, null, "handleFault", classElement, true);
-        ep = new EipOption("handleFault", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
-        eipOptions.add(ep);
-
-        // delayer
-        docComment = findJavaDoc(elementUtils, null, "delayer", classElement, true);
-        ep = new EipOption("delayer", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
-        eipOptions.add(ep);
-
-        // autoStartup
-        docComment = findJavaDoc(elementUtils, null, "autoStartup", classElement, true);
-        ep = new EipOption("autoStartup", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
-        eipOptions.add(ep);
-
-        // startupOrder
-        docComment = findJavaDoc(elementUtils, null, "startupOrder", classElement, true);
-        ep = new EipOption("startupOrder", "attribute", "java.lang.Integer", false, "", docComment, false, null, false, null);
-        eipOptions.add(ep);
-
-        // errorHandlerRef
-        docComment = findJavaDoc(elementUtils, null, "errorHandlerRef", classElement, true);
-        ep = new EipOption("errorHandlerRef", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
-        eipOptions.add(ep);
-
-        // routePolicyRef
-        docComment = findJavaDoc(elementUtils, null, "routePolicyRef", classElement, true);
-        ep = new EipOption("routePolicyRef", "attribute", "java.lang.String", false, "", docComment, 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", classElement, true);
-        ep = new EipOption("shutdownRoute", "attribute", "org.apache.camel.ShutdownRoute", false, "", docComment, true, enums, false, null);
-        eipOptions.add(ep);
-
-        // shutdownRunningTask
-        enums = new LinkedHashSet<String>();
-        enums.add("CompleteCurrentTaskOnly");
-        enums.add("CompleteAllTasks");
-        docComment = findJavaDoc(elementUtils, null, "shutdownRunningTask", classElement, true);
-        ep = new EipOption("shutdownRunningTask", "attribute", "org.apache.camel.ShutdownRunningTask", false, "", docComment, true, enums, false, null);
-        eipOptions.add(ep);
-
-        // inputs
-        Set<String> oneOfTypes = new TreeSet<String>();
-        oneOfTypes.add("from");
-        docComment = findJavaDoc(elementUtils, null, "inputs", classElement, true);
-        ep = new EipOption("inputs", "element", "java.util.List<org.apache.camel.model.FromDefinition>", true, "", docComment, 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", classElement, true);
-        ep = new EipOption("outputs", "element", "java.util.List<org.apache.camel.model.ProcessorDefinition<?>>", true, "", docComment, 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", classElement, true);
-        EipOption ep = new EipOption("id", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
-        eipOptions.add(ep);
-
-        // description
-        docComment = findJavaDoc(elementUtils, null, "description", classElement, true);
-        ep = new EipOption("description", "element", "org.apache.camel.model.DescriptionDefinition", false, "", docComment, 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", classElement, true);
-            ep = new EipOption("customId", "attribute", "java.lang.String", false, "", docComment, false, null, false, null);
-            eipOptions.add(ep);
-        }
-    }
-
-    /**
-     * Special for processing an @XmlElementRef expression field
-     */
-    private void processExpression(RoundEnvironment roundEnv, XmlElementRef elementRef, VariableElement fieldElement,
-                                   String fieldName, Set<EipOption> eipOptions, String prefix) {
-        if ("expression".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();
-
-            // gather oneOf expression/predicates which uses language
-            Set<String> oneOfTypes = new TreeSet<String>();
-            TypeElement languages = findTypeElement(roundEnv, ONE_OF_LANGUAGES);
-            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);
-                    }
-                }
-            }
-
-            EipOption ep = new EipOption(name, kind, fieldTypeName, true, "", "", 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, 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 static final class EipModel {
-
-        private String name;
-        private String javaType;
-        private String label;
-        private String description;
-
-        public String getName() {
-            return name;
-        }
-
-        public void setName(String name) {
-            this.name = name;
-        }
-
-        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 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 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.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 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();
-        }
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e5bdc179/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 68f577f..5148414 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,5 +14,5 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+org.apache.camel.tools.apt.EipAnnotationProcessor
 org.apache.camel.tools.apt.EndpointAnnotationProcessor
-org.apache.camel.tools.apt.ModelDocumentationAnnotationProcessor


[2/2] camel git commit: CAMEL-7999: apt compiler to generate json schema documentation for the model, whcih we later use to enrich the xml xsd to include documentation. Work in progress.

Posted by da...@apache.org.
CAMEL-7999: apt compiler to generate json schema documentation for the model, whcih we later use to enrich the xml xsd to include documentation. Work in progress.


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

Branch: refs/heads/master
Commit: 92a351e34ab1759aa012449b5487b9a3b2ffaefa
Parents: e5bdc17
Author: Claus Ibsen <da...@apache.org>
Authored: Wed Dec 31 08:58:23 2014 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Wed Dec 31 08:58:23 2014 +0100

----------------------------------------------------------------------
 .../apache/camel/model/MarshalDefinition.java   |   9 +-
 .../apache/camel/model/UnmarshalDefinition.java |   9 +-
 .../camel/tools/apt/EipAnnotationProcessor.java | 244 +++++++++++--------
 3 files changed, 157 insertions(+), 105 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/92a351e3/camel-core/src/main/java/org/apache/camel/model/MarshalDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/MarshalDefinition.java b/camel-core/src/main/java/org/apache/camel/model/MarshalDefinition.java
index ac317d2..b520d92 100644
--- a/camel-core/src/main/java/org/apache/camel/model/MarshalDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/MarshalDefinition.java
@@ -71,11 +71,8 @@ import org.apache.camel.spi.RouteContext;
 @XmlAccessorType(XmlAccessType.FIELD)
 public class MarshalDefinition extends NoOutputDefinition<MarshalDefinition> {
 
-    // TODO: Camel 3.0, ref attribute should be removed as RefDataFormat is to be used instead
+    // TODO: Camel 3.0, ref attribute should be removed as CustomDataFormat is to be used instead
 
-    @XmlAttribute
-    @Deprecated
-    private String ref;
     // cannot use @XmlElementRef as it doesn't allow optional properties
     @XmlElements({
     @XmlElement(required = false, name = "avro", type = AvroDataFormat.class),
@@ -113,6 +110,10 @@ public class MarshalDefinition extends NoOutputDefinition<MarshalDefinition> {
     )
     private DataFormatDefinition dataFormatType;
 
+    @XmlAttribute
+    @Deprecated
+    private String ref;
+
     public MarshalDefinition() {
     }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/92a351e3/camel-core/src/main/java/org/apache/camel/model/UnmarshalDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/UnmarshalDefinition.java b/camel-core/src/main/java/org/apache/camel/model/UnmarshalDefinition.java
index 2d2a7b3..a4a91e5 100644
--- a/camel-core/src/main/java/org/apache/camel/model/UnmarshalDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/UnmarshalDefinition.java
@@ -71,11 +71,8 @@ import org.apache.camel.spi.RouteContext;
 @XmlAccessorType(XmlAccessType.FIELD)
 public class UnmarshalDefinition extends NoOutputDefinition<UnmarshalDefinition> {
 
-    // TODO: Camel 3.0, ref attribute should be removed as RefDataFormat is to be used instead
+    // TODO: Camel 3.0, ref attribute should be removed as UnmarshalDataFormat is to be used instead
 
-    @XmlAttribute
-    @Deprecated
-    private String ref;
     // cannot use @XmlElementRef as it doesn't allow optional properties
     @XmlElements({
     @XmlElement(required = false, name = "avro", type = AvroDataFormat.class),
@@ -113,6 +110,10 @@ public class UnmarshalDefinition extends NoOutputDefinition<UnmarshalDefinition>
     )
     private DataFormatDefinition dataFormatType;
 
+    @XmlAttribute
+    @Deprecated
+    private String ref;
+
     public UnmarshalDefinition() {
     }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/92a351e3/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
index 8805c1b..a4aa927 100644
--- 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
@@ -36,6 +36,7 @@ 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;
 
@@ -48,12 +49,7 @@ import static org.apache.camel.tools.apt.Strings.safeNull;
 
 // TODO: figure out a way to specify default value in the model classes which this APT can read
 
-// TODO: add support for @XmlElements which a few EIPs uses such as resequence
-//@XmlElements({
-//        @XmlElement(name = "batch-config", type = BatchResequencerConfig.class),
-//        @XmlElement(name = "stream-config", type = StreamResequencerConfig.class)}
-//)
-
+// TODO: add support for @deprecated
 
 /**
  * Process all camel-core's model classes (EIPs and DSL) and generate json schema documentation
@@ -217,113 +213,32 @@ public class EipAnnotationProcessor extends AbstractAnnotationProcessor {
 
     protected void findClassProperties(PrintWriter writer, RoundEnvironment roundEnv, Set<EipOption> eipOptions,
                                        TypeElement originalClassType, TypeElement classElement, String prefix) {
-        Elements elementUtils = processingEnv.getElementUtils();
         while (true) {
             List<VariableElement> fieldElements = ElementFilter.fieldsIn(classElement.getEnclosedElements());
             for (VariableElement fieldElement : fieldElements) {
 
-                XmlAttribute attribute = fieldElement.getAnnotation(XmlAttribute.class);
                 String fieldName = fieldElement.getSimpleName().toString();
-                if (attribute != null) {
-                    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)) {
-                            continue;
-                        }
-                    }
-
-                    name = prefix + name;
-                    TypeMirror fieldType = fieldElement.asType();
-                    String fieldTypeName = fieldType.toString();
-                    TypeElement fieldTypeElement = findTypeElement(roundEnv, fieldTypeName);
-
-                    String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement, true);
-                    boolean required = attribute.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);
-                            }
-                        }
+                XmlAttribute attribute = fieldElement.getAnnotation(XmlAttribute.class);
+                if (attribute != null) {
+                    boolean skip = processAttribute(roundEnv, originalClassType, classElement, fieldElement, fieldName, attribute, eipOptions, prefix);
+                    if (skip) {
+                        continue;
                     }
+                }
 
-                    EipOption ep = new EipOption(name, "attribute", fieldTypeName, required, "", docComment, isEnum, enums, false, null);
-                    eipOptions.add(ep);
+                XmlElements elements = fieldElement.getAnnotation(XmlElements.class);
+                if (elements != null) {
+                    processElements(roundEnv, classElement, elements, fieldElement, eipOptions, prefix);
                 }
 
                 XmlElement element = fieldElement.getAnnotation(XmlElement.class);
-                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 docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement, true);
-                    boolean required = element.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) {
-                        TypeElement languages = findTypeElement(roundEnv, ONE_OF_LANGUAGES);
-                        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);
-                                }
-                            }
-                        }
-                    }
-
-                    EipOption ep = new EipOption(name, kind, fieldTypeName, required, "", docComment, isEnum, enums, isOneOf, oneOfTypes);
-                    eipOptions.add(ep);
+                    processElement(roundEnv, classElement, element, fieldElement, eipOptions, prefix);
                 }
 
                 // special for eips which has outputs or requires an expressions
                 XmlElementRef elementRef = fieldElement.getAnnotation(XmlElementRef.class);
-                fieldName = fieldElement.getSimpleName().toString();
                 if (elementRef != null) {
 
                     // special for outputs
@@ -356,6 +271,141 @@ public class EipAnnotationProcessor extends AbstractAnnotationProcessor {
         }
     }
 
+    private boolean processAttribute(RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement classElement, VariableElement fieldElement, String fieldName, XmlAttribute attribute, Set<EipOption> eipOptions, String prefix) {
+        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 docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement, true);
+        boolean required = attribute.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);
+                }
+            }
+        }
+
+        EipOption ep = new EipOption(name, "attribute", fieldTypeName, required, "", docComment, isEnum, enums, false, null);
+        eipOptions.add(ep);
+
+        return false;
+    }
+
+    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 docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement, true);
+            boolean required = element.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) {
+                TypeElement languages = findTypeElement(roundEnv, ONE_OF_LANGUAGES);
+                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);
+                        }
+                    }
+                }
+            }
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, required, "", docComment, 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 docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement, true);
+            boolean required = true;
+
+            // 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, "", docComment, false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
     private void processRoute(RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement classElement,
                               Set<EipOption> eipOptions, String prefix) {