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/30 11:42:22 UTC

[06/29] 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.

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/1ee75b43
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/1ee75b43
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/1ee75b43

Branch: refs/heads/master
Commit: 1ee75b4321c81ebbb2c82c6516f2b4a71c5a6a13
Parents: e505d03
Author: Claus Ibsen <da...@apache.org>
Authored: Thu Dec 25 18:06:34 2014 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Tue Dec 30 10:56:39 2014 +0100

----------------------------------------------------------------------
 .../tools/apt/AbstractAnnotationProcessor.java  | 43 +++++++++++-
 .../tools/apt/EndpointAnnotationProcessor.java  | 10 +--
 .../camel/tools/apt/JsonSchemaHelper.java       | 13 +++-
 .../ModelDocumentationAnnotationProcessor.java  | 70 +++++++++++++++-----
 4 files changed, 112 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/1ee75b43/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
index e558869..f4806b3 100644
--- 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
@@ -34,6 +34,7 @@ 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.util.ElementFilter;
 import javax.lang.model.util.Elements;
 import javax.tools.Diagnostic;
@@ -49,7 +50,7 @@ import static org.apache.camel.tools.apt.Strings.isNullOrEmpty;
  */
 public abstract class AbstractAnnotationProcessor extends AbstractProcessor {
 
-    protected String findJavaDoc(Elements elementUtils, VariableElement fieldElement, String fieldName, TypeElement classElement) {
+    protected String findJavaDoc(Elements elementUtils, VariableElement fieldElement, String fieldName, TypeElement classElement, boolean builderPattern) {
         String answer = elementUtils.getDocComment(fieldElement);
         if (isNullOrEmpty(answer)) {
             String setter = "set" + fieldName.substring(0, 1).toUpperCase();
@@ -60,7 +61,7 @@ public abstract class AbstractAnnotationProcessor extends AbstractProcessor {
             List<ExecutableElement> methods = ElementFilter.methodsIn(classElement.getEnclosedElements());
             for (ExecutableElement method : methods) {
                 String methodName = method.getSimpleName().toString();
-                if (setter.equals(methodName) && method.getParameters().size() == 1) {
+                if (setter.equals(methodName) && method.getParameters().size() == 1 && method.getReturnType().getKind().equals(TypeKind.VOID)) {
                     String doc = elementUtils.getDocComment(method);
                     if (!isNullOrEmpty(doc)) {
                         answer = doc;
@@ -92,6 +93,22 @@ public abstract class AbstractAnnotationProcessor extends AbstractProcessor {
                     }
                 }
             }
+
+            // lets try builder pattern
+            if (answer == null && builderPattern) {
+                // lets find the getter
+                methods = ElementFilter.methodsIn(classElement.getEnclosedElements());
+                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;
+                        }
+                    }
+                }
+            }
         }
         return answer;
     }
@@ -136,6 +153,28 @@ public abstract class AbstractAnnotationProcessor extends AbstractProcessor {
         return null;
     }
 
+    protected void findTypeElementChildren(RoundEnvironment roundEnv, Set<TypeElement> found, String superClassName) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        int idx = superClassName.lastIndexOf('.');
+        if (idx > 0) {
+            String packageName = superClassName.substring(0, idx);
+            PackageElement pe = elementUtils.getPackageElement(packageName);
+            if (pe != null) {
+                List<? extends Element> enclosedElements = pe.getEnclosedElements();
+                for (Element rootElement : enclosedElements) {
+                    if (rootElement instanceof TypeElement) {
+                        TypeElement typeElement = (TypeElement) rootElement;
+                        String aSuperClassName = canonicalClassName(typeElement.getSuperclass().toString());
+                        if (superClassName.equals(aSuperClassName)) {
+                            found.add(typeElement);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Helper method to produce class output text file using the given handler
      */

http://git-wip-us.apache.org/repos/asf/camel/blob/1ee75b43/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 f51c903..a091ab7 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
@@ -190,7 +190,8 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
                 buffer.append(",");
             }
             buffer.append("\n    ");
-            buffer.append(JsonSchemaHelper.toJson(path.getName(), "path", null, path.getType(), "", path.getDocumentation(), path.isEnumType(), path.getEnums()));
+            buffer.append(JsonSchemaHelper.toJson(path.getName(), "path", null, path.getType(), "", path.getDocumentation(),
+                    path.isEnumType(), path.getEnums(), false, null));
         }
 
         // and then regular parameter options
@@ -204,7 +205,8 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
             // as its json we need to sanitize the docs
             String doc = entry.getDocumentationWithNotes();
             doc = sanitizeDescription(doc, false);
-            buffer.append(JsonSchemaHelper.toJson(entry.getName(), "parameter", null, entry.getType(), entry.getDefaultValue(), doc, entry.isEnumType(), entry.getEnums()));
+            buffer.append(JsonSchemaHelper.toJson(entry.getName(), "parameter", null, entry.getType(), entry.getDefaultValue(), doc,
+                    entry.isEnumType(), entry.getEnums(), false, null));
         }
         buffer.append("\n  }");
 
@@ -336,7 +338,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
                     String fieldTypeName = fieldType.toString();
                     TypeElement fieldTypeElement = findTypeElement(roundEnv, fieldTypeName);
 
-                    String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement);
+                    String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement, false);
                     if (isNullOrEmpty(docComment)) {
                         docComment = path.description();
                     }
@@ -388,7 +390,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor {
                         }
                         findClassProperties(writer, roundEnv, endpointPaths, endpointOptions, fieldTypeElement, nestedPrefix);
                     } else {
-                        String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement);
+                        String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement, false);
                         if (isNullOrEmpty(docComment)) {
                             docComment = param.description();
                         }

