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 daa273617c278361d95451bc78b24c746dca7b69
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Mon Aug 17 13:01:58 2020 +0200

    CAMEL-15394: PropertyBindingSupport should use configurer to set 
array/list/map on root objects without reflection. WIP
---
 core/camel-main/pom.xml                            |  19 ++
 .../java/org/apache/camel/main/MySecondBar.java    |  34 +++
 .../apache/camel/main/MySecondBarConfigurer.java   |  45 +++
 .../java/org/apache/camel/main/MySecondFoo.java    |  35 +++
 .../apache/camel/main/MySecondFooConfigurer.java   |  45 +++
 .../main/PropertyBindingSupportRootArrayTest.java  |  64 ++++
 ...yBindingSupportRootArrayWithConfigurerTest.java |  65 ++++
 .../org/apache/camel/configurer/MySecondBar        |   2 +
 .../org/apache/camel/configurer/MySecondFoo        |   2 +
 ...jo.java => AbstractGenerateConfigurerMojo.java} |  65 ++--
 .../maven/packaging/GenerateConfigurerMojo.java    | 335 +--------------------
 .../packaging/GenerateTestConfigurerMojo.java      |  77 +++++
 12 files changed, 417 insertions(+), 371 deletions(-)

diff --git a/core/camel-main/pom.xml b/core/camel-main/pom.xml
index c8b8802..7edbe4f 100644
--- a/core/camel-main/pom.xml
+++ b/core/camel-main/pom.xml
@@ -140,6 +140,25 @@
                     </execution>
                 </executions>
             </plugin>
