This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit 59309b7c1d1116ad658f0b436abefd3e4b786f19 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Tue Aug 13 09:03:36 2019 +0200 CAMEL-13850: Optimize model classes to provide changeable properties that support property placeholders to avoid reflection. Work in progress. --- .../apt/CoreEipAnnotationProcessorHelper.java | 180 +----------------- .../tools/apt/PropertyPlaceholderGenerator.java | 206 +++++++++++++++++++++ 2 files changed, 212 insertions(+), 174 deletions(-) diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessorHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessorHelper.java index 93f57a0..f003530 100644 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessorHelper.java +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessorHelper.java @@ -17,7 +17,6 @@ package org.apache.camel.tools.apt; import java.io.PrintWriter; -import java.io.Writer; import java.util.Comparator; import java.util.HashSet; import java.util.LinkedHashSet; @@ -35,8 +34,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.Diagnostic; -import javax.tools.JavaFileObject; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementRef; @@ -47,17 +44,16 @@ import javax.xml.bind.annotation.XmlValue; import org.apache.camel.spi.AsPredicate; import org.apache.camel.spi.Metadata; -import org.apache.camel.tools.apt.helper.IOHelper; import org.apache.camel.tools.apt.helper.JsonSchemaHelper; import org.apache.camel.tools.apt.helper.Strings; -import static org.apache.camel.tools.apt.AnnotationProcessorHelper.dumpExceptionToErrorFile; import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findJavaDoc; import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findTypeElement; import static org.apache.camel.tools.apt.AnnotationProcessorHelper.findTypeElementChildren; import static org.apache.camel.tools.apt.AnnotationProcessorHelper.hasSuperClass; import static org.apache.camel.tools.apt.AnnotationProcessorHelper.implementsInterface; import static org.apache.camel.tools.apt.AnnotationProcessorHelper.processFile; +import static org.apache.camel.tools.apt.PropertyPlaceholderGenerator.generatePropertyPlaceholderDefinitionsHelper; 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; @@ -135,7 +131,7 @@ public class CoreEipAnnotationProcessorHelper { // if last then generate source code for helper that contains all the generated property placeholder providers // (this allows fast property placeholders at runtime without reflection overhead) if (last) { - writePropertyPlaceholderDefinitionsHelper(processingEnv, roundEnv, propertyPlaceholderDefinitions); + generatePropertyPlaceholderDefinitionsHelper(processingEnv, roundEnv, propertyPlaceholderDefinitions); } } @@ -182,7 +178,7 @@ public class CoreEipAnnotationProcessorHelper { String cn = def + "PropertyPlaceholderProvider"; String fqn = "org.apache.camel.model.placeholder." + cn; - doWritePropertyPlaceholderProviderSource(processingEnv, parent, def, fqnDef, cn, fqn, options); + PropertyPlaceholderGenerator.generatePropertyPlaceholderProviderSource(processingEnv, parent, def, fqnDef, cn, fqn, options); propertyPlaceholderDefinitions.add(fqnDef); // we also need to generate from when we generate route as from can also configure property placeholders @@ -196,175 +192,11 @@ public class CoreEipAnnotationProcessorHelper { options.add(new EipOption("id", null, null, "java.lang.String", false, null, null, false, null, false, null, false, null, false)); options.add(new EipOption("uri", null, null, "java.lang.String", false, null, null, false, null, false, null, false, null, false)); - doWritePropertyPlaceholderProviderSource(processingEnv, parent, def, fqnDef, cn, fqn, options); + PropertyPlaceholderGenerator.generatePropertyPlaceholderProviderSource(processingEnv, parent, def, fqnDef, cn, fqn, options); propertyPlaceholderDefinitions.add(fqnDef); } } - private void doWritePropertyPlaceholderProviderSource(ProcessingEnvironment processingEnv, TypeElement parent, - String def, String fqnDef, String cn, String fqn, - Set<EipOption> options) { - - Writer w = null; - try { - JavaFileObject src = processingEnv.getFiler().createSourceFile(fqn, parent); - w = src.openWriter(); - - w.write("/* Generated by camel-apt */\n"); - w.write("package org.apache.camel.model.placeholder;\n"); - w.write("\n"); - w.write("import java.util.HashMap;\n"); - w.write("import java.util.Map;\n"); - w.write("import java.util.function.Consumer;\n"); - w.write("import java.util.function.Supplier;\n"); - w.write("\n"); - w.write("import org.apache.camel.CamelContext;\n"); - w.write("import " + fqnDef + ";\n"); - w.write("import org.apache.camel.spi.PropertyPlaceholderConfigurer;\n"); - w.write("\n"); - w.write("public class " + cn + " implements PropertyPlaceholderConfigurer {\n"); - w.write("\n"); - w.write(" private final Map<String, Supplier<String>> readPlaceholders = new HashMap<>();\n"); - w.write(" private final Map<String, Consumer<String>> writePlaceholders = new HashMap<>();\n"); - w.write("\n"); - - // add constructor - w.write(" public " + cn + "(Object obj) {\n"); - w.write(" " + def + " definition = (" + def + ") obj;\n"); - w.write("\n"); - - // only include string types as they are the only ones we can use for property placeholders - boolean found = false; - for (EipOption option : options) { - if ("java.lang.String".equals(option.getType())) { - found = true; - String getOrSet = sanitizePropertyPlaceholderOptionName(def, option); - getOrSet = Character.toUpperCase(getOrSet.charAt(0)) + getOrSet.substring(1); - w.write(" readPlaceholders.put(\"" + option.getName() + "\", definition::get" + getOrSet + ");\n"); - w.write(" writePlaceholders.put(\"" + option.getName() + "\", definition::set" + getOrSet + ");\n"); - } - } - if (!found) { - w.write("\n"); - } - - w.write(" }\n"); - w.write("\n"); - w.write(" @Override\n"); - w.write(" public Map<String, Supplier<String>> getReadPropertyPlaceholderOptions(CamelContext camelContext) {\n"); - w.write(" return readPlaceholders;\n"); - w.write(" }\n"); - w.write("\n"); - w.write(" @Override\n"); - w.write(" public Map<String, Consumer<String>> getWritePropertyPlaceholderOptions(CamelContext camelContext) {\n"); - w.write(" return writePlaceholders;\n"); - w.write(" }\n"); - w.write("\n"); - w.write("}\n"); - w.write("\n"); - } catch (Exception e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Unable to process annotated elements in " + getClass().getSimpleName() + ": " + e.getMessage()); - dumpExceptionToErrorFile("camel-apt-error.log", "Error processing annotation in " + getClass().getSimpleName(), e); - } finally { - IOHelper.close(w); - } - } - - /** - * Some models have different setter/getter names vs the xml name (eg as defined in @XmlAttribute). - * So we need to correct this using this method. - */ - public String sanitizePropertyPlaceholderOptionName(String def, EipOption option) { - if ("SimpleExpression".equals(def) || "JsonPathExpression".equals(def)) { - if ("resultType".equals(option.getName())) { - return "resultTypeName"; - } - } else if ("EnrichDefinition".equals(def) || "PollEnrichDefinition".equals(def) || "ClaimCheckDefinition".equals(def)) { - if ("strategyRef".equals(option.getName())) { - return "aggregationStrategyRef"; - } else if ("strategyMethodName".equals(option.getName())) { - return "aggregationStrategyMethodName"; - } else if ("strategyMethodAllowNull".equals(option.getName())) { - return "aggregationStrategyMethodAllowNull"; - } - } else if ("MethodCallExpression".equals(def)) { - if ("beanType".equals(option.getName())) { - return "beanTypeName"; - } - } else if ("XPathExpression".equals(def)) { - if ("documentType".equals(option.getName())) { - return "documentTypeName"; - } else if ("resultType".equals(option.getName())) { - return "resultTypeName"; - } - } else if ("WireTapDefinition".equals(def)) { - if ("processorRef".equals(option.getName())) { - return "newExchangeProcessorRef"; - } - } else if ("TidyMarkupDataFormat".equals(def)) { - if ("dataObjectType".equals(option.getName())) { - return "dataObjectTypeName"; - } - } else if ("BindyDataFormat".equals(def)) { - if ("classType".equals(option.getName())) { - return "classTypeAsString"; - } - } - - return option.getName(); - } - - private void writePropertyPlaceholderDefinitionsHelper(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, - Set<String> propertyPlaceholderDefinitions) { - Writer w = null; - try { - JavaFileObject src = processingEnv.getFiler().createSourceFile("org.apache.camel.model.placeholder.DefinitionPropertiesPlaceholderProviderHelper"); - w = src.openWriter(); - - w.write("/* Generated by camel-apt */\n"); - w.write("package org.apache.camel.model.placeholder;\n"); - w.write("\n"); - w.write("import java.util.HashMap;\n"); - w.write("import java.util.Map;\n"); - w.write("import java.util.Optional;\n"); - w.write("import java.util.function.Function;\n"); - w.write("import java.util.function.Supplier;\n"); - w.write("\n"); - w.write("import org.apache.camel.spi.PropertyPlaceholderConfigurer;\n"); - for (String def : propertyPlaceholderDefinitions) { - w.write("import " + def + ";\n"); - } - w.write("\n"); - w.write("public class DefinitionPropertiesPlaceholderProviderHelper {\n"); - w.write("\n"); - w.write(" private static final Map<Class, Function<Object, PropertyPlaceholderConfigurer>> MAP;\n"); - w.write(" static {\n"); - w.write(" Map<Class, Function<Object, PropertyPlaceholderConfigurer>> map = new HashMap<>(" + propertyPlaceholderDefinitions.size() + ");\n"); - for (String def : propertyPlaceholderDefinitions) { - String cn = def.substring(def.lastIndexOf('.') + 1); - w.write(" map.put(" + cn + ".class, " + cn + "PropertyPlaceholderProvider::new);\n"); - } - w.write(" MAP = map;\n"); - w.write(" }\n"); - w.write("\n"); - w.write(" public static Optional<PropertyPlaceholderConfigurer> provider(Object definition) {\n"); - w.write(" Function<Object, PropertyPlaceholderConfigurer> func = MAP.get(definition.getClass());\n"); - w.write(" if (func != null) {\n"); - w.write(" return Optional.of(func.apply(definition));\n"); - w.write(" }\n"); - w.write(" return Optional.empty();\n"); - w.write(" }\n"); - w.write("\n"); - w.write("}\n"); - w.write("\n"); - } catch (Exception e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Unable to process annotated elements in " + getClass().getSimpleName() + ": " + e.getMessage()); - dumpExceptionToErrorFile("camel-apt-error.log", "Error processing annotation in " + getClass().getSimpleName(), e); - } finally { - IOHelper.close(w); - } - } - public String createParameterJsonSchema(EipModel eipModel, Set<EipOption> options) { StringBuilder buffer = new StringBuilder("{"); // eip model @@ -1277,7 +1109,7 @@ public class CoreEipAnnotationProcessorHelper { return false; } - private static final class EipModel { + public static final class EipModel { private String name; private String title; @@ -1379,7 +1211,7 @@ public class CoreEipAnnotationProcessorHelper { } } - private static final class EipOption { + public static final class EipOption { private String name; private String displayName; diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/PropertyPlaceholderGenerator.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/PropertyPlaceholderGenerator.java new file mode 100644 index 0000000..263f86e --- /dev/null +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/PropertyPlaceholderGenerator.java @@ -0,0 +1,206 @@ +/* + * 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.Writer; +import java.util.Set; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; + +import org.apache.camel.tools.apt.helper.IOHelper; + +import static org.apache.camel.tools.apt.AnnotationProcessorHelper.dumpExceptionToErrorFile; + +public class PropertyPlaceholderGenerator { + + public static void generatePropertyPlaceholderProviderSource(ProcessingEnvironment processingEnv, TypeElement parent, + String def, String fqnDef, String cn, String fqn, + Set<CoreEipAnnotationProcessorHelper.EipOption> options) { + + Writer w = null; + try { + JavaFileObject src = processingEnv.getFiler().createSourceFile(fqn, parent); + w = src.openWriter(); + + w.write("/* Generated by camel-apt */\n"); + w.write("package org.apache.camel.model.placeholder;\n"); + w.write("\n"); + w.write("import java.util.HashMap;\n"); + w.write("import java.util.Map;\n"); + w.write("import java.util.function.Consumer;\n"); + w.write("import java.util.function.Supplier;\n"); + w.write("\n"); + w.write("import org.apache.camel.CamelContext;\n"); + w.write("import " + fqnDef + ";\n"); + w.write("import org.apache.camel.spi.PropertyPlaceholderConfigurer;\n"); + w.write("\n"); + w.write("/**\n"); + w.write(" * Source code generated by org.apache.camel:apt\n"); + w.write(" */\n"); + w.write("public class " + cn + " implements PropertyPlaceholderConfigurer {\n"); + w.write("\n"); + w.write(" private final Map<String, Supplier<String>> readPlaceholders = new HashMap<>();\n"); + w.write(" private final Map<String, Consumer<String>> writePlaceholders = new HashMap<>();\n"); + w.write("\n"); + + // add constructor + w.write(" public " + cn + "(Object obj) {\n"); + w.write(" " + def + " definition = (" + def + ") obj;\n"); + w.write("\n"); + + // only include string types as they are the only ones we can use for property placeholders + boolean found = false; + for (CoreEipAnnotationProcessorHelper.EipOption option : options) { + if ("java.lang.String".equals(option.getType())) { + found = true; + String getOrSet = sanitizePropertyPlaceholderOptionName(def, option); + getOrSet = Character.toUpperCase(getOrSet.charAt(0)) + getOrSet.substring(1); + w.write(" readPlaceholders.put(\"" + option.getName() + "\", definition::get" + getOrSet + ");\n"); + w.write(" writePlaceholders.put(\"" + option.getName() + "\", definition::set" + getOrSet + ");\n"); + } + } + if (!found) { + w.write("\n"); + } + + w.write(" }\n"); + w.write("\n"); + w.write(" @Override\n"); + w.write(" public Map<String, Supplier<String>> getReadPropertyPlaceholderOptions(CamelContext camelContext) {\n"); + w.write(" return readPlaceholders;\n"); + w.write(" }\n"); + w.write("\n"); + w.write(" @Override\n"); + w.write(" public Map<String, Consumer<String>> getWritePropertyPlaceholderOptions(CamelContext camelContext) {\n"); + w.write(" return writePlaceholders;\n"); + w.write(" }\n"); + w.write("\n"); + w.write("}\n"); + w.write("\n"); + } catch (Exception e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Unable to generate source code file: " + fqn + ": " + e.getMessage()); + dumpExceptionToErrorFile("camel-apt-error.log", "Unable to generate source code file: " + fqn, e); + } finally { + IOHelper.close(w); + } + } + + public static void generatePropertyPlaceholderDefinitionsHelper(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, + Set<String> propertyPlaceholderDefinitions) { + + String fqn = "org.apache.camel.model.placeholder.DefinitionPropertiesPlaceholderProviderHelper"; + + Writer w = null; + try { + JavaFileObject src = processingEnv.getFiler().createSourceFile(fqn); + w = src.openWriter(); + + w.write("/* Generated by camel-apt */\n"); + w.write("package org.apache.camel.model.placeholder;\n"); + w.write("\n"); + w.write("import java.util.HashMap;\n"); + w.write("import java.util.Map;\n"); + w.write("import java.util.Optional;\n"); + w.write("import java.util.function.Function;\n"); + w.write("import java.util.function.Supplier;\n"); + w.write("\n"); + w.write("import org.apache.camel.spi.PropertyPlaceholderConfigurer;\n"); + for (String def : propertyPlaceholderDefinitions) { + w.write("import " + def + ";\n"); + } + w.write("\n"); + w.write("/**\n"); + w.write(" * Source code generated by org.apache.camel:apt\n"); + w.write(" */\n"); + w.write("public class DefinitionPropertiesPlaceholderProviderHelper {\n"); + w.write("\n"); + w.write(" private static final Map<Class, Function<Object, PropertyPlaceholderConfigurer>> MAP;\n"); + w.write(" static {\n"); + w.write(" Map<Class, Function<Object, PropertyPlaceholderConfigurer>> map = new HashMap<>(" + propertyPlaceholderDefinitions.size() + ");\n"); + for (String def : propertyPlaceholderDefinitions) { + String cn = def.substring(def.lastIndexOf('.') + 1); + w.write(" map.put(" + cn + ".class, " + cn + "PropertyPlaceholderProvider::new);\n"); + } + w.write(" MAP = map;\n"); + w.write(" }\n"); + w.write("\n"); + w.write(" public static Optional<PropertyPlaceholderConfigurer> provider(Object definition) {\n"); + w.write(" Function<Object, PropertyPlaceholderConfigurer> func = MAP.get(definition.getClass());\n"); + w.write(" if (func != null) {\n"); + w.write(" return Optional.of(func.apply(definition));\n"); + w.write(" }\n"); + w.write(" return Optional.empty();\n"); + w.write(" }\n"); + w.write("\n"); + w.write("}\n"); + w.write("\n"); + } catch (Exception e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Unable to generate source code file: " + fqn + ": " + e.getMessage()); + dumpExceptionToErrorFile("camel-apt-error.log", "Unable to generate source code file: " + fqn, e); + } finally { + IOHelper.close(w); + } + } + + /** + * Some models have different setter/getter names vs the xml name (eg as defined in @XmlAttribute). + * So we need to correct this using this method. + */ + private static String sanitizePropertyPlaceholderOptionName(String def, CoreEipAnnotationProcessorHelper.EipOption option) { + if ("SimpleExpression".equals(def) || "JsonPathExpression".equals(def)) { + if ("resultType".equals(option.getName())) { + return "resultTypeName"; + } + } else if ("EnrichDefinition".equals(def) || "PollEnrichDefinition".equals(def) || "ClaimCheckDefinition".equals(def)) { + if ("strategyRef".equals(option.getName())) { + return "aggregationStrategyRef"; + } else if ("strategyMethodName".equals(option.getName())) { + return "aggregationStrategyMethodName"; + } else if ("strategyMethodAllowNull".equals(option.getName())) { + return "aggregationStrategyMethodAllowNull"; + } + } else if ("MethodCallExpression".equals(def)) { + if ("beanType".equals(option.getName())) { + return "beanTypeName"; + } + } else if ("XPathExpression".equals(def)) { + if ("documentType".equals(option.getName())) { + return "documentTypeName"; + } else if ("resultType".equals(option.getName())) { + return "resultTypeName"; + } + } else if ("WireTapDefinition".equals(def)) { + if ("processorRef".equals(option.getName())) { + return "newExchangeProcessorRef"; + } + } else if ("TidyMarkupDataFormat".equals(def)) { + if ("dataObjectType".equals(option.getName())) { + return "dataObjectTypeName"; + } + } else if ("BindyDataFormat".equals(def)) { + if ("classType".equals(option.getName())) { + return "classTypeAsString"; + } + } + + return option.getName(); + } + +}