http://git-wip-us.apache.org/repos/asf/camel/blob/1ee75b43/tooling/apt/src/main/java/org/apache/camel/tools/apt/JsonSchemaHelper.java
----------------------------------------------------------------------
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/JsonSchemaHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/JsonSchemaHelper.java
index fd54723..42a2699 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/JsonSchemaHelper.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/JsonSchemaHelper.java
@@ -30,7 +30,8 @@ final class JsonSchemaHelper {
     private JsonSchemaHelper() {
     }
 
-    public static String toJson(String name, String kind, Boolean required, String type, String defaultValue, String description, boolean enumType, Set<String> enums) {
+    public static String toJson(String name, String kind, Boolean required, String type, String defaultValue, String description,
+                                boolean enumType, Set<String> enums, boolean oneOfType, Set<String> oneOffTypes) {
         String typeName = JsonSchemaHelper.getType(type, enumType);
 
         StringBuilder sb = new StringBuilder();
@@ -53,6 +54,16 @@ final class JsonSchemaHelper {
             sb.append(", \"enum\": [ ");
             sb.append(enumValues.toString());
             sb.append(" ]");
+        } else if (oneOfType) {
+            sb.append(Strings.doubleQuote("object"));
+            sb.append(", \"javaType\": \"" + type + "\"");
+            CollectionStringBuffer oneOfValues = new CollectionStringBuffer();
+            for (Object value : oneOffTypes) {
+                oneOfValues.append(Strings.doubleQuote(value.toString()));
+            }
+            sb.append(", \"oneOf\": [ ");
+            sb.append(oneOfValues.toString());
+            sb.append(" ]");
         } else if ("array".equals(typeName)) {
             sb.append(Strings.doubleQuote("array"));
             sb.append(", \"javaType\": \"" + type + "\"");

http://git-wip-us.apache.org/repos/asf/camel/blob/1ee75b43/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
index c81910c..215f8bd 100644
--- 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
@@ -16,16 +16,10 @@
  */
 package org.apache.camel.tools.apt;
 
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
 import java.io.PrintWriter;
-import java.io.Writer;
-import java.net.URI;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
-import javax.annotation.processing.Filer;
 import javax.annotation.processing.RoundEnvironment;
 import javax.annotation.processing.SupportedAnnotationTypes;
 import javax.annotation.processing.SupportedSourceVersion;
@@ -37,8 +31,6 @@ 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.tools.FileObject;
-import javax.tools.StandardLocation;
 import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
@@ -47,12 +39,16 @@ 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;
 
-// TODO: add support for @XmlElement @XmlElementRef
+// TODO: add support for @XmlElementRef (eg as used by choice)
 
 @SupportedAnnotationTypes({"javax.xml.bind.annotation.*"})
 @SupportedSourceVersion(SourceVersion.RELEASE_7)
 public class ModelDocumentationAnnotationProcessor extends AbstractAnnotationProcessor {
 
+    // special when using expression/predicates in the model
+    private final String ONE_OF_TYPE_NAME = "org.apache.camel.model.ExpressionSubElementDefinition";
+    private final String ONE_OF_LANGUAGES = "org.apache.camel.model.language.ExpressionDefinition";
+
     @Override
     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
         if (roundEnv.processingOver()) {
@@ -79,8 +75,15 @@ public class ModelDocumentationAnnotationProcessor extends AbstractAnnotationPro
         final XmlRootElement rootElement = classElement.getAnnotation(XmlRootElement.class);
         final String name = rootElement.name();
 
+        // 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
-        String fileName = classElement.getSimpleName().toString() + ".json";
         Func1<PrintWriter, Void> handler = new Func1<PrintWriter, Void>() {
             @Override
             public Void call(PrintWriter writer) {
@@ -125,7 +128,8 @@ public class ModelDocumentationAnnotationProcessor extends AbstractAnnotationPro
             // as its json we need to sanitize the docs
             String doc = entry.getDocumentationWithNotes();
             doc = sanitizeDescription(doc, false);
-            buffer.append(JsonSchemaHelper.toJson(entry.getName(), entry.getKind(), entry.isRequired(), entry.getType(), entry.getDefaultValue(), doc, entry.isEnumType(), entry.getEnums()));
+            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  }");
 
@@ -176,7 +180,7 @@ public class ModelDocumentationAnnotationProcessor extends AbstractAnnotationPro
                     String fieldTypeName = fieldType.toString();
                     TypeElement fieldTypeElement = findTypeElement(roundEnv, fieldTypeName);
 
-                    String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement);
+                    String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement, true);
                     boolean required = attribute.required();
 
                     // gather enums
@@ -194,13 +198,14 @@ public class ModelDocumentationAnnotationProcessor extends AbstractAnnotationPro
                         }
                     }
 
-                    EipOption ep = new EipOption(name, "attribute", fieldTypeName, required, "", "", docComment, isEnum, enums);
+                    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;
@@ -210,7 +215,7 @@ public class ModelDocumentationAnnotationProcessor extends AbstractAnnotationPro
                     String fieldTypeName = fieldType.toString();
                     TypeElement fieldTypeElement = findTypeElement(roundEnv, fieldTypeName);
 
-                    String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement);
+                    String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, classElement, true);
                     boolean required = element.required();
 
                     // gather enums
@@ -228,10 +233,29 @@ public class ModelDocumentationAnnotationProcessor extends AbstractAnnotationPro
                         }
                     }
 