+            <plugin>
+                <!-- we need to generate additional configurer classes -->
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-package-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>generate-test-configurer</id>
+                        <phase>process-test-classes</phase>
+                        <goals>
+                            <goal>generate-test-configurer</goal>
+                        </goals>
+                        <!-- only do these test classes -->
+                        <configuration>
+                            <discoverClasses>false</discoverClasses>
+                            
<classes>org.apache.camel.main.MySecondFoo,org.apache.camel.main.MySecondBar</classes>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 
diff --git 
a/core/camel-main/src/test/java/org/apache/camel/main/MySecondBar.java 
b/core/camel-main/src/test/java/org/apache/camel/main/MySecondBar.java
new file mode 100644
index 0000000..5110b07
--- /dev/null
+++ b/core/camel-main/src/test/java/org/apache/camel/main/MySecondBar.java
@@ -0,0 +1,34 @@
+/*
+ * 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.main;
+
+import java.util.List;
+
+import org.apache.camel.spi.Configurer;
+
+@Configurer
+public class MySecondBar {
+    private List<String> names;
+
+    public List<String> getNames() {
+        return names;
+    }
+
+    public void setNames(List<String> names) {
+        this.names = names;
+    }
+}
diff --git 
a/core/camel-main/src/test/java/org/apache/camel/main/MySecondBarConfigurer.java
 
b/core/camel-main/src/test/java/org/apache/camel/main/MySecondBarConfigurer.java
new file mode 100644
index 0000000..d31f486
--- /dev/null
+++ 
b/core/camel-main/src/test/java/org/apache/camel/main/MySecondBarConfigurer.java
@@ -0,0 +1,45 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.main;
+
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.main.MySecondBar;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@SuppressWarnings("unchecked")
+public class MySecondBarConfigurer extends 
org.apache.camel.support.component.PropertyConfigurerSupport implements 
GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String 
name, Object value, boolean ignoreCase) {
+        org.apache.camel.main.MySecondBar target = 
(org.apache.camel.main.MySecondBar) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "names":
+        case "Names": target.setNames(property(camelContext, 
java.util.List.class, value)); return true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public Map<String, Object> getAllOptions(Object target) {
+        Map<String, Object> answer = new CaseInsensitiveMap();
+        answer.put("Names", java.util.List.class);
+        return answer;
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        org.apache.camel.main.MySecondBar target = 
(org.apache.camel.main.MySecondBar) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "names":
+        case "Names": return target.getNames();
+        default: return null;
+        }
+    }
+}
+
diff --git 
a/core/camel-main/src/test/java/org/apache/camel/main/MySecondFoo.java 
b/core/camel-main/src/test/java/org/apache/camel/main/MySecondFoo.java
new file mode 100644
index 0000000..f3442a7
--- /dev/null
+++ b/core/camel-main/src/test/java/org/apache/camel/main/MySecondFoo.java
@@ -0,0 +1,35 @@
+/*
+ * 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.main;
+
+import java.util.List;
+
+import org.apache.camel.spi.Configurer;
+
+@Configurer
+public class MySecondFoo {
+
+    private List<MySecondBar> bars;
+
+    public List<MySecondBar> getBars() {
+        return bars;
+    }
+
+    public void setBars(List<MySecondBar> bars) {
+        this.bars = bars;
+    }
+}
diff --git 
a/core/camel-main/src/test/java/org/apache/camel/main/MySecondFooConfigurer.java
 
b/core/camel-main/src/test/java/org/apache/camel/main/MySecondFooConfigurer.java
new file mode 100644
index 0000000..5044c1f
--- /dev/null
+++ 
b/core/camel-main/src/test/java/org/apache/camel/main/MySecondFooConfigurer.java
@@ -0,0 +1,45 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.main;
+
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.main.MySecondFoo;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@SuppressWarnings("unchecked")
+public class MySecondFooConfigurer extends 
org.apache.camel.support.component.PropertyConfigurerSupport implements 
GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String 
name, Object value, boolean ignoreCase) {
+        org.apache.camel.main.MySecondFoo target = 
(org.apache.camel.main.MySecondFoo) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "bars":
+        case "Bars": target.setBars(property(camelContext, 
java.util.List.class, value)); return true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public Map<String, Object> getAllOptions(Object target) {
+        Map<String, Object> answer = new CaseInsensitiveMap();
+        answer.put("Bars", java.util.List.class);
+        return answer;
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        org.apache.camel.main.MySecondFoo target = 
(org.apache.camel.main.MySecondFoo) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "bars":
+        case "Bars": return target.getBars();
+        default: return null;
+        }
+    }
+}
+
diff --git 
a/core/camel-main/src/test/java/org/apache/camel/main/PropertyBindingSupportRootArrayTest.java
 
b/core/camel-main/src/test/java/org/apache/camel/main/PropertyBindingSupportRootArrayTest.java
new file mode 100644
index 0000000..a26cb63
--- /dev/null
+++ 
b/core/camel-main/src/test/java/org/apache/camel/main/PropertyBindingSupportRootArrayTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.main;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.spi.BeanIntrospection;
+import org.apache.camel.support.PropertyBindingSupport;
+import org.junit.jupiter.api.Test;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Unit test for PropertyBindingSupport
+ */
+public class PropertyBindingSupportRootArrayTest {
+
+    @Test
+    public void testRootArray() throws Exception {
+        CamelContext context = new DefaultCamelContext();
+
+        BeanIntrospection bi = 
context.adapt(ExtendedCamelContext.class).getBeanIntrospection();
+        bi.setExtendedStatistics(true);
+
+        context.start();
+
+        MySecondFoo target = new MySecondFoo();
+
+        PropertyBindingSupport.build()
+                .withCamelContext(context)
+                .withTarget(target)
+                .withProperty("bars[0]", "#class:" + 
MySecondBar.class.getName())
+                .withProperty("bars[0].names[0]", "a")
+                .withProperty("bars[0].names[1]", "b")
+                .withRemoveParameters(false).bind();
+
+        assertEquals(1, target.getBars().size());
+        assertEquals(2, target.getBars().get(0).getNames().size());
+        assertEquals("a", target.getBars().get(0).getNames().get(0));
+        assertEquals("b", target.getBars().get(0).getNames().get(1));
+
+        // no configurer so reflection is in use
+        assertEquals(3, bi.getInvokedCounter());
+
+        context.stop();
+    }
+
+}
diff --git 
a/core/camel-main/src/test/java/org/apache/camel/main/PropertyBindingSupportRootArrayWithConfigurerTest.java
 
