CAMEL-9482: Generate json schema model for camel-spring
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/3f14b029 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/3f14b029 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/3f14b029 Branch: refs/heads/master Commit: 3f14b0295acc72fc9534de7fb1cac9fbc21383f1 Parents: 87ba55d Author: Claus Ibsen <[email protected]> Authored: Wed Aug 10 12:29:01 2016 +0200 Committer: Claus Ibsen <[email protected]> Committed: Wed Aug 10 19:08:13 2016 +0200 ---------------------------------------------------------------------- .../camel/spring/CamelContextFactoryBean.java | 19 +- .../apt/CamelContextAnnotationProcessor.java | 664 +++++++++++++++++++ .../javax.annotation.processing.Processor | 1 + 3 files changed, 675 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/3f14b029/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java ---------------------------------------------------------------------- diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java index 42def32..60547ee 100644 --- a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java +++ b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java @@ -63,6 +63,7 @@ import org.apache.camel.model.remote.KubernetesConfigurationDefinition; import org.apache.camel.model.remote.RibbonConfigurationDefinition; import org.apache.camel.model.rest.RestConfigurationDefinition; import org.apache.camel.model.rest.RestDefinition; +import org.apache.camel.spi.Metadata; import org.apache.camel.spi.PackageScanFilter; import org.apache.camel.spi.Registry; import org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer; @@ -99,7 +100,7 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr private String dependsOn; @XmlAttribute private String trace; - @XmlAttribute + @XmlAttribute @Metadata(defaultValue = "true") private String messageHistory; @XmlAttribute private String logExhaustedMessageBody; @@ -111,34 +112,34 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr private String handleFault; @XmlAttribute private String errorHandlerRef; - @XmlAttribute + @XmlAttribute @Metadata(defaultValue = "true") private String autoStartup; - @XmlAttribute + @XmlAttribute @Metadata(defaultValue = "true") private String shutdownEager; @XmlAttribute private String useMDCLogging; - @XmlAttribute + @XmlAttribute @Metadata(defaultValue = "true") private String useBreadcrumb; @XmlAttribute private String allowUseOriginalMessage; - @XmlAttribute + @XmlAttribute @Metadata(defaultValue = "true") private String runtimeEndpointRegistryEnabled; @XmlAttribute private String managementNamePattern; @XmlAttribute private String threadNamePattern; - @XmlAttribute + @XmlAttribute @Metadata(defaultValue = "Default") private ShutdownRoute shutdownRoute; - @XmlAttribute + @XmlAttribute @Metadata(defaultValue = "CompleteCurrentTaskOnly") private ShutdownRunningTask shutdownRunningTask; @XmlAttribute @Deprecated private Boolean lazyLoadTypeConverters; @XmlAttribute private Boolean typeConverterStatisticsEnabled; - @XmlAttribute + @XmlAttribute @Metadata(defaultValue = "Override") private TypeConverterExists typeConverterExists; - @XmlAttribute + @XmlAttribute @Metadata(defaultValue = "WARN") private LoggingLevel typeConverterExistsLoggingLevel; @XmlElement(name = "properties") private PropertiesDefinition properties; http://git-wip-us.apache.org/repos/asf/camel/blob/3f14b029/tooling/apt/src/main/java/org/apache/camel/tools/apt/CamelContextAnnotationProcessor.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/CamelContextAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/CamelContextAnnotationProcessor.java new file mode 100644 index 0000000..3538ef6 --- /dev/null +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/CamelContextAnnotationProcessor.java @@ -0,0 +1,664 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.tools.apt; + +import java.io.PrintWriter; +import java.util.Comparator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.Elements; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElements; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + +import org.apache.camel.spi.Metadata; +import org.apache.camel.tools.apt.helper.JsonSchemaHelper; +import org.apache.camel.tools.apt.helper.Strings; + +import static org.apache.camel.tools.apt.helper.JsonSchemaHelper.sanitizeDescription; +import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName; +import static org.apache.camel.tools.apt.helper.Strings.isNullOrEmpty; +import static org.apache.camel.tools.apt.helper.Strings.safeNull; + +/** + * Process camel-spring's <camelContext> and generate json schema documentation + */ +@SupportedAnnotationTypes({"javax.xml.bind.annotation.*", "org.apache.camel.spi.Label"}) +@SupportedSourceVersion(SourceVersion.RELEASE_8) +public class CamelContextAnnotationProcessor extends AbstractAnnotationProcessor { + + private static final String ONE_OF_TYPE_NAME = ""; + private boolean skipUnwanted = true; + + @Override + public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { + try { + if (roundEnv.processingOver()) { + return true; + } + + Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(XmlRootElement.class); + for (Element element : elements) { + if (element instanceof TypeElement) { + processModelClass(roundEnv, (TypeElement) element); + } + } + } catch (Throwable e) { + dumpExceptionToErrorFile("camel-apt-error.log", "Error processing CamelContext model", e); + } + return true; + } + + protected void processModelClass(final RoundEnvironment roundEnv, final TypeElement classElement) { + // must be from org.apache.camel.model + final String javaTypeName = canonicalClassName(classElement.getQualifiedName().toString()); + String packageName = javaTypeName.substring(0, javaTypeName.lastIndexOf(".")); + if (!javaTypeName.startsWith("org.apache.camel.spring")) { + return; + } + + // skip abstract classes + if (classElement.getModifiers().contains(Modifier.ABSTRACT)) { + return; + } + + // skip unwanted classes which are "abstract" holders + if (skipUnwanted) { + if (classElement.getQualifiedName().toString().equals(ONE_OF_TYPE_NAME)) { + return; + } + } + + final XmlRootElement rootElement = classElement.getAnnotation(XmlRootElement.class); + if (rootElement == null) { + return; + } + + String aName = rootElement.name(); + if (isNullOrEmpty(aName) || "##default".equals(aName)) { + XmlType typeElement = classElement.getAnnotation(XmlType.class); + aName = typeElement.name(); + } + final String name = aName; + + // lets use the xsd name as the file name + String fileName; + if (isNullOrEmpty(name) || "##default".equals(name)) { + fileName = classElement.getSimpleName().toString() + ".json"; + } else { + fileName = name + ".json"; + } + + // write json schema + Func1<PrintWriter, Void> handler = new Func1<PrintWriter, Void>() { + @Override + public Void call(PrintWriter writer) { + writeJSonSchemeDocumentation(writer, roundEnv, classElement, rootElement, javaTypeName, name); + return null; + } + }; + processFile(packageName, fileName, handler); + } + + protected void writeJSonSchemeDocumentation(PrintWriter writer, RoundEnvironment roundEnv, TypeElement classElement, XmlRootElement rootElement, + String javaTypeName, String modelName) { + // gather eip information + EipModel eipModel = findEipModelProperties(roundEnv, classElement, javaTypeName, modelName); + + // collect eip information + Set<EipOption> eipOptions = new TreeSet<EipOption>(new EipOptionComparator(eipModel)); + findClassProperties(writer, roundEnv, eipOptions, classElement, classElement, "", modelName); + + String json = createParameterJsonSchema(eipModel, eipOptions); + writer.println(json); + } + + public String createParameterJsonSchema(EipModel eipModel, Set<EipOption> options) { + StringBuilder buffer = new StringBuilder("{"); + // eip model + buffer.append("\n \"model\": {"); + buffer.append("\n \"kind\": \"").append("model").append("\","); + buffer.append("\n \"name\": \"").append(eipModel.getName()).append("\","); + if (eipModel.getTitle() != null) { + buffer.append("\n \"title\": \"").append(eipModel.getTitle()).append("\","); + } else { + // fallback and use name as title + buffer.append("\n \"title\": \"").append(asTitle(eipModel.getName())).append("\","); + } + buffer.append("\n \"description\": \"").append(safeNull(eipModel.getDescription())).append("\","); + buffer.append("\n \"javaType\": \"").append(eipModel.getJavaType()).append("\","); + buffer.append("\n \"label\": \"").append(safeNull(eipModel.getLabel())).append("\""); + buffer.append("\n },"); + + buffer.append("\n \"properties\": {"); + boolean first = true; + for (EipOption entry : options) { + if (first) { + first = false; + } else { + buffer.append(","); + } + buffer.append("\n "); + // as its json we need to sanitize the docs + String doc = entry.getDocumentation(); + doc = sanitizeDescription(doc, false); + buffer.append(JsonSchemaHelper.toJson(entry.getName(), entry.getKind(), entry.isRequired(), entry.getType(), entry.getDefaultValue(), doc, + entry.isDeprecated(), false, null, null, entry.isEnumType(), entry.getEnums(), entry.isOneOf(), entry.getOneOfTypes(), null, null, false)); + } + buffer.append("\n }"); + + buffer.append("\n}\n"); + return buffer.toString(); + } + + protected EipModel findEipModelProperties(RoundEnvironment roundEnv, TypeElement classElement, String javaTypeName, String name) { + EipModel model = new EipModel(); + model.setJavaType(javaTypeName); + model.setName(name); + + Metadata metadata = classElement.getAnnotation(Metadata.class); + if (metadata != null) { + if (!Strings.isNullOrEmpty(metadata.label())) { + model.setLabel(metadata.label()); + } + if (!Strings.isNullOrEmpty(metadata.title())) { + model.setTitle(metadata.title()); + } + } + + // favor to use class javadoc of component as description + if (model.getJavaType() != null) { + Elements elementUtils = processingEnv.getElementUtils(); + TypeElement typeElement = findTypeElement(roundEnv, model.getJavaType()); + if (typeElement != null) { + String doc = elementUtils.getDocComment(typeElement); + if (doc != null) { + // need to sanitize the description first (we only want a summary) + doc = sanitizeDescription(doc, true); + // the javadoc may actually be empty, so only change the doc if we got something + if (!Strings.isNullOrEmpty(doc)) { + model.setDescription(doc); + } + } + } + } + + return model; + } + + protected void findClassProperties(PrintWriter writer, RoundEnvironment roundEnv, Set<EipOption> eipOptions, + TypeElement originalClassType, TypeElement classElement, String prefix, String modelName) { + while (true) { + List<VariableElement> fieldElements = ElementFilter.fieldsIn(classElement.getEnclosedElements()); + for (VariableElement fieldElement : fieldElements) { + + String fieldName = fieldElement.getSimpleName().toString(); + + XmlAttribute attribute = fieldElement.getAnnotation(XmlAttribute.class); + if (attribute != null) { + boolean skip = processAttribute(roundEnv, originalClassType, classElement, fieldElement, fieldName, attribute, eipOptions, prefix, modelName); + if (skip) { + continue; + } + } + + XmlElements elements = fieldElement.getAnnotation(XmlElements.class); + if (elements != null) { + processElements(roundEnv, classElement, elements, fieldElement, eipOptions, prefix); + } + + XmlElement element = fieldElement.getAnnotation(XmlElement.class); + if (element != null) { + if ("rests".equals(fieldName)) { + processRests(roundEnv, classElement, element, fieldElement, fieldName, eipOptions, prefix); + } else if ("routes".equals(fieldName)) { + processRoutes(roundEnv, classElement, element, fieldElement, fieldName, eipOptions, prefix); + } else { + processElement(roundEnv, classElement, element, fieldElement, eipOptions, prefix); + } + } + } + + // check super classes which may also have fields + TypeElement baseTypeElement = null; + TypeMirror superclass = classElement.getSuperclass(); + if (superclass != null) { + String superClassName = canonicalClassName(superclass.toString()); + baseTypeElement = findTypeElement(roundEnv, superClassName); + } + if (baseTypeElement != null) { + classElement = baseTypeElement; + } else { + break; + } + } + } + + private boolean processAttribute(RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement classElement, VariableElement fieldElement, + String fieldName, XmlAttribute attribute, Set<EipOption> eipOptions, String prefix, String modelName) { + Elements elementUtils = processingEnv.getElementUtils(); + + String name = attribute.name(); + if (isNullOrEmpty(name) || "##default".equals(name)) { + name = fieldName; + } + + // lets skip some unwanted attributes + if (skipUnwanted) { + } + + name = prefix + name; + TypeMirror fieldType = fieldElement.asType(); + String fieldTypeName = fieldType.toString(); + TypeElement fieldTypeElement = findTypeElement(roundEnv, fieldTypeName); + + String defaultValue = findDefaultValue(fieldElement, fieldTypeName); + String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true); + boolean required = attribute.required(); + // metadata may overrule element required + required = findRequired(fieldElement, required); + + // gather enums + Set<String> enums = new TreeSet<String>(); + boolean isEnum = fieldTypeElement != null && fieldTypeElement.getKind() == ElementKind.ENUM; + if (isEnum) { + TypeElement enumClass = findTypeElement(roundEnv, fieldTypeElement.asType().toString()); + // find all the enum constants which has the possible enum value that can be used + List<VariableElement> fields = ElementFilter.fieldsIn(enumClass.getEnclosedElements()); + for (VariableElement var : fields) { + if (var.getKind() == ElementKind.ENUM_CONSTANT) { + String val = var.toString(); + enums.add(val); + } + } + } + + boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null; + + EipOption ep = new EipOption(name, "attribute", fieldTypeName, required, defaultValue, docComment, deprecated, isEnum, enums, false, null); + eipOptions.add(ep); + + return false; + } + + /** + * Special for processing an @XmlElement routes field + */ + private void processRoutes(RoundEnvironment roundEnv, TypeElement originalClassType, XmlElement element, + VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) { + + TypeMirror fieldType = fieldElement.asType(); + String fieldTypeName = fieldType.toString(); + + Set<String> oneOfTypes = new TreeSet<String>(); + oneOfTypes.add("route"); + + EipOption ep = new EipOption("route", "element", fieldTypeName, false, "", "Contains the Camel routes", false, false, null, true, oneOfTypes); + eipOptions.add(ep); + } + + /** + * Special for processing an @XmlElement rests field + */ + private void processRests(RoundEnvironment roundEnv, TypeElement originalClassType, XmlElement element, + VariableElement fieldElement, String fieldName, Set<EipOption> eipOptions, String prefix) { + + TypeMirror fieldType = fieldElement.asType(); + String fieldTypeName = fieldType.toString(); + + Set<String> oneOfTypes = new TreeSet<String>(); + oneOfTypes.add("rest"); + + EipOption ep = new EipOption("rest", "element", fieldTypeName, false, "", "Contains the rest services defined using the rest-dsl", false, false, null, true, oneOfTypes); + eipOptions.add(ep); + } + + private void processElement(RoundEnvironment roundEnv, TypeElement classElement, XmlElement element, VariableElement fieldElement, + Set<EipOption> eipOptions, String prefix) { + Elements elementUtils = processingEnv.getElementUtils(); + + String fieldName; + fieldName = fieldElement.getSimpleName().toString(); + if (element != null) { + + String kind = "element"; + String name = element.name(); + if (isNullOrEmpty(name) || "##default".equals(name)) { + name = fieldName; + } + name = prefix + name; + TypeMirror fieldType = fieldElement.asType(); + String fieldTypeName = fieldType.toString(); + TypeElement fieldTypeElement = findTypeElement(roundEnv, fieldTypeName); + + String defaultValue = findDefaultValue(fieldElement, fieldTypeName); + String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true); + boolean required = element.required(); + // metadata may overrule element required + required = findRequired(fieldElement, required); + + // gather enums + Set<String> enums = new LinkedHashSet<String>(); + boolean isEnum = fieldTypeElement != null && fieldTypeElement.getKind() == ElementKind.ENUM; + if (isEnum) { + TypeElement enumClass = findTypeElement(roundEnv, fieldTypeElement.asType().toString()); + // find all the enum constants which has the possible enum value that can be used + List<VariableElement> fields = ElementFilter.fieldsIn(enumClass.getEnclosedElements()); + for (VariableElement var : fields) { + if (var.getKind() == ElementKind.ENUM_CONSTANT) { + String val = var.toString(); + enums.add(val); + } + } + } + + boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null; + + EipOption ep = new EipOption(name, kind, fieldTypeName, required, defaultValue, docComment, deprecated, isEnum, enums, false, null); + eipOptions.add(ep); + } + } + + private void processElements(RoundEnvironment roundEnv, TypeElement classElement, XmlElements elements, VariableElement fieldElement, + Set<EipOption> eipOptions, String prefix) { + Elements elementUtils = processingEnv.getElementUtils(); + + String fieldName; + fieldName = fieldElement.getSimpleName().toString(); + if (elements != null) { + String kind = "element"; + String name = fieldName; + name = prefix + name; + + TypeMirror fieldType = fieldElement.asType(); + String fieldTypeName = fieldType.toString(); + + String defaultValue = findDefaultValue(fieldElement, fieldTypeName); + String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, true); + + boolean required = false; + required = findRequired(fieldElement, required); + + // gather oneOf of the elements + Set<String> oneOfTypes = new TreeSet<String>(); + for (XmlElement element : elements.value()) { + String child = element.name(); + oneOfTypes.add(child); + } + + EipOption ep = new EipOption(name, kind, fieldTypeName, required, defaultValue, docComment, false, false, null, true, oneOfTypes); + eipOptions.add(ep); + } + } + + private String findDefaultValue(VariableElement fieldElement, String fieldTypeName) { + String defaultValue = null; + Metadata metadata = fieldElement.getAnnotation(Metadata.class); + if (metadata != null) { + if (!Strings.isNullOrEmpty(metadata.defaultValue())) { + defaultValue = metadata.defaultValue(); + } + } + if (defaultValue == null) { + // if its a boolean type, then we use false as the default + if ("boolean".equals(fieldTypeName) || "java.lang.Boolean".equals(fieldTypeName)) { + defaultValue = "false"; + } + } + + return defaultValue; + } + + private boolean findRequired(VariableElement fieldElement, boolean defaultValue) { + Metadata metadata = fieldElement.getAnnotation(Metadata.class); + if (metadata != null) { + if (!Strings.isNullOrEmpty(metadata.required())) { + defaultValue = "true".equals(metadata.required()); + } + } + return defaultValue; + } + + /** + * Capitializes the name as a title + * + * @param name the name + * @return as a title + */ + private static String asTitle(String name) { + StringBuilder sb = new StringBuilder(); + for (char c : name.toCharArray()) { + boolean upper = Character.isUpperCase(c); + boolean first = sb.length() == 0; + if (first) { + sb.append(Character.toUpperCase(c)); + } else if (upper) { + sb.append(' '); + sb.append(c); + } else { + sb.append(Character.toLowerCase(c)); + } + } + return sb.toString().trim(); + } + + private static final class EipModel { + + private String name; + private String title; + private String javaType; + private String label; + private String description; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getJavaType() { + return javaType; + } + + public void setJavaType(String javaType) { + this.javaType = javaType; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + } + + private static final class EipOption { + + private String name; + private String kind; + private String type; + private boolean required; + private String defaultValue; + private String documentation; + private boolean deprecated; + private boolean enumType; + private Set<String> enums; + private boolean oneOf; + private Set<String> oneOfTypes; + + private EipOption(String name, String kind, String type, boolean required, String defaultValue, String documentation, boolean deprecated, + boolean enumType, Set<String> enums, boolean oneOf, Set<String> oneOfTypes) { + this.name = name; + this.kind = kind; + this.type = type; + this.required = required; + this.defaultValue = defaultValue; + this.documentation = documentation; + this.deprecated = deprecated; + this.enumType = enumType; + this.enums = enums; + this.oneOf = oneOf; + this.oneOfTypes = oneOfTypes; + } + + public String getName() { + return name; + } + + public String getKind() { + return kind; + } + + public String getType() { + return type; + } + + public boolean isRequired() { + return required; + } + + public String getDefaultValue() { + return defaultValue; + } + + public String getDocumentation() { + return documentation; + } + + public boolean isDeprecated() { + return deprecated; + } + + public boolean isEnumType() { + return enumType; + } + + public Set<String> getEnums() { + return enums; + } + + public boolean isOneOf() { + return oneOf; + } + + public Set<String> getOneOfTypes() { + return oneOfTypes; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + EipOption that = (EipOption) o; + + if (!name.equals(that.name)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + } + + private static final class EipOptionComparator implements Comparator<EipOption> { + + private final EipModel model; + + private EipOptionComparator(EipModel model) { + this.model = model; + } + + @Override + public int compare(EipOption o1, EipOption o2) { + int weigth = weigth(o1); + int weigth2 = weigth(o2); + + if (weigth == weigth2) { + // keep the current order + return 1; + } else { + // sort according to weight + return weigth2 - weigth; + } + } + + private int weigth(EipOption o) { + String name = o.getName(); + + // these should be first + if ("expression".equals(name)) { + return 10; + } + + // these should be last + if ("description".equals(name)) { + return -10; + } else if ("id".equals(name)) { + return -9; + } else if ("pattern".equals(name) && "to".equals(model.getName())) { + // and pattern only for the to model + return -8; + } + return 0; + } + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/3f14b029/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 5148414..a1fa0cb 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,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # +org.apache.camel.tools.apt.CamelContextAnnotationProcessor org.apache.camel.tools.apt.EipAnnotationProcessor org.apache.camel.tools.apt.EndpointAnnotationProcessor