-                    EipOption ep = new EipOption(name, "element", fieldTypeName, required, "", "", docComment, isEnum, enums);
+                    // gather oneOf expression/predicates which uses language
+                    Set<String> oneOfTypes = new LinkedHashSet<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);
                 }
-
             }
 
             // check super classes which may also have @UriParam fields
@@ -291,9 +315,11 @@ public class ModelDocumentationAnnotationProcessor extends AbstractAnnotationPro
         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 defaultValueNote,
-                          String documentation, boolean enumType, Set<String> enums) {
+                          String documentation, boolean enumType, Set<String> enums, boolean oneOf, Set<String> oneOfTypes) {
             this.name = name;
             this.kind = kind;
             this.type = type;
@@ -303,6 +329,8 @@ public class ModelDocumentationAnnotationProcessor extends AbstractAnnotationPro
             this.documentation = documentation;
             this.enumType = enumType;
             this.enums = enums;
+            this.oneOf = oneOf;
+            this.oneOfTypes = oneOfTypes;
         }
 
         public String getName() {
@@ -358,6 +386,14 @@ public class ModelDocumentationAnnotationProcessor extends AbstractAnnotationPro
             return enums;
         }
 
+        public boolean isOneOf() {
+            return oneOf;
+        }
+
+        public Set<String> getOneOfTypes() {
+            return oneOfTypes;
+        }
+
         @Override
         public boolean equals(Object o) {
             if (this == o) {