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 <davscl...@apache.org> Authored: Wed Dec 31 08:58:23 2014 +0100 Committer: Claus Ibsen <davscl...@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) {