b/core/camel-main/src/test/java/org/apache/camel/main/PropertyBindingSupportRootArrayWithConfigurerTest.java
new file mode 100644
index 0000000..2748e1a
--- /dev/null
+++ 
b/core/camel-main/src/test/java/org/apache/camel/main/PropertyBindingSupportRootArrayWithConfigurerTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.main;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.spi.BeanIntrospection;
+import org.apache.camel.support.PropertyBindingSupport;
+import org.junit.jupiter.api.Test;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Unit test for PropertyBindingSupport
+ */
+public class PropertyBindingSupportRootArrayWithConfigurerTest {
+
+    @Test
+    public void testRootArray() throws Exception {
+        CamelContext context = new DefaultCamelContext();
+
+        BeanIntrospection bi = 
context.adapt(ExtendedCamelContext.class).getBeanIntrospection();
+        bi.setExtendedStatistics(true);
+
+        context.start();
+
+        MySecondFoo target = new MySecondFoo();
+
+        PropertyBindingSupport.build()
+                .withCamelContext(context)
+                .withTarget(target)
+                .withProperty("bars[0]", "#class:" + 
MySecondBar.class.getName())
+                .withProperty("bars[0].names[0]", "a")
+                .withProperty("bars[0].names[1]", "b")
+                .withConfigurer(new MySecondFooConfigurer())
+                .withRemoveParameters(false).bind();
+
+        assertEquals(1, target.getBars().size());
+        assertEquals(2, target.getBars().get(0).getNames().size());
+        assertEquals("a", target.getBars().get(0).getNames().get(0));
+        assertEquals("b", target.getBars().get(0).getNames().get(1));
+
+        // TODO: CAMEL-15394
+        // assertEquals(0, bi.getInvokedCounter());
+
+        context.stop();
+    }
+
+}
diff --git 
a/core/camel-main/src/test/resources/META-INF/services/org/apache/camel/configurer/MySecondBar
 
b/core/camel-main/src/test/resources/META-INF/services/org/apache/camel/configurer/MySecondBar
new file mode 100644
index 0000000..e223b95
--- /dev/null
+++ 
b/core/camel-main/src/test/resources/META-INF/services/org/apache/camel/configurer/MySecondBar
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.main.MySecondBarConfigurer
diff --git 
a/core/camel-main/src/test/resources/META-INF/services/org/apache/camel/configurer/MySecondFoo
 
b/core/camel-main/src/test/resources/META-INF/services/org/apache/camel/configurer/MySecondFoo
new file mode 100644
index 0000000..8b49b25
--- /dev/null
+++ 
b/core/camel-main/src/test/resources/META-INF/services/org/apache/camel/configurer/MySecondFoo
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.main.MySecondFooConfigurer
diff --git 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateConfigurerMojo.java
 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/AbstractGenerateConfigurerMojo.java
similarity index 87%
copy from 
tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateConfigurerMojo.java
copy to 
tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/AbstractGenerateConfigurerMojo.java
index 1abb926..12fc5a5 100644
--- 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateConfigurerMojo.java
+++ 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/AbstractGenerateConfigurerMojo.java
@@ -50,10 +50,7 @@ import org.apache.maven.model.Exclusion;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugins.annotations.Component;
-import org.apache.maven.plugins.annotations.LifecyclePhase;
-import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
-import org.apache.maven.plugins.annotations.ResolutionScope;
 import org.jboss.jandex.AnnotationInstance;
 import org.jboss.jandex.AnnotationTarget;
 import org.jboss.jandex.AnnotationValue;
@@ -62,44 +59,24 @@ import org.jboss.jandex.DotName;
 import org.jboss.jandex.Index;
 import org.jboss.jandex.IndexReader;
 
+
 import static org.apache.camel.tooling.util.ReflectionHelper.doWithMethods;
 import static org.apache.camel.tooling.util.Strings.between;
 
 /**
- * Generate configurer classes from @Configuer annotated classes.
+ * Abstract class for configurer generator.
  */
