You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2023/09/25 12:05:01 UTC

[camel] 01/01: CAMEL-19820: camel-core-model - Add to to make it easier and more tooling friendly to specify constructor args

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

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

commit 4f7cfe30aed60c27b8c69f822b01a75d5eb6b86a
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Sep 25 14:00:07 2023 +0200

    CAMEL-19820: camel-core-model - Add <constructor> to <bean> to make it easier and more tooling friendly to specify constructor args
---
 .../apache/camel/catalog/schemas/camel-spring.xsd  | 11 +++
 .../org/apache/camel/model/app/jaxb.index          |  2 +
 .../camel/model/app/BeanConstructorDefinition.java | 55 +++++++++++++++
 .../camel/model/app/BeanConstructorsAdapter.java   | 69 +++++++++++++++++++
 .../model/app/BeanConstructorsDefinition.java      | 41 +++++++++++
 .../camel/model/app/RegistryBeanDefinition.java    | 11 +++
 .../java/org/apache/camel/xml/in/ModelParser.java  | 29 ++++++--
 .../java/org/apache/camel/xml/out/ModelWriter.java | 18 +++++
 .../org/apache/camel/xml/LwModelToXMLDumper.java   | 13 ++++
 .../org/apache/camel/xml/in/ModelParserTest.java   | 29 +++++++-
 .../src/test/resources/beansWithConstructors.xml   | 41 +++++++++++
 .../camel/xml/jaxb/JaxbModelToXMLDumper.java       | 13 ++++
 .../org/apache/camel/yaml/out/ModelWriter.java     | 18 +++++
 .../org/apache/camel/yaml/LwModelToYAMLDumper.java | 12 ++++
 .../main/xml/spring/SpringXmlBeansHandler.java     | 28 ++++----
 .../src/main/docs/java-xml-io-dsl.adoc             | 41 +++++++++++
 .../camel/dsl/xml/io/XmlRoutesBuilderLoader.java   | 18 +++++
 .../apache/camel/dsl/xml/io/XmlLoadAppTest.java    | 23 +++++++
 .../apache/camel/dsl/xml/io/beans/MyCtrBean.java   | 50 ++++++++++++++
 .../org/apache/camel/dsl/xml/io/camel-app5.xml     | 38 ++++++++++
 .../dsl/yaml/deserializers/ModelDeserializers.java | 80 ++++++++++++++++++++++
 .../deserializers/ModelDeserializersResolver.java  |  2 +
 .../dsl/yaml/deserializers/BeansDeserializer.java  | 24 ++++++-
 .../generated/resources/schema/camelYamlDsl.json   | 28 ++++++++
 .../org/apache/camel/dsl/yaml/BeansTest.groovy     | 44 ++++++++++++
 .../camel/dsl/yaml/support/model/MyCtrBean.groovy  | 44 ++++++++++++
 26 files changed, 764 insertions(+), 18 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 8882c7ddb24..c52b32f6558 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
@@ -13598,11 +13598,22 @@ org.apache.camel.builder.RouteBuilder.
   </xs:complexType>
   <xs:complexType name="registryBeanDefinition">
     <xs:sequence>
+      <xs:element minOccurs="0" name="constructors" type="tns:beanConstructorsDefinition"/>
       <xs:element minOccurs="0" name="properties" type="tns:beanPropertiesDefinition"/>
     </xs:sequence>
     <xs:attribute name="name" type="xs:string" use="required"/>
     <xs:attribute name="type" type="xs:string" use="required"/>
   </xs:complexType>
+  <xs:complexType name="beanConstructorsDefinition">
+    <xs:sequence>
+      <xs:element maxOccurs="unbounded" minOccurs="0" name="constructor" type="tns:beanConstructorDefinition"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="beanConstructorDefinition">
+    <xs:sequence/>
+    <xs:attribute name="index" type="xs:int"/>
+    <xs:attribute name="value" type="xs:string" use="required"/>
+  </xs:complexType>
   <xs:complexType name="restConfigurationDefinition">
     <xs:sequence>
       <xs:element maxOccurs="unbounded" minOccurs="0" name="componentProperty" type="tns:restPropertyDefinition">
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/app/jaxb.index b/core/camel-core-model/src/generated/resources/org/apache/camel/model/app/jaxb.index
index 5a0a73a15d0..d5d2a547b9d 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/app/jaxb.index
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/app/jaxb.index
@@ -1,5 +1,7 @@
 # Generated by camel build tools - do NOT edit this file!
 ApplicationDefinition
