This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 27b46f7ef45 CAMEL-19912: camel-core-model - Add factory-method 
parameter (#11554)
27b46f7ef45 is described below

commit 27b46f7ef451e32e67d717a1f1e6260db4e765b3
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Tue Sep 26 09:05:20 2023 +0200

    CAMEL-19912: camel-core-model - Add factory-method parameter (#11554)
---
 .../apache/camel/catalog/schemas/camel-spring.xsd  |  1 +
 .../camel/model/app/RegistryBeanDefinition.java    | 10 ++++
 .../java/org/apache/camel/xml/in/ModelParser.java  |  1 +
 .../java/org/apache/camel/xml/out/ModelWriter.java |  1 +
 .../org/apache/camel/xml/LwModelToXMLDumper.java   |  7 ++-
 .../org/apache/camel/xml/in/ModelParserTest.java   | 29 ++++++++++++
 .../src/test/resources/beansWithFactoryMethod.xml  | 40 ++++++++++++++++
 .../camel/xml/jaxb/JaxbModelToXMLDumper.java       |  7 ++-
 .../org/apache/camel/yaml/out/ModelWriter.java     |  1 +
 .../org/apache/camel/yaml/LwModelToYAMLDumper.java |  4 ++
 .../xml/blueprint/BlueprintXmlBeansHandler.java    | 37 +++++++++++++--
 .../main/xml/spring/SpringXmlBeansHandler.java     |  4 ++
 .../src/main/docs/java-xml-io-dsl.adoc             | 32 +++++++++++++
 .../camel/dsl/xml/io/XmlRoutesBuilderLoader.java   |  4 ++
 .../apache/camel/dsl/xml/io/XmlLoadAppTest.java    | 23 +++++++++
 .../apache/camel/dsl/xml/io/beans/MyFacBean.java   | 54 ++++++++++++++++++++++
 .../org/apache/camel/dsl/xml/io/camel-app6.xml     | 38 +++++++++++++++
 .../dsl/yaml/deserializers/ModelDeserializers.java |  6 +++
 .../dsl/yaml/deserializers/BeansDeserializer.java  |  4 ++
 .../generated/resources/schema/camelYamlDsl.json   |  3 ++
 .../camel-yaml-dsl/src/main/docs/yaml-dsl.adoc     | 52 +++++++++++++++++++++
 .../org/apache/camel/dsl/yaml/BeansTest.groovy     | 24 ++++++++++
 .../camel/dsl/yaml/support/model/MyFacBean.groovy  | 48 +++++++++++++++++++
 23 files changed, 423 insertions(+), 7 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
index c52b32f6558..4727a1a81c2 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
@@ -13603,6 +13603,7 @@ org.apache.camel.builder.RouteBuilder.
     </xs:sequence>
     <xs:attribute name="name" type="xs:string" use="required"/>
     <xs:attribute name="type" type="xs:string" use="required"/>
+    <xs:attribute name="factoryMethod" type="xs:string"/>
   </xs:complexType>
   <xs:complexType name="beanConstructorsDefinition">
     <xs:sequence>
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/model/app/RegistryBeanDefinition.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/model/app/RegistryBeanDefinition.java
index 43ea6c01f6c..39b34c1ff95 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/model/app/RegistryBeanDefinition.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/model/app/RegistryBeanDefinition.java
@@ -46,6 +46,8 @@ public class RegistryBeanDefinition implements ResourceAware {
     private String name;
     @XmlAttribute(required = true)
     private String type;
+    @XmlAttribute
+    private String factoryMethod;
     @XmlElement(name = "constructors")
     @XmlJavaTypeAdapter(BeanConstructorsAdapter.class)
     private Map<Integer, Object> constructors;
@@ -69,6 +71,14 @@ public class RegistryBeanDefinition implements ResourceAware 
{
         this.type = type;
     }
 
+    public String getFactoryMethod() {
+        return factoryMethod;
+    }
+
+    public void setFactoryMethod(String factoryMethod) {
+        this.factoryMethod = factoryMethod;
+    }
+
     public Map<Integer, Object> getConstructors() {
         return constructors;
     }
diff --git 
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java 
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
index fc4ee8275e5..7d49154c5ad 100644
--- 
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
+++ 
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
@@ -1634,6 +1634,7 @@ public class ModelParser extends BaseParser {
     protected RegistryBeanDefinition doParseRegistryBeanDefinition() throws 
IOException, XmlPullParserException {
         return doParse(new RegistryBeanDefinition(), (def, key, val) -> {
             switch (key) {
+                case "factoryMethod": def.setFactoryMethod(val); break;
                 case "name": def.setName(val); break;
                 case "type": def.setType(val); break;
                 default: return false;
diff --git 
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
 
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
index 51ae6036ef8..2c2ef105ef5 100644
--- 
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
+++ 
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
@@ -2566,6 +2566,7 @@ public class ModelWriter extends BaseWriter {
             RegistryBeanDefinition def)
             throws IOException {
         startElement(name);
+        doWriteAttribute("factoryMethod", def.getFactoryMethod());
         doWriteAttribute("name", def.getName());
         doWriteAttribute("type", def.getType());
         doWriteElement("constructors", new 
BeanConstructorsAdapter().marshal(def.getConstructors()), 
this::doWriteBeanConstructorsDefinition);
diff --git 
a/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java 
b/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java
index 577d4bec4b4..252c86dfce2 100644
--- 
a/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java
+++ 
b/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java
@@ -324,7 +324,12 @@ public class LwModelToXMLDumper implements 
ModelToXMLDumper {
             if (type.startsWith("#class:")) {
                 type = type.substring(7);
             }
-            buffer.write(String.format("    <bean name=\"%s\" type=\"%s\">%n", 
b.getName(), type));
+            String factoryMethod = b.getFactoryMethod();
+            if (factoryMethod != null) {
+                buffer.write(String.format("    <bean name=\"%s\" type=\"%s\" 
factoryMethod=\"%s\">%n", b.getName(), type, factoryMethod));
+            } else {
+                buffer.write(String.format("    <bean name=\"%s\" 
type=\"%s\">%n", b.getName(), type));
+            }
             if (b.getConstructors() != null && !b.getConstructors().isEmpty()) 
{
                 buffer.write(String.format("        <constructors>%n"));
                 for (Map.Entry<Integer, Object> entry : 
b.getConstructors().entrySet()) {
diff --git 
a/core/camel-xml-io/src/test/java/org/apache/camel/xml/in/ModelParserTest.java 
b/core/camel-xml-io/src/test/java/org/apache/camel/xml/in/ModelParserTest.java
index 17a9111179d..e64dd499829 100644
--- 
a/core/camel-xml-io/src/test/java/org/apache/camel/xml/in/ModelParserTest.java
+++ 
b/core/camel-xml-io/src/test/java/org/apache/camel/xml/in/ModelParserTest.java
@@ -294,6 +294,35 @@ public class ModelParserTest {
         assertEquals("v2", b2.getProperties().get("p2"));
     }
 
+    @Test
+    public void testBeansWithFactoryMethod() throws Exception {
+        Path dir = getResourceFolder();
+        Path path = new File(dir.toFile(), 
"beansWithFactoryMethod.xml").toPath();
+        ModelParser parser = new ModelParser(Files.newInputStream(path), 
NAMESPACE);
+        BeansDefinition beans = parser.parseBeansDefinition().orElse(null);
+        assertNotNull(beans);
+        assertEquals(2, beans.getBeans().size());
+        assertTrue(beans.getSpringBeans().isEmpty());
+
+        RegistryBeanDefinition b1 = beans.getBeans().get(0);
+        RegistryBeanDefinition b2 = beans.getBeans().get(1);
+
+        assertEquals("b1", b1.getName());
+        assertEquals("org.apache.camel.xml.in.ModelParserTest.MyBean", 
b1.getType());
+        assertEquals("createMyBean", b1.getFactoryMethod());
+        assertEquals(2, b1.getConstructors().size());
+        assertEquals("c1", b1.getConstructors().get(0));
+        assertEquals("c2", b1.getConstructors().get(1));
+
+        assertEquals("b2", b2.getName());
+        assertEquals("org.apache.camel.xml.in.ModelParserTest.MyBean", 
b2.getType());
+        assertEquals("createMyBean", b2.getFactoryMethod());
+        assertEquals(1, b2.getConstructors().size());
+        assertEquals("c1", b2.getConstructors().get(0));
+        assertEquals("v1", b2.getProperties().get("p1"));
+        assertEquals("v2", b2.getProperties().get("p2"));
+    }
+
     @Test
     public void testSpringBeans() throws Exception {
         Path dir = getResourceFolder();
diff --git a/core/camel-xml-io/src/test/resources/beansWithFactoryMethod.xml 
b/core/camel-xml-io/src/test/resources/beansWithFactoryMethod.xml
new file mode 100644
index 00000000000..9065010d4c4
--- /dev/null
+++ b/core/camel-xml-io/src/test/resources/beansWithFactoryMethod.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<beans xmlns="http://camel.apache.org/schema/spring"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+xsi:schemaLocation="http://camel.apache.org/schema/spring 
file:/data/sources/github.com/apache/camel-upstream/components/camel-spring-xml/target/classes/camel-spring.xsd">
+
+       <bean name="b1" type="org.apache.camel.xml.in.ModelParserTest.MyBean" 
factoryMethod="createMyBean">
+               <constructors>
+                       <constructor value="c1" />
+                       <constructor value="c2" />
+               </constructors>
+       </bean>
+
+       <bean name="b2" type="org.apache.camel.xml.in.ModelParserTest.MyBean" 
factoryMethod="createMyBean">
+               <constructors>
+                       <constructor index="0" value="c1" />
+               </constructors>
+               <properties>
+                       <property key="p1" value="v1" />
+                       <property key="p2" value="v2" />
+               </properties>
+       </bean>
+
+</beans>
diff --git 
a/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java
 
b/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java
index 1ffbd95c74b..8fa8b190bc9 100644
--- 
a/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java
+++ 
b/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java
@@ -337,7 +337,12 @@ public class JaxbModelToXMLDumper implements 
ModelToXMLDumper {
             if (type.startsWith("#class:")) {
                 type = type.substring(7);
             }
-            buffer.write(String.format("    <bean name=\"%s\" type=\"%s\">%n", 
b.getName(), type));
+            String factoryMethod = b.getFactoryMethod();
+            if (factoryMethod != null) {
+                buffer.write(String.format("    <bean name=\"%s\" type=\"%s\" 
factoryMethod=\"%s\">%n", b.getName(), type, factoryMethod));
+            } else {
+                buffer.write(String.format("    <bean name=\"%s\" 
type=\"%s\">%n", b.getName(), type));
+            }
             if (b.getConstructors() != null && !b.getConstructors().isEmpty()) 
{
                 buffer.write(String.format("        <constructors>%n"));
                 for (Map.Entry<Integer, Object> entry : 
b.getConstructors().entrySet()) {
diff --git 
a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
 
b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
index 7d73b3ebb96..09249ae2272 100644
--- 
a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
+++ 
b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
@@ -2566,6 +2566,7 @@ public class ModelWriter extends BaseWriter {
             RegistryBeanDefinition def)
             throws IOException {
         startElement(name);
+        doWriteAttribute("factoryMethod", def.getFactoryMethod());
         doWriteAttribute("name", def.getName());
         doWriteAttribute("type", def.getType());
         doWriteElement("constructors", new 
BeanConstructorsAdapter().marshal(def.getConstructors()), 
this::doWriteBeanConstructorsDefinition);
diff --git 
a/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
 
b/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
index 0ab28843b2a..7cca44385c9 100644
--- 
a/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
+++ 
b/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
@@ -312,8 +312,12 @@ public class LwModelToYAMLDumper implements 
ModelToYAMLDumper {
             if (type.startsWith("#class:")) {
                 type = type.substring(7);
             }
+            String factoryMethod = b.getFactoryMethod();
             buffer.write(String.format("    - name: %s%n", b.getName()));
             buffer.write(String.format("      type: \"%s\"%n", type));
+            if (factoryMethod != null) {
+                buffer.write(String.format("      factoryMethod: \"%s\"%n", 
factoryMethod));
+            }
             if (b.getConstructors() != null && !b.getConstructors().isEmpty()) 
{
                 buffer.write(String.format("      constructors:%n"));
                 int counter = 0;
diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/blueprint/BlueprintXmlBeansHandler.java
 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/blueprint/BlueprintXmlBeansHandler.java
index 77a2e755bbd..5548661cae2 100644
--- 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/blueprint/BlueprintXmlBeansHandler.java
+++ 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/blueprint/BlueprintXmlBeansHandler.java
@@ -21,6 +21,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.StringJoiner;
+import java.util.TreeMap;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -106,9 +107,16 @@ public class BlueprintXmlBeansHandler {
         rrd.setType(XmlHelper.getAttribute(node, "class"));
         rrd.setName(name);
 
+        // factory method
+        String fm = XmlHelper.getAttribute(node, "factory-method");
+        if (fm != null) {
+            rrd.setFactoryMethod(fm);
+        }
         // constructor arguments
-        StringJoiner sj = new StringJoiner(", ");
+        Map<Integer, Object> constructors = new LinkedHashMap<>();
+        rrd.setConstructors(constructors);
         NodeList props = node.getChildNodes();
+        int index = 0;
         for (int i = 0; i < props.getLength(); i++) {
             Node child = props.item(i);
             // assume the args are in order (1, 2)
@@ -116,14 +124,14 @@ public class BlueprintXmlBeansHandler {
                 String val = XmlHelper.getAttribute(child, "value");
                 String ref = XmlHelper.getAttribute(child, "ref");
                 if (val != null) {
-                    sj.add("'" + extractValue(camelContext, val, false) + "'");
+                    constructors.put(index++, extractValue(camelContext, val, 
false));
                 } else if (ref != null) {
-                    sj.add("'#bean:" + extractValue(camelContext, ref, false) 
+ "'");
+                    constructors.put(index++, "#bean:" + 
extractValue(camelContext, ref, false));
                 }
             }
         }
-        if (sj.length() > 0) {
-            rrd.setType("#class:" + rrd.getType() + "(" + sj + ")");
+        if (!constructors.isEmpty()) {
+            rrd.setConstructors(constructors);
         }
 
         // property values
@@ -202,6 +210,25 @@ public class BlueprintXmlBeansHandler {
                 type = "#class:" + type;
             }
             try {
+                // factory method
+                if (def.getFactoryMethod() != null) {
+                    type = type + "#" + def.getFactoryMethod();
+                }
+                // property binding support has constructor arguments as part 
of the type
+                StringJoiner ctr = new StringJoiner(", ");
+                if (def.getConstructors() != null && 
!def.getConstructors().isEmpty()) {
+                    // need to sort constructor args based on index position
+                    Map<Integer, Object> sorted = new 
TreeMap<>(def.getConstructors());
+                    for (Object val : sorted.values()) {
+                        String text = val.toString();
+                        if (!StringHelper.isQuoted(text)) {
+                            text = "\"" + text + "\"";
+                        }
+                        ctr.add(text);
+                    }
+                    type = type + "(" + ctr + ")";
+                }
+
                 final Object target = 
PropertyBindingSupport.resolveBean(camelContext, type);
 
                 if (def.getProperties() != null && 
!def.getProperties().isEmpty()) {
diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/spring/SpringXmlBeansHandler.java
 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/spring/SpringXmlBeansHandler.java
index aeeced8d905..61ad9c44fa8 100644
--- 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/spring/SpringXmlBeansHandler.java
+++ 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/spring/SpringXmlBeansHandler.java
@@ -236,6 +236,10 @@ public class SpringXmlBeansHandler {
             rrd.setName(name);
             model.addRegistryBean(rrd);
 
+            // factory method
+            if (def.getFactoryMethodName() != null) {
+                rrd.setFactoryMethod(def.getFactoryMethodName());
+            }
             // constructor arguments
             if (def.hasConstructorArgumentValues()) {
                 Map<Integer, Object> constructors = new LinkedHashMap<>();
diff --git a/dsl/camel-xml-io-dsl/src/main/docs/java-xml-io-dsl.adoc 
b/dsl/camel-xml-io-dsl/src/main/docs/java-xml-io-dsl.adoc
index 5493e2a5e0f..4b1e029eff7 100644
--- a/dsl/camel-xml-io-dsl/src/main/docs/java-xml-io-dsl.adoc
+++ b/dsl/camel-xml-io-dsl/src/main/docs/java-xml-io-dsl.adoc
@@ -157,6 +157,38 @@ If you use Camel 4.0, then constructor arguments must be 
defined in the `type` a
 </bean>
 ----
 
+=== Creating beans from factory method
+
+A bean can also be created from a factory method (public static) as shown 
below:
+
+[source,xml]
+----
+       <bean name="myBean" type="com.acme.MyBean" factoryMethod="createMyBean">
+        <constructors>
+          <constructor index="0" value="true"/>
+          <constructor index="1" value="Hello World"/>
+        </constructors>
+       </bean>
+----
+
+When using `factoryMethod` then the arguments to this method is taken from 
`constructors`.
+So in the example above, this means that class `com.acme.MyBean` should be as 
follows:
+
+[source,java]
+----
+public class MyBean {
+
+    public static MyBean createMyBean(boolean important, String message) {
+        MyBean answer = ...
+        // create and configure the bean
+        return answer;
+    }
+}
+----
+
+NOTE: The factory method must be `public static` and from the same class as 
the created class itself.
+
+
 == See Also
 
 See xref:manual:ROOT:dsl.adoc[DSL]
diff --git 
a/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
 
b/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
index 472506f2158..541eda03ae2 100644
--- 
a/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
+++ 
b/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
@@ -327,6 +327,10 @@ public class XmlRoutesBuilderLoader extends 
RouteBuilderLoaderSupport {
         if (type != null && !type.startsWith("#")) {
             type = "#class:" + type;
             try {
+                // factory method
+                if (def.getFactoryMethod() != null) {
+                    type = type + "#" + def.getFactoryMethod();
+                }
                 // property binding support has constructor arguments as part 
of the type
                 StringJoiner ctr = new StringJoiner(", ");
                 if (def.getConstructors() != null && 
!def.getConstructors().isEmpty()) {
diff --git 
a/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/XmlLoadAppTest.java
 
b/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/XmlLoadAppTest.java
index 1baf549658e..59dddb4ef9d 100644
--- 
a/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/XmlLoadAppTest.java
+++ 
b/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/XmlLoadAppTest.java
@@ -144,4 +144,27 @@ public class XmlLoadAppTest {
         }
     }
 
+    @Test
+    public void testLoadCamelAppWithBeanFactory() throws Exception {
+        try (DefaultCamelContext context = new DefaultCamelContext()) {
+            context.start();
+
+            Resource resource = 
PluginHelper.getResourceLoader(context).resolveResource(
+                    "/org/apache/camel/dsl/xml/io/camel-app6.xml");
+
+            RoutesLoader routesLoader = PluginHelper.getRoutesLoader(context);
+            routesLoader.preParseRoute(resource, false);
+            routesLoader.loadRoutes(resource);
+
+            assertNotNull(context.getRoute("r6"), "Loaded r6 route should be 
there");
+            assertEquals(1, context.getRoutes().size());
+
+            // test that loaded route works
+            MockEndpoint y6 = context.getEndpoint("mock:y6", 
MockEndpoint.class);
+            y6.expectedBodiesReceived("Hello Moon. I am Camel and 43 years 
old!");
+            context.createProducerTemplate().sendBody("direct:x6", "Moon");
+            y6.assertIsSatisfied();
+        }
+    }
+
 }
diff --git 
a/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/beans/MyFacBean.java
 
b/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/beans/MyFacBean.java
new file mode 100644
index 00000000000..3db2c39de10
--- /dev/null
+++ 
b/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/beans/MyFacBean.java
@@ -0,0 +1,54 @@
+/*
+ * 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.dsl.xml.io.beans;
+
+public class MyFacBean {
+
+    private String field1;
+    private String field2;
+    private int age;
+
+    public static MyFacBean createBean(String field1, String field2) {
+        return new MyFacBean(field1, field2);
+    }
+
+    private MyFacBean(String field1, String field2) {
+        this.field1 = field1;
+        this.field2 = field2;
+    }
+
+    public String getField1() {
+        return field1;
+    }
+
+    public String getField2() {
+        return field2;
+    }
+
+    public int getAge() {
+        return age;
+    }
+
+    public void setAge(int age) {
+        this.age = age;
+    }
+
+    public String hi(String body) {
+        return field1 + " " + body + ". I am " + field2 + " and " + age + " 
years old!";
+    }
+
+}
diff --git 
a/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/dsl/xml/io/camel-app6.xml
 
b/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/dsl/xml/io/camel-app6.xml
new file mode 100644
index 00000000000..c7e9eaeb7e1
--- /dev/null
+++ 
b/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/dsl/xml/io/camel-app6.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<camel xmlns="http://camel.apache.org/schema/spring"; 
xmlns:s="http://www.springframework.org/schema/beans";>
+
+    <bean name="xml-bean-from-registry" 
type="org.apache.camel.dsl.xml.io.beans.MyFacBean" factoryMethod="createBean">
+        <constructors>
+            <constructor value="Hello"/>
+            <constructor value="Camel"/>
+        </constructors>
+        <properties>
+            <property key="age" value="43"/>
+        </properties>
+    </bean>
+
+    <route id="r6">
+        <from uri="direct:x6"/>
+        <bean ref="xml-bean-from-registry" method="hi"/>
+        <to uri="mock:y6"/>
+    </route>
+
+</camel>
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
index 5cb80ff5430..b8e5b914ec2 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
@@ -12349,6 +12349,7 @@ public final class ModelDeserializers extends 
YamlDeserializerSupport {
             order = 
org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
             properties = {
                     @YamlProperty(name = "constructors", type = "object"),
+                    @YamlProperty(name = "factory-method", type = "string"),
                     @YamlProperty(name = "name", type = "string", required = 
true),
                     @YamlProperty(name = "properties", type = "object"),
                     @YamlProperty(name = "type", type = "string", required = 
true)
@@ -12373,6 +12374,11 @@ public final class ModelDeserializers extends 
YamlDeserializerSupport {
                     target.setConstructors(val);
                     break;
                 }
+                case "factory-method": {
+                    String val = asText(node);
+                    target.setFactoryMethod(val);
+                    break;
+                }
                 case "name": {
                     String val = asText(node);
                     target.setName(val);
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/BeansDeserializer.java
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/BeansDeserializer.java
index d6f62a66482..917ea258fd3 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/BeansDeserializer.java
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/BeansDeserializer.java
@@ -95,6 +95,10 @@ public class BeansDeserializer extends 
YamlDeserializerSupport implements Constr
 
         String type = bean.getType();
 
+        // factory method
+        if (bean.getFactoryMethod() != null) {
+            type = type + "#" + bean.getFactoryMethod();
+        }
         // property binding support has constructor arguments as part of the 
type
         StringJoiner ctr = new StringJoiner(", ");
         if (bean.getConstructors() != null && 
!bean.getConstructors().isEmpty()) {
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
index fcb2e9a20a0..7a3c7e0c5fc 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
@@ -8026,6 +8026,9 @@
           "constructors" : {
             "type" : "object"
           },
+          "factoryMethod" : {
+            "type" : "string"
+          },
           "name" : {
             "type" : "string"
           },
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/docs/yaml-dsl.adoc 
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/docs/yaml-dsl.adoc
index 78929a196d2..49c68aca270 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/docs/yaml-dsl.adoc
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/docs/yaml-dsl.adoc
@@ -180,6 +180,58 @@ The properties of the bean can be defined using either a 
map or properties style
 The `beans` elements can only be used as the root element
 ====
 
+=== Creating bean using constructors
+
+When beans must be created with constructor arguments, then this is made 
easier in Camel 4.1 onwards.
+
+For example as shown below:
+
+[source,yaml]
+----
+- beans:
+  - name: myBean
+    type: com.acme.MyBean
+    constructors:
+      0: true
+      1: "Hello World"
+----
+
+The `constructors` is index based so the keys must be numbers starting from 
zero.
+
+TIP: You can use both constructors and properties.
+
+=== Creating beans from factory method
+
+A bean can also be created from a factory method (public static) as shown 
below:
+
+[source,yaml]
+----
+- beans:
+  - name: myBean
+    type: com.acme.MyBean
+    factoryMethod: createMyBean
+    constructors:
+      0: true
+      1: "Hello World"
+----
+
+When using `factoryMethod` then the arguments to this method is taken from 
`constructors`.
+So in the example above, this means that class `com.acme.MyBean` should be as 
follows:
+
+[source,java]
+----
+public class MyBean {
+
+    public static MyBean createMyBean(boolean important, String message) {
+        MyBean answer = ...
+        // create and configure the bean
+        return answer;
+    }
+}
+----
+
+NOTE: The factory method must be `public static` and from the same class as 
the created class itself.
+
 == Configuring options on languages
 
 Some xref:components:languages:index.adoc[Languages] have additional 
configurations
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/BeansTest.groovy
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/BeansTest.groovy
index 4b1e5253ce9..eb24f59d604 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/BeansTest.groovy
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/BeansTest.groovy
@@ -19,6 +19,7 @@ package org.apache.camel.dsl.yaml
 import org.apache.camel.dsl.yaml.support.YamlTestSupport
 import org.apache.camel.dsl.yaml.support.model.MyBean
 import org.apache.camel.dsl.yaml.support.model.MyCtrBean
+import org.apache.camel.dsl.yaml.support.model.MyFacBean
 
 class BeansTest extends YamlTestSupport {
 
@@ -131,4 +132,27 @@ class BeansTest extends YamlTestSupport {
         }
     }
 
+    def "beans with factory"() {
+        when:
+        loadRoutes """
+                - beans:
+                  - name: myFac
+                    type: ${MyFacBean.class.name}
+                    factoryMethod: createBean
+                    constructors:
+                      0: 'fac1'
+                      1: 'fac2'
+                    properties:
+                      age: 43 
+            """
+
+        then:
+        with(context.registry.lookupByName('myFac'), MyFacBean) {
+            it.field1 == 'fac1'
+            it.field2 == 'fac2'
+            it.age == 43
+        }
+    }
+
+
 }
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/model/MyFacBean.groovy
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/model/MyFacBean.groovy
new file mode 100644
index 00000000000..ce9267d0863
--- /dev/null
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/model/MyFacBean.groovy
@@ -0,0 +1,48 @@
+/*
+ * 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.dsl.yaml.support.model
+
+class MyFacBean {
+    String field1
+    String field2
+    int age;
+
+    static MyFacBean createBean(String field1, String field2) {
+        return new MyFacBean(field1, field2);
+    }
+
+    private MyFacBean(String field1, String field2) {
+        this.field1 = field1
+        this.field2 = field2
+    }
+
+    String getField1() {
+        return field1
+    }
+
+    String getField2() {
+        return field2
+    }
+
+    int getAge() {
+        return age
+    }
+
+    void setAge(int age) {
+        this.age = age
+    }
+}


Reply via email to