-@Mojo(name = "generate-configurer", threadSafe = true, defaultPhase = 
LifecyclePhase.PROCESS_CLASSES,
-        requiresDependencyCollection = ResolutionScope.COMPILE,
-        requiresDependencyResolution = ResolutionScope.COMPILE)
-// must include runtime dependencies to generate configurer source
-public class GenerateConfigurerMojo extends AbstractGeneratorMojo {
+public abstract class AbstractGenerateConfigurerMojo extends 
AbstractGeneratorMojo {
 
     public static final DotName CONFIGURER = 
DotName.createSimple("org.apache.camel.spi.Configurer");
 
     /**
-     * The output directory for generated java source code
-     */
-    @Parameter(defaultValue = "${project.basedir}/src/generated/java")
-    protected File sourcesOutputDir;
-
-    @Parameter(defaultValue = "${project.basedir}/src/generated/resources")
-    protected File resourcesOutputDir;
-
-    /**
      * Whether to discover configurer classes from classpath by scanning for 
@Configurer annotations.
      * This requires using jandex-maven-plugin.
      */
     @Parameter(defaultValue = "true")
     protected boolean discoverClasses = true;
 
-    /**
-     * To generate configurer for these classes.
-     * The syntax is either <tt>fqn</tt> or </tt>fqn=targetFqn</tt>.
-     * This allows to map source class to target class to generate the source 
code using a different classname.
-     */
-    @Parameter
-    protected List<String> classes;
-
     @Component
     private ArtifactFactory artifactFactory;
 
@@ -127,11 +104,10 @@ public class GenerateConfigurerMojo extends 
AbstractGeneratorMojo {
         }
     }
 
-    public GenerateConfigurerMojo() {
+    public AbstractGenerateConfigurerMojo() {
     }
 
-    @Override
-    public void execute() throws MojoExecutionException, MojoFailureException {
+    protected void doExecute(File sourcesOutputDir, File resourcesOutputDir, 
List<String> classes, boolean testClasspathOnly) throws MojoExecutionException, 
MojoFailureException {
         if ("pom".equals(project.getPackaging())) {
             return;
         }
@@ -145,7 +121,7 @@ public class GenerateConfigurerMojo extends 
AbstractGeneratorMojo {
 
         List<URL> urls = new ArrayList<>();
         // need to include project compile dependencies (code similar to 
camel-maven-plugin)
-        addRelevantProjectDependenciesToClasspath(urls);
+        addRelevantProjectDependenciesToClasspath(urls, testClasspathOnly);
         projectClassLoader = 
DynamicClassLoader.createDynamicClassLoaderFromUrls(urls);
 
         Set<String> set = new LinkedHashSet<>();
@@ -179,7 +155,6 @@ public class GenerateConfigurerMojo extends 
AbstractGeneratorMojo {
         if (getLog().isDebugEnabled()) {
             getLog().debug("Generating configuers for the following classes: " 
+ set);
         }
-
         for (String fqn : set) {
             try {
                 String targetFqn = fqn;
@@ -189,8 +164,8 @@ public class GenerateConfigurerMojo extends 
AbstractGeneratorMojo {
                     fqn = fqn.substring(0, pos);
                 }
                 List<Option> options = processClass(fqn);
-                generateConfigurer(fqn, targetFqn, options);
-                generateMetaInfConfigurer(targetFqn);
+                generateConfigurer(fqn, targetFqn, options, sourcesOutputDir);
+                generateMetaInfConfigurer(targetFqn, resourcesOutputDir);
             } catch (Exception e) {
                 throw new MojoExecutionException("Error processing class: " + 
fqn, e);
             }
@@ -201,16 +176,22 @@ public class GenerateConfigurerMojo extends 
AbstractGeneratorMojo {
      * Add any relevant project dependencies to the classpath. Takes
      * includeProjectDependencies into consideration.
      *
-     * @param path classpath of {@link java.net.URL} objects
+     * @param path classpath of {@link URL} objects
      * @throws MojoExecutionException
      */
-    private void addRelevantProjectDependenciesToClasspath(List<URL> path) 
throws MojoExecutionException {
+    private void addRelevantProjectDependenciesToClasspath(List<URL> path, 
boolean testClasspathOnly) throws MojoExecutionException {
         try {
             getLog().debug("Project Dependencies will be included.");
 
-            URL mainClasses = new 
File(project.getBuild().getOutputDirectory()).toURI().toURL();
-            getLog().debug("Adding to classpath : " + mainClasses);
-            path.add(mainClasses);
+            if (testClasspathOnly) {
+                URL testClasses = new 
File(project.getBuild().getTestOutputDirectory()).toURI().toURL();
+                getLog().debug("Adding to classpath : " + testClasses);
+                path.add(testClasses);
+            } else {
+                URL mainClasses = new 
File(project.getBuild().getOutputDirectory()).toURI().toURL();
+                getLog().debug("Adding to classpath : " + mainClasses);
+                path.add(mainClasses);
+            }
 
             Set<Artifact> dependencies = project.getArtifacts();
 
@@ -357,7 +338,7 @@ public class GenerateConfigurerMojo extends 
AbstractGeneratorMojo {
         return true;
     }
 
-    private void generateConfigurer(String fqn, String targetFqn, List<Option> 
options) throws IOException {
+    private void generateConfigurer(String fqn, String targetFqn, List<Option> 
options, File outputDir) throws IOException {
         int pos = targetFqn.lastIndexOf('.');
         String pn = targetFqn.substring(0, pos);
         String cn = targetFqn.substring(pos + 1) + "Configurer";
@@ -372,14 +353,14 @@ public class GenerateConfigurerMojo extends 
AbstractGeneratorMojo {
         String source = sw.toString();
 
         String fileName = pn.replace('.', '/') + "/" + cn + ".java";
-        sourcesOutputDir.mkdirs();
-        boolean updated = updateResource(sourcesOutputDir.toPath(), fileName, 
source);
+        outputDir.mkdirs();
+        boolean updated = updateResource(outputDir.toPath(), fileName, source);
         if (updated) {
             getLog().info("Updated " + fileName);
         }
     }
 
-    private void generateMetaInfConfigurer(String name) {
+    private void generateMetaInfConfigurer(String name, File 
resourcesOutputDir) {
         int pos = name.lastIndexOf('.');
         String pn = name.substring(0, pos);
         String en = name.substring(pos + 1);
diff --git 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateConfigurerMojo.java
 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateConfigurerMojo.java
index 1abb926..52e8be5 100644
--- 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateConfigurerMojo.java
+++ 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateConfigurerMojo.java
@@ -17,64 +17,23 @@
 package org.apache.camel.maven.packaging;
 
 import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
 import java.util.List;
-import java.util.Set;
 
-import org.apache.camel.tooling.model.BaseOptionModel;
-import org.apache.camel.tooling.util.ReflectionHelper;
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.factory.ArtifactFactory;
-import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
-import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
-import 
org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
-import org.apache.maven.artifact.versioning.VersionRange;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.Exclusion;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugins.annotations.Component;
 import org.apache.maven.plugins.annotations.LifecyclePhase;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.plugins.annotations.ResolutionScope;
-import org.jboss.jandex.AnnotationInstance;
-import org.jboss.jandex.AnnotationTarget;
-import org.jboss.jandex.AnnotationValue;
-import org.jboss.jandex.ClassInfo;
-import org.jboss.jandex.DotName;
-import org.jboss.jandex.Index;
-import org.jboss.jandex.IndexReader;
-
-import static org.apache.camel.tooling.util.ReflectionHelper.doWithMethods;
-import static org.apache.camel.tooling.util.Strings.between;
 
 /**
- * Generate configurer classes from @Configuer annotated classes.
+ * Generate configurer classes from @Configuer annotated classes for main 
sources.
  */
 @Mojo(name = "generate-configurer", threadSafe = true, defaultPhase = 
LifecyclePhase.PROCESS_CLASSES,
         requiresDependencyCollection = ResolutionScope.COMPILE,
         requiresDependencyResolution = ResolutionScope.COMPILE)
 // must include runtime dependencies to generate configurer source
-public class GenerateConfigurerMojo extends AbstractGeneratorMojo {
-
-    public static final DotName CONFIGURER = 
DotName.createSimple("org.apache.camel.spi.Configurer");
+public class GenerateConfigurerMojo extends AbstractGenerateConfigurerMojo {
 
     /**
      * The output directory for generated java source code
@@ -82,15 +41,11 @@ public class GenerateConfigurerMojo extends 
AbstractGeneratorMojo {
     @Parameter(defaultValue = "${project.basedir}/src/generated/java")
     protected File sourcesOutputDir;
 
-    @Parameter(defaultValue = "${project.basedir}/src/generated/resources")
-    protected File resourcesOutputDir;
-
     /**
-     * Whether to discover configurer classes from classpath by scanning for 
@Configurer annotations.
-     * This requires using jandex-maven-plugin.
+     * The output directory for generated resource source code
      */
-    @Parameter(defaultValue = "true")
-    protected boolean discoverClasses = true;
+    @Parameter(defaultValue = "${project.basedir}/src/generated/resources")
+    protected File resourcesOutputDir;
 
     /**
      * To generate configurer for these classes.
@@ -100,33 +55,6 @@ public class GenerateConfigurerMojo extends 
AbstractGeneratorMojo {
     @Parameter
     protected List<String> classes;
 
-    @Component
-    private ArtifactFactory artifactFactory;
-
-    private DynamicClassLoader projectClassLoader;
-
-    private static class Option extends BaseOptionModel {
-
-        public Option(String name, Class type, String getter) {
-            // we just use name, type
-            setName(name);
-            if (byte[].class == type) {
-                // special for byte array
-                setJavaType("byte[]");
-            } else if (long[].class == type) {
-                // special for long array
-                setJavaType("long[]");
-            } else if (type.isArray()) {
-                // special for array
-                String arrType = between(type.getName(), "[L", ";") + "[]";
-                setJavaType(arrType);
-            } else {
-                setJavaType(type.getName());
-            }
-            setGetterMethod(getter);
-        }
-    }
-
     public GenerateConfigurerMojo() {
     }
 
@@ -143,258 +71,7 @@ public class GenerateConfigurerMojo extends 
AbstractGeneratorMojo {
             resourcesOutputDir = new File(project.getBasedir(), 
"src/generated/resources");
         }
 
-        List<URL> urls = new ArrayList<>();
-        // need to include project compile dependencies (code similar to 
camel-maven-plugin)
-        addRelevantProjectDependenciesToClasspath(urls);
-        projectClassLoader = 
DynamicClassLoader.createDynamicClassLoaderFromUrls(urls);
-
-        Set<String> set = new LinkedHashSet<>();
-
-        if (discoverClasses) {
-            Path output = Paths.get(project.getBuild().getOutputDirectory());
-            Index index;
-            try (InputStream is = 
Files.newInputStream(output.resolve("META-INF/jandex.idx"))) {
-                index = new IndexReader(is).read();
-            } catch (IOException e) {
-                throw new MojoExecutionException("IOException: " + 
e.getMessage(), e);
-            }
-
-            // discover all classes annotated with @Configurer
-            List<AnnotationInstance> annotations = 
index.getAnnotations(CONFIGURER);
-            annotations.stream()
-                    .filter(annotation -> annotation.target().kind() == 
AnnotationTarget.Kind.CLASS)
-                    .filter(annotation -> 
annotation.target().asClass().nestingType() == ClassInfo.NestingType.TOP_LEVEL)
-                    .filter(annotation -> asBooleanDefaultTrue(annotation, 
"generateConfigurer"))
-                    .forEach(annotation -> {
-                        String currentClass = 
annotation.target().asClass().name().toString();
-                        set.add(currentClass);
-                    });
-        }
-
-        // additional classes
-        if (classes != null && !classes.isEmpty()) {
-            set.addAll(classes);
-        }
-
-        if (getLog().isDebugEnabled()) {
-            getLog().debug("Generating configuers for the following classes: " 
+ set);
-        }
-
-        for (String fqn : set) {
-            try {
-                String targetFqn = fqn;
-                int pos = fqn.indexOf('=');
-                if (pos != -1) {
-                    targetFqn = fqn.substring(pos + 1);
-                    fqn = fqn.substring(0, pos);
-                }
-                List<Option> options = processClass(fqn);
-                generateConfigurer(fqn, targetFqn, options);
-                generateMetaInfConfigurer(targetFqn);
-            } catch (Exception e) {
-                throw new MojoExecutionException("Error processing class: " + 
fqn, e);
-            }
-        }
-    }
-
-    /**
-     * Add any relevant project dependencies to the classpath. Takes
-     * includeProjectDependencies into consideration.
-     *
-     * @param path classpath of {@link java.net.URL} objects
-     * @throws MojoExecutionException
-     */
-    private void addRelevantProjectDependenciesToClasspath(List<URL> path) 
throws MojoExecutionException {
-        try {
-            getLog().debug("Project Dependencies will be included.");
-
-            URL mainClasses = new 
File(project.getBuild().getOutputDirectory()).toURI().toURL();
-            getLog().debug("Adding to classpath : " + mainClasses);
-            path.add(mainClasses);
-
-            Set<Artifact> dependencies = project.getArtifacts();
-
-            // system scope dependencies are not returned by maven 2.0. See
-            // MEXEC-17
-            dependencies.addAll(getAllNonTestScopedDependencies());
-
-            Iterator<Artifact> iter = dependencies.iterator();
-            while (iter.hasNext()) {
-                Artifact classPathElement = iter.next();
-                getLog().debug("Adding project dependency artifact: " + 
classPathElement.getArtifactId()
-                        + " to classpath");
-                File file = classPathElement.getFile();
-                if (file != null) {
-                    path.add(file.toURI().toURL());
-                }
-            }
-
-        } catch (MalformedURLException e) {
-            throw new MojoExecutionException("Error during setting up 
classpath", e);
-        }
-    }
-
-    private Collection<Artifact> getAllNonTestScopedDependencies() throws 
MojoExecutionException {
-        List<Artifact> answer = new ArrayList<>();
-
-        for (Artifact artifact : getAllDependencies()) {
-
-            // do not add test artifacts
-            if (!artifact.getScope().equals(Artifact.SCOPE_TEST)) {
-                answer.add(artifact);
-            }
-        }
-        return answer;
-    }
-
-    // generic method to retrieve all the transitive dependencies
-    private Collection<Artifact> getAllDependencies() throws 
MojoExecutionException {
-        List<Artifact> artifacts = new ArrayList<>();
-
-        for (Iterator<?> dependencies = project.getDependencies().iterator(); 
dependencies.hasNext();) {
-            Dependency dependency = (Dependency)dependencies.next();
-
-            String groupId = dependency.getGroupId();
-            String artifactId = dependency.getArtifactId();
-
-            VersionRange versionRange;
-            try {
-                versionRange = 
VersionRange.createFromVersionSpec(dependency.getVersion());
-            } catch (InvalidVersionSpecificationException e) {
-                throw new MojoExecutionException("unable to parse version", e);
-            }
-
-            String type = dependency.getType();
-            if (type == null) {
-                type = "jar";
-            }
-            String classifier = dependency.getClassifier();
-            boolean optional = dependency.isOptional();
-            String scope = dependency.getScope();
-            if (scope == null) {
-                scope = Artifact.SCOPE_COMPILE;
-            }
-
-            if (this.artifactFactory != null) {
-                Artifact art = 
this.artifactFactory.createDependencyArtifact(groupId, artifactId, versionRange,
-                        type, classifier, scope, null, optional);
-
-                if (scope.equalsIgnoreCase(Artifact.SCOPE_SYSTEM)) {
-                    art.setFile(new File(dependency.getSystemPath()));
-                }
-
-                List<String> exclusions = new ArrayList<>();
-                for (Exclusion exclusion : dependency.getExclusions()) {
-                    exclusions.add(exclusion.getGroupId() + ":" + 
exclusion.getArtifactId());
-                }
-
-                ArtifactFilter newFilter = new 
ExcludesArtifactFilter(exclusions);
-
-                art.setDependencyFilter(newFilter);
-
-                artifacts.add(art);
-            }
-        }
-
-        return artifacts;
-    }
-
-    private List<Option> processClass(String fqn) throws 
ClassNotFoundException {
-        List<Option> answer = new ArrayList<>();
-        // filter out duplicates by using a names set that has already added
-        Set<String> names = new HashSet<>();
-
-        Class clazz = projectClassLoader.loadClass(fqn);
-        // find all public setters
-        doWithMethods(clazz, m -> {
-            boolean setter = m.getName().length() >= 4 && 
m.getName().startsWith("set") && Character.isUpperCase(m.getName().charAt(3));
-            setter &= Modifier.isPublic(m.getModifiers()) && 
m.getParameterCount() == 1;
-            setter &= filterSetter(m);
-            if (setter) {
-                String getter = "get" + 
Character.toUpperCase(m.getName().charAt(3)) + m.getName().substring(4);
-                Class type = m.getParameterTypes()[0];
-                if (boolean.class == type || Boolean.class == type) {
-                    try {
-                        String isGetter = "is" + getter.substring(3);
-                        clazz.getMethod(isGetter, null);
-                        getter = isGetter;
-                    } catch (Exception e) {
-                        // ignore as its then assumed to be get
-                    }
-                }
-                String t = Character.toUpperCase(m.getName().charAt(3)) + 
m.getName().substring(3 + 1);
-                if (names.add(t)) {
-                    answer.add(new Option(t, type, getter));
-                } else {
-                    boolean replace = false;
-                    // try to find out what the real type is of the 
correspondent field so we chose among the clash
-                    Field field = ReflectionHelper.findField(clazz, 
Character.toLowerCase(t.charAt(0)) + t.substring(1));
-                    if (field != null && field.getType().equals(type)) {
-                        // this is the correct type for the new option
-                        replace = true;
-                    }
-                    if (replace) {
-                        answer.removeIf(o -> o.getName().equals(t));
-                        answer.add(new Option(t, type, getter));
-                    }
-                }
-            }
-        });
-
-        return answer;
-    }
-
-    private boolean filterSetter(Method setter) {
-        // special for some
-        if ("setBindingMode".equals(setter.getName())) {
-            // we only want the string setter
-            return setter.getParameterTypes()[0] == String.class;
-        } else if ("setHostNameResolver".equals(setter.getName())) {
-            // we only want the string setter
-            return setter.getParameterTypes()[0] == String.class;
-        }
-
-        return true;
-    }
-
-    private void generateConfigurer(String fqn, String targetFqn, List<Option> 
options) throws IOException {
-        int pos = targetFqn.lastIndexOf('.');
-        String pn = targetFqn.substring(0, pos);
-        String cn = targetFqn.substring(pos + 1) + "Configurer";
-        String en = fqn;
-        String pfqn = fqn;
-        String psn = 
"org.apache.camel.support.component.PropertyConfigurerSupport";
-
-        StringWriter sw = new StringWriter();
-        PropertyConfigurerGenerator.generatePropertyConfigurer(pn, cn, en, 
pfqn, psn,
-                false, false, options, sw);
-
-        String source = sw.toString();
-
-        String fileName = pn.replace('.', '/') + "/" + cn + ".java";
-        sourcesOutputDir.mkdirs();
-        boolean updated = updateResource(sourcesOutputDir.toPath(), fileName, 
source);
-        if (updated) {
-            getLog().info("Updated " + fileName);
-        }
-    }
-
-    private void generateMetaInfConfigurer(String name) {
-        int pos = name.lastIndexOf('.');
-        String pn = name.substring(0, pos);
-        String en = name.substring(pos + 1);
-        try (Writer w = new StringWriter()) {
-            w.append("# " + GENERATED_MSG + "\n");
-            
w.append("class=").append(pn).append(".").append(en).append("Configurer").append("\n");
-            updateResource(resourcesOutputDir.toPath(), 
"META-INF/services/org/apache/camel/configurer/" + en, w.toString());
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    private static boolean asBooleanDefaultTrue(AnnotationInstance ai, String 
name) {
-        AnnotationValue av = ai.value(name);
-        return av == null || av.asBoolean();
+        doExecute(sourcesOutputDir, resourcesOutputDir, classes, false);
     }
 
 }
diff --git 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateTestConfigurerMojo.java
 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateTestConfigurerMojo.java
new file mode 100644
index 0000000..f423189
--- /dev/null
+++ 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/GenerateTestConfigurerMojo.java
@@ -0,0 +1,77 @@
+/*
+ * 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.maven.packaging;
+
+import java.io.File;
+import java.util.List;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+
+/**
+ * Generate configurer classes from @Configuer annotated classes for test 
sources.
+ */
+@Mojo(name = "generate-test-configurer", threadSafe = true, defaultPhase = 
LifecyclePhase.PROCESS_CLASSES,
+        requiresDependencyCollection = ResolutionScope.COMPILE,
+        requiresDependencyResolution = ResolutionScope.COMPILE)
+// must include runtime dependencies to generate configurer source
+public class GenerateTestConfigurerMojo extends AbstractGenerateConfigurerMojo 
{
+
+    /**
+     * The output directory for generated test java source code
+     */
+    @Parameter(defaultValue = "${project.basedir}/src/test/java")
+    protected File sourcesOutputDir;
+
+    /**
+     * The output directory for generated test resource source code
+     */
+    @Parameter(defaultValue = "${project.basedir}/src/test/resources")
+    protected File resourcesOutputDir;
+
+    /**
+     * To generate configurer for these test classes.
+     * The syntax is either <tt>fqn</tt> or </tt>fqn=targetFqn</tt>.
+     * This allows to map source class to target class to generate the source 
code using a different classname.
+     */
+    @Parameter
+    protected List<String> classes;
+
+    public GenerateTestConfigurerMojo() {
+    }
+
+    @Override
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        if ("pom".equals(project.getPackaging())) {
+            return;
+        }
+
+        if (sourcesOutputDir == null) {
+            sourcesOutputDir = new File(project.getBasedir(), "src/test/java");
+        }
+        if (resourcesOutputDir == null) {
+            resourcesOutputDir = new File(project.getBasedir(), 
"src/test/resources");
+        }
+
+        doExecute(sourcesOutputDir, resourcesOutputDir, classes, true);
+    }
+
+}

Reply via email to