+BeanConstructorDefinition
+BeanConstructorsDefinition
 BeanPropertiesDefinition
 BeanPropertyDefinition
 BeansDefinition
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/app/BeanConstructorDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/app/BeanConstructorDefinition.java
new file mode 100644
index 00000000000..72ce4c9f1ab
--- /dev/null
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/app/BeanConstructorDefinition.java
@@ -0,0 +1,55 @@
+/*
+ * 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.model.app;
+
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAttribute;
+import jakarta.xml.bind.annotation.XmlType;
+
+@XmlType
+@XmlAccessorType(XmlAccessType.FIELD)
+public class BeanConstructorDefinition {
+
+    @XmlAttribute
+    private Integer index;
+    @XmlAttribute(required = true)
+    private String value;
+
+    public Integer getIndex() {
+        return index;
+    }
+
+    /**
+     * Constructor index
+     */
+    public void setIndex(Integer index) {
+        this.index = index;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * The argument value for the constructor.
+     */
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/app/BeanConstructorsAdapter.java b/core/camel-core-model/src/main/java/org/apache/camel/model/app/BeanConstructorsAdapter.java
new file mode 100644
index 00000000000..4e09122732b
--- /dev/null
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/app/BeanConstructorsAdapter.java
@@ -0,0 +1,69 @@
+/*
+ * 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.model.app;
+
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import jakarta.xml.bind.annotation.adapters.XmlAdapter;
+
+public class BeanConstructorsAdapter extends XmlAdapter<BeanConstructorsDefinition, Map<Integer, Object>> {
+
+    @Override
+    public Map<Integer, Object> unmarshal(BeanConstructorsDefinition v) {
+        if (v == null) {
+            return null;
+        }
+        int counter = 0;
+        Map<Integer, Object> result = new LinkedHashMap<>();
+        for (BeanConstructorDefinition pd : v.getConstructors()) {
+            Integer idx = pd.getIndex();
+            if (idx == null) {
+                idx = counter;
+                counter++;
+            }
+            result.put(idx, pd.getValue());
+        }
+
+        return result;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public BeanConstructorsDefinition marshal(Map<Integer, Object> v) {
+        if (v == null) {
+            return null;
+        }
+        final BeanConstructorDefinition[] result = new BeanConstructorDefinition[v.size()];
+        int pos = 0;
+        for (Map.Entry<Integer, Object> entry : v.entrySet()) {
+            Integer idx = entry.getKey();
+            Object value = entry.getValue();
+            BeanConstructorDefinition pd = new BeanConstructorDefinition();
+            if (idx != null) {
+                pd.setIndex(idx);
+            }
+            pd.setValue(value.toString());
+            result[pos++] = pd;
+        }
+        BeanConstructorsDefinition def = new BeanConstructorsDefinition();
+        def.setConstructors(Arrays.asList(result));
+        return def;
+    }
+
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/app/BeanConstructorsDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/app/BeanConstructorsDefinition.java
new file mode 100644
index 00000000000..11daaacd9cf
--- /dev/null
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/app/BeanConstructorsDefinition.java
@@ -0,0 +1,41 @@
+/*
+ * 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.model.app;
+
+import java.util.List;
+
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlElement;
+import jakarta.xml.bind.annotation.XmlType;
+
+@XmlType
+@XmlAccessorType(XmlAccessType.FIELD)
+public class BeanConstructorsDefinition {
+
+    @XmlElement(name = "constructor")
+    private List<BeanConstructorDefinition> constructors;
+
+    public List<BeanConstructorDefinition> getConstructors() {
+        return constructors;
+    }
+
+    public void setConstructors(List<BeanConstructorDefinition> constructors) {
+        this.constructors = constructors;
+    }
+
+}
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 524428a4e3e..43ea6c01f6c 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,9 @@ public class RegistryBeanDefinition implements ResourceAware {
     private String name;
     @XmlAttribute(required = true)
     private String type;
+    @XmlElement(name = "constructors")
+    @XmlJavaTypeAdapter(BeanConstructorsAdapter.class)
+    private Map<Integer, Object> constructors;
     @XmlElement(name = "properties")
     @XmlJavaTypeAdapter(BeanPropertiesAdapter.class)
     private Map<String, Object> properties;
@@ -66,6 +69,14 @@ public class RegistryBeanDefinition implements ResourceAware {
         this.type = type;
     }
 
+    public Map<Integer, Object> getConstructors() {
+        return constructors;
+    }
+
+    public void setConstructors(Map<Integer, Object> constructors) {
+        this.constructors = constructors;
+    }
+
     public Map<String, Object> getProperties() {
         return properties;
     }
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 d8890ea2ce6..fc4ee8275e5 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
@@ -1640,11 +1640,12 @@ public class ModelParser extends BaseParser {
             }
             return true;
         }, (def, key) -> {
-            if ("properties".equals(key)) {
-                def.setProperties(new BeanPropertiesAdapter().unmarshal(doParseBeanPropertiesDefinition()));
-                return true;
+            switch (key) {
+                case "constructors": def.setConstructors(new BeanConstructorsAdapter().unmarshal(doParseBeanConstructorsDefinition())); break;
+                case "properties": def.setProperties(new BeanPropertiesAdapter().unmarshal(doParseBeanPropertiesDefinition())); break;
+                default: return false;
             }
-            return false;
+            return true;
         }, noValueHandler());
     }
     protected RestConfigurationDefinition doParseRestConfigurationDefinition() throws IOException, XmlPullParserException {
@@ -1687,6 +1688,26 @@ public class ModelParser extends BaseParser {
             return true;
         }, noValueHandler());
     }
+    protected BeanConstructorDefinition doParseBeanConstructorDefinition() throws IOException, XmlPullParserException {
+        return doParse(new BeanConstructorDefinition(), (def, key, val) -> {
+            switch (key) {
+                case "index": def.setIndex(Integer.valueOf(val)); break;
+                case "value": def.setValue(val); break;
+                default: return false;
+            }
+            return true;
+        }, noElementHandler(), noValueHandler());
+    }
+    protected BeanConstructorsDefinition doParseBeanConstructorsDefinition() throws IOException, XmlPullParserException {
+        return doParse(new BeanConstructorsDefinition(),
+            noAttributeHandler(), (def, key) -> {
+            if ("constructor".equals(key)) {
+                doAdd(doParseBeanConstructorDefinition(), def.getConstructors(), def::setConstructors);
+                return true;
+            }
+            return false;
+        }, noValueHandler());
+    }
     protected BeanPropertyDefinition doParseBeanPropertyDefinition() throws IOException, XmlPullParserException {
         return doParse(new BeanPropertyDefinition(), (def, key, val) -> {
             switch (key) {
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 2e89e6409c4..51ae6036ef8 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
@@ -2496,6 +2496,23 @@ public class ModelWriter extends BaseWriter {
         doWriteBeansDefinitionElements(def);
         endElement(name);
     }
+    protected void doWriteBeanConstructorDefinition(
+            String name,
+            BeanConstructorDefinition def)
+            throws IOException {
+        startElement(name);
+        doWriteAttribute("index", toString(def.getIndex()));
+        doWriteAttribute("value", def.getValue());
+        endElement(name);
+    }
+    protected void doWriteBeanConstructorsDefinition(
+            String name,
+            BeanConstructorsDefinition def)
+            throws IOException {
+        startElement(name);
+        doWriteList(null, "constructor", def.getConstructors(), this::doWriteBeanConstructorDefinition);
+        endElement(name);
+    }
     protected void doWriteBeanPropertiesDefinition(
             String name,
             BeanPropertiesDefinition def)
@@ -2551,6 +2568,7 @@ public class ModelWriter extends BaseWriter {
         startElement(name);
         doWriteAttribute("name", def.getName());
         doWriteAttribute("type", def.getType());
+        doWriteElement("constructors", new BeanConstructorsAdapter().marshal(def.getConstructors()), this::doWriteBeanConstructorsDefinition);
         doWriteElement("properties", new BeanPropertiesAdapter().marshal(def.getProperties()), this::doWriteBeanPropertiesDefinition);
         endElement(name);
     }
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 39c7c513250..577d4bec4b4 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
@@ -325,6 +325,19 @@ public class LwModelToXMLDumper implements ModelToXMLDumper {
                 type = type.substring(7);
             }
             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()) {
+                    Integer idx = entry.getKey();
+                    Object value = entry.getValue();
+                    if (idx != null) {
+                        buffer.write(String.format("            <constructor index=\"%d\" value=\"%s\"/>%n", idx, value));
+                    } else {
+                        buffer.write(String.format("            <constructor value=\"%s\"/>%n", value));
+                    }
+                }
+                buffer.write(String.format("        </constructors>%n"));
+            }
             if (b.getProperties() != null && !b.getProperties().isEmpty()) {
                 buffer.write(String.format("        <properties>%n"));
                 for (Map.Entry<String, Object> entry : b.getProperties().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 f5efc6a8bf3..17a9111179d 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
@@ -259,7 +259,7 @@ public class ModelParserTest {
         assertEquals("v2a", ((Map<String, Object>) b1.getProperties().get("nested")).get("p2"));
 
         assertEquals("b2", b2.getName());
-        assertEquals("org.apache.camel.xml.in.ModelParserTest.MyBean", b1.getType());
+        assertEquals("org.apache.camel.xml.in.ModelParserTest.MyBean", b2.getType());
         assertEquals("v1", b2.getProperties().get("p1"));
         assertEquals("v2", b2.getProperties().get("p2"));
         assertNull(b2.getProperties().get("nested"));
@@ -267,6 +267,33 @@ public class ModelParserTest {
         assertEquals("v2a", b2.getProperties().get("nested.p2"));
     }
 
+    @Test
+    public void testBeansWithConstructors() throws Exception {
+        Path dir = getResourceFolder();
+        Path path = new File(dir.toFile(), "beansWithConstructors.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(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(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/beansWithConstructors.xml b/core/camel-xml-io/src/test/resources/beansWithConstructors.xml
new file mode 100644
index 00000000000..6c7e158c239
--- /dev/null
+++ b/core/camel-xml-io/src/test/resources/beansWithConstructors.xml
@@ -0,0 +1,41 @@
+<?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">
+		<constructors>
+			<!-- index is optional -->
+			<constructor value="c1" />
+			<constructor value="c2" />
+		</constructors>
+	</bean>
+
+	<bean name="b2" type="org.apache.camel.xml.in.ModelParserTest.MyBean">
+		<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 6ed3af7c46b..1ffbd95c74b 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
@@ -338,6 +338,19 @@ public class JaxbModelToXMLDumper implements ModelToXMLDumper {
                 type = type.substring(7);
             }
             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()) {
+                    Integer idx = entry.getKey();
+                    Object value = entry.getValue();
+                    if (idx != null) {
+                        buffer.write(String.format("            <constructor index=\"%d\" value=\"%s\"/>%n", idx, value));
+                    } else {
+                        buffer.write(String.format("            <constructor value=\"%s\"/>%n", value));
+                    }
+                }
+                buffer.write(String.format("        </constructors>%n"));
+            }
             if (b.getProperties() != null && !b.getProperties().isEmpty()) {
                 buffer.write(String.format("        <properties>%n"));
                 for (Map.Entry<String, Object> entry : b.getProperties().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 3010257af60..7d73b3ebb96 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
@@ -2496,6 +2496,23 @@ public class ModelWriter extends BaseWriter {
         doWriteBeansDefinitionElements(def);
         endElement(name);
     }
+    protected void doWriteBeanConstructorDefinition(
+            String name,
+            BeanConstructorDefinition def)
+            throws IOException {
+        startElement(name);
+        doWriteAttribute("index", toString(def.getIndex()));
+        doWriteAttribute("value", def.getValue());
+        endElement(name);
+    }
+    protected void doWriteBeanConstructorsDefinition(
+            String name,
+            BeanConstructorsDefinition def)
+            throws IOException {
+        startElement(name);
+        doWriteList(null, "constructor", def.getConstructors(), this::doWriteBeanConstructorDefinition);
+        endElement(name);
+    }
     protected void doWriteBeanPropertiesDefinition(
             String name,
             BeanPropertiesDefinition def)
@@ -2551,6 +2568,7 @@ public class ModelWriter extends BaseWriter {
         startElement(name);
         doWriteAttribute("name", def.getName());
         doWriteAttribute("type", def.getType());
+        doWriteElement("constructors", new BeanConstructorsAdapter().marshal(def.getConstructors()), this::doWriteBeanConstructorsDefinition);
         doWriteElement("properties", new BeanPropertiesAdapter().marshal(def.getProperties()), this::doWriteBeanPropertiesDefinition);
         endElement(name);
     }
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 d07d18826d2..0ab28843b2a 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
@@ -314,6 +314,18 @@ public class LwModelToYAMLDumper implements ModelToYAMLDumper {
             }
             buffer.write(String.format("    - name: %s%n", b.getName()));
             buffer.write(String.format("      type: \"%s\"%n", type));
+            if (b.getConstructors() != null && !b.getConstructors().isEmpty()) {
+                buffer.write(String.format("      constructors:%n"));
+                int counter = 0;
+                for (Map.Entry<Integer, Object> entry : b.getConstructors().entrySet()) {
+                    Integer key = entry.getKey();
+                    Object value = entry.getValue();
+                    if (key == null) {
+                        key = counter++;
+                    }
+                    buffer.write(String.format("        %d: \"%s\"%n", key, value));
+                }
+            }
             if (b.getProperties() != null && !b.getProperties().isEmpty()) {
                 buffer.write(String.format("      properties:%n"));
                 for (Map.Entry<String, Object> entry : b.getProperties().entrySet()) {
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 34b2159169c..aeeced8d905 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
@@ -26,7 +26,6 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.StringJoiner;
 import java.util.function.Supplier;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -238,19 +237,24 @@ public class SpringXmlBeansHandler {
             model.addRegistryBean(rrd);
 
             // constructor arguments
-            ConstructorArgumentValues ctr = def.getConstructorArgumentValues();
-            StringJoiner sj = new StringJoiner(", ");
-            for (ConstructorArgumentValues.ValueHolder v : ctr.getIndexedArgumentValues().values()) {
-                Object val = v.getValue();
-                if (val instanceof TypedStringValue tsv) {
-                    sj.add("'" + extractValue(camelContext, tsv.getValue(), false) + "'");
-                } else if (val instanceof BeanReference br) {
-                    sj.add("'#bean:" + extractValue(camelContext, br.getBeanName(), false) + "'");
+            if (def.hasConstructorArgumentValues()) {
+                Map<Integer, Object> constructors = new LinkedHashMap<>();
+                rrd.setConstructors(constructors);
+
+                ConstructorArgumentValues ctrs = def.getConstructorArgumentValues();
+                for (int i = 0; i < ctrs.getArgumentCount(); i++) {
+                    ConstructorArgumentValues.ValueHolder vh = ctrs.getArgumentValue(i, Object.class);
+                    if (vh != null) {
+                        Object val = vh.getValue();
+                        if (val instanceof TypedStringValue tsv) {
+                            constructors.put(i, extractValue(camelContext, tsv.getValue(), false));
+                        } else if (val instanceof BeanReference br) {
+                            constructors.put(i, "#bean:" + extractValue(camelContext, br.getBeanName(), false));
+                        }
+                    }
                 }
             }
-            if (sj.length() > 0) {
-                rrd.setType("#class:" + def.getBeanClassName() + "(" + sj + ")");
-            }
+
             // property values
             if (def.hasPropertyValues()) {
                 Map<String, Object> properties = 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 d2f5d7b66fc..5493e2a5e0f 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
@@ -116,6 +116,47 @@ A `my-route` route is referring to `greeter` bean which is defined using Spring
 
 More examples can be found in xref:manual:ROOT:camel-jbang.adoc#_using_spring_beans_in_camel_xml_dsl[Camel JBang] page.
 
+=== Using bean with 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,xml]
+----
+<camel>
+
+	<bean name="beanFromProps" type="com.acme.MyBean">
+        <constructors>
+          <constructor index="0" value="true"/>
+          <constructor index="1" value="Hello World"/>
+        </constructors>
+        <!-- and you can still have properties -->
+		<properties>
+			<property key="field1" value="f1_p" />
+			<property key="field2" value="f2_p" />
+			<property key="nested.field1" value="nf1_p" />
+			<property key="nested.field2" value="nf2_p" />
+		</properties>
+	</bean>
+
+</camel>
+----
+
+If you use Camel 4.0, then constructor arguments must be defined in the `type` attribute:
+
+[source,xml]
+----
+<bean name="beanFromProps" type="com.acme.MyBean(true, 'Hello World')">
+    <properties>
+        <property key="field1" value="f1_p" />
+        <property key="field2" value="f2_p" />
+        <property key="nested.field1" value="nf1_p" />
+        <property key="nested.field2" value="nf2_p" />
+    </properties>
+</bean>
+----
+
 == 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 e5bcc4014c1..472506f2158 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
@@ -22,6 +22,8 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.StringJoiner;
+import java.util.TreeMap;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -50,6 +52,7 @@ import org.apache.camel.spi.annotations.RoutesLoader;
 import org.apache.camel.support.CachedResource;
 import org.apache.camel.support.PropertyBindingSupport;
 import org.apache.camel.support.scan.PackageScanHelper;
+import org.apache.camel.util.StringHelper;
 import org.apache.camel.xml.io.util.XmlStreamDetector;
 import org.apache.camel.xml.io.util.XmlStreamInfo;
 import org.slf4j.Logger;
@@ -324,6 +327,21 @@ public class XmlRoutesBuilderLoader extends RouteBuilderLoaderSupport {
         if (type != null && !type.startsWith("#")) {
             type = "#class:" + type;
             try {
+                // 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(getCamelContext(), type);
 
                 if (def.getProperties() != null && !def.getProperties().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 867e086a69c..1baf549658e 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
@@ -121,4 +121,27 @@ public class XmlLoadAppTest {
         }
     }
 
+    @Test
+    public void testLoadCamelAppWithBeanCtr() throws Exception {
+        try (DefaultCamelContext context = new DefaultCamelContext()) {
+            context.start();
+
+            Resource resource = PluginHelper.getResourceLoader(context).resolveResource(
+                    "/org/apache/camel/dsl/xml/io/camel-app5.xml");
+
+            RoutesLoader routesLoader = PluginHelper.getRoutesLoader(context);
+            routesLoader.preParseRoute(resource, false);
+            routesLoader.loadRoutes(resource);
+
+            assertNotNull(context.getRoute("r5"), "Loaded r5 route should be there");
+            assertEquals(1, context.getRoutes().size());
+
+            // test that loaded route works
+            MockEndpoint y5 = context.getEndpoint("mock:y5", MockEndpoint.class);
+            y5.expectedBodiesReceived("Hello World. I am Camel and 42 years old!");
+            context.createProducerTemplate().sendBody("direct:x5", "World");
+            y5.assertIsSatisfied();
+        }
+    }
+
 }
diff --git a/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/beans/MyCtrBean.java b/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/beans/MyCtrBean.java
new file mode 100644
index 00000000000..c5abd8959a7
--- /dev/null
+++ b/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/beans/MyCtrBean.java
@@ -0,0 +1,50 @@
+/*
+ * 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 MyCtrBean {
+
+    private String field1;
+    private String field2;
+    private int age;
+
+    public MyCtrBean(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 hello(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-app5.xml b/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/dsl/xml/io/camel-app5.xml
new file mode 100644
index 00000000000..b125a3f5048
--- /dev/null
+++ b/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/dsl/xml/io/camel-app5.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.MyCtrBean">
+        <constructors>
+            <constructor value="Hello"/>
+            <constructor value="Camel"/>
+        </constructors>
+        <properties>
+            <property key="age" value="42"/>
+        </properties>
+    </bean>
+
+    <route id="r5">
+        <from uri="direct:x5"/>
+        <bean ref="xml-bean-from-registry" method="hello"/>
+        <to uri="mock:y5"/>
+    </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 0655b5bdd82..5cb80ff5430 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
@@ -99,6 +99,8 @@ import org.apache.camel.model.WhenDefinition;
 import org.apache.camel.model.WhenSkipSendToEndpointDefinition;
 import org.apache.camel.model.WireTapDefinition;
 import org.apache.camel.model.app.ApplicationDefinition;
+import org.apache.camel.model.app.BeanConstructorDefinition;
+import org.apache.camel.model.app.BeanConstructorsDefinition;
 import org.apache.camel.model.app.BeanPropertiesDefinition;
 import org.apache.camel.model.app.BeanPropertyDefinition;
 import org.apache.camel.model.app.BeansDefinition;
@@ -1068,6 +1070,78 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
         }
     }
 
+    @YamlType(
+            types = org.apache.camel.model.app.BeanConstructorDefinition.class,
+            order = org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
+            properties = {
+                    @YamlProperty(name = "index", type = "number"),
+                    @YamlProperty(name = "value", type = "string", required = true)
+            }
+    )
+    public static class BeanConstructorDefinitionDeserializer extends YamlDeserializerBase<BeanConstructorDefinition> {
+        public BeanConstructorDefinitionDeserializer() {
+            super(BeanConstructorDefinition.class);
+        }
+
+        @Override
+        protected BeanConstructorDefinition newInstance() {
+            return new BeanConstructorDefinition();
+        }
+
+        @Override
+        protected boolean setProperty(BeanConstructorDefinition target, String propertyKey,
+                String propertyName, Node node) {
+            switch(propertyKey) {
+                case "index": {
+                    String val = asText(node);
+                    target.setIndex(java.lang.Integer.valueOf(val));
+                    break;
+                }
+                case "value": {
+                    String val = asText(node);
+                    target.setValue(val);
+                    break;
+                }
+                default: {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    @YamlType(
+            types = org.apache.camel.model.app.BeanConstructorsDefinition.class,
+            order = org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
+            properties = @YamlProperty(name = "constructor", type = "array:org.apache.camel.model.app.BeanConstructorDefinition")
+    )
+    public static class BeanConstructorsDefinitionDeserializer extends YamlDeserializerBase<BeanConstructorsDefinition> {
+        public BeanConstructorsDefinitionDeserializer() {
+            super(BeanConstructorsDefinition.class);
+        }
+
+        @Override
+        protected BeanConstructorsDefinition newInstance() {
+            return new BeanConstructorsDefinition();
+        }
+
+        @Override
+        protected boolean setProperty(BeanConstructorsDefinition target, String propertyKey,
+                String propertyName, Node node) {
+            switch(propertyKey) {
+                case "constructor": {
+                    java.util.List<org.apache.camel.model.app.BeanConstructorDefinition> val = asFlatList(node, org.apache.camel.model.app.BeanConstructorDefinition.class);
+                    target.setConstructors(val);
+                    break;
+                }
+                default: {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
     @YamlType(
             nodes = "bean",
             inline = true,
@@ -12274,6 +12348,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
             types = org.apache.camel.model.app.RegistryBeanDefinition.class,
             order = org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
             properties = {
+                    @YamlProperty(name = "constructors", type = "object"),
                     @YamlProperty(name = "name", type = "string", required = true),
                     @YamlProperty(name = "properties", type = "object"),
                     @YamlProperty(name = "type", type = "string", required = true)
@@ -12293,6 +12368,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
         protected boolean setProperty(RegistryBeanDefinition target, String propertyKey,
                 String propertyName, Node node) {
             switch(propertyKey) {
+                case "constructors": {
+                    java.util.Map val = asMap(node);
+                    target.setConstructors(val);
+                    break;
+                }
                 case "name": {
                     String val = asText(node);
                     target.setName(val);
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
index 960fdb05881..fa4f77c4ec4 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
@@ -35,6 +35,8 @@ public final class ModelDeserializersResolver implements YamlDeserializerResolve
             case "org.apache.camel.model.rest.BasicAuthDefinition": return new ModelDeserializers.BasicAuthDefinitionDeserializer();
             case "batch-config": return new ModelDeserializers.BatchResequencerConfigDeserializer();
             case "org.apache.camel.model.config.BatchResequencerConfig": return new ModelDeserializers.BatchResequencerConfigDeserializer();
+            case "org.apache.camel.model.app.BeanConstructorDefinition": return new ModelDeserializers.BeanConstructorDefinitionDeserializer();
+            case "org.apache.camel.model.app.BeanConstructorsDefinition": return new ModelDeserializers.BeanConstructorsDefinitionDeserializer();
             case "bean": return new ModelDeserializers.BeanDefinitionDeserializer();
             case "org.apache.camel.model.BeanDefinition": return new ModelDeserializers.BeanDefinitionDeserializer();
             case "org.apache.camel.model.app.BeanPropertiesDefinition": return new ModelDeserializers.BeanPropertiesDefinitionDeserializer();
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 7ac54a605ec..d6f62a66482 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
@@ -19,7 +19,10 @@ package org.apache.camel.dsl.yaml.deserializers;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import java.util.StringJoiner;
+import java.util.TreeMap;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.dsl.yaml.common.YamlDeserializationContext;
@@ -33,6 +36,7 @@ import org.apache.camel.spi.annotations.YamlProperty;
 import org.apache.camel.spi.annotations.YamlType;
 import org.apache.camel.support.PropertyBindingSupport;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StringHelper;
 import org.snakeyaml.engine.v2.api.ConstructNode;
 import org.snakeyaml.engine.v2.nodes.Node;
 import org.snakeyaml.engine.v2.nodes.SequenceNode;
@@ -88,7 +92,25 @@ public class BeansDeserializer extends YamlDeserializerSupport implements Constr
     }
 
     public Object newInstance(RegistryBeanDefinition bean, CamelContext context) throws Exception {
-        final Object target = PropertyBindingSupport.resolveBean(context, bean.getType());
+
+        String type = bean.getType();
+
+        // property binding support has constructor arguments as part of the type
+        StringJoiner ctr = new StringJoiner(", ");
+        if (bean.getConstructors() != null && !bean.getConstructors().isEmpty()) {
+            // need to sort constructor args based on index position
+            Map<Integer, Object> sorted = new TreeMap<>(bean.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(context, type);
 
         if (bean.getProperties() != null && !bean.getProperties().isEmpty()) {
             PropertyBindingSupport.setPropertiesOnTarget(context, target, bean.getProperties());
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 b1022f4f969..fcb2e9a20a0 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
@@ -7895,6 +7895,31 @@
           }
         }
       },
+      "org.apache.camel.model.app.BeanConstructorDefinition" : {
+        "type" : "object",
+        "additionalProperties" : false,
+        "properties" : {
+          "index" : {
+            "type" : "number"
+          },
+          "value" : {
+            "type" : "string"
+          }
+        },
+        "required" : [ "value" ]
+      },
+      "org.apache.camel.model.app.BeanConstructorsDefinition" : {
+        "type" : "object",
+        "additionalProperties" : false,
+        "properties" : {
+          "constructor" : {
+            "type" : "array",
+            "items" : {
+              "$ref" : "#/items/definitions/org.apache.camel.model.app.BeanConstructorDefinition"
+            }
+          }
+        }
+      },
       "org.apache.camel.model.app.BeanPropertiesDefinition" : {
         "type" : "object",
         "additionalProperties" : false,
@@ -7998,6 +8023,9 @@
         "type" : "object",
         "additionalProperties" : false,
         "properties" : {
+          "constructors" : {
+            "type" : "object"
+          },
           "name" : {
             "type" : "string"
           },
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 cccbc24ab24..4b1e5253ce9 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
@@ -18,6 +18,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
 
 class BeansTest extends YamlTestSupport {
 
@@ -87,4 +88,47 @@ class BeansTest extends YamlTestSupport {
                 it.nested.foo == 'f3'
             }
     }
+
+    def "beans with constructor"() {
+        when:
+        loadRoutes """
+                - beans:
+                  - name: myCtr
+                    type: ${MyCtrBean.class.name}
+                    constructors:
+                      0: 'f1'
+                      1: 'f2'
+                    properties:
+                      age: 42 
+            """
+
+        then:
+        with(context.registry.lookupByName('myCtr'), MyCtrBean) {
+            it.field1 == 'f1'
+            it.field2 == 'f2'
+            it.age == 42
+        }
+    }
+
+    def "beans with constructor sorted"() {
+        when:
+        loadRoutes """
+                - beans:
+                  - name: myCtr
+                    type: ${MyCtrBean.class.name}
+                    constructors:
+                      1: 'f2'
+                      0: 'f1'
+                    properties:
+                      age: 43 
+            """
+
+        then:
+        with(context.registry.lookupByName('myCtr'), MyCtrBean) {
+            it.field1 == 'f1'
+            it.field2 == 'f2'
+            it.age == 43
+        }
+    }
+
 }
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/model/MyCtrBean.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/model/MyCtrBean.groovy
new file mode 100644
index 00000000000..40ca33e356c
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/model/MyCtrBean.groovy
@@ -0,0 +1,44 @@
+/*
+ * 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 MyCtrBean {
+    String field1
+    String field2
+    int age;
+
+    MyCtrBean(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
+    }
+}