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

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

commit 4294528610c95369293118ea793f302c87b64af7
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Nov 30 10:01:42 2023 +0100

    CAMEL-20130: camel-yaml-dsl - Allow to use bean builder classes when 
defining beans
---
 .../resources/org/apache/camel/model/app/bean.json | 10 +++--
 .../camel/model/app/RegistryBeanDefinition.java    | 29 ++++++++++++++
 .../java/org/apache/camel/xml/in/ModelParser.java  |  2 +
 .../java/org/apache/camel/xml/out/ModelWriter.java |  2 +
 .../org/apache/camel/yaml/out/ModelWriter.java     |  2 +
 .../dsl/yaml/deserializers/ModelDeserializers.java | 12 ++++++
 .../dsl/yaml/deserializers/BeansDeserializer.java  | 14 ++++++-
 .../generated/resources/schema/camelYamlDsl.json   |  6 +++
 .../org/apache/camel/dsl/yaml/BeansTest.groovy     | 21 ++++++++++
 .../dsl/yaml/support/model/MyBeanBuilder.groovy    | 46 ++++++++++++++++++++++
 10 files changed, 139 insertions(+), 5 deletions(-)

diff --git 
a/core/camel-core-model/src/generated/resources/org/apache/camel/model/app/bean.json
 
b/core/camel-core-model/src/generated/resources/org/apache/camel/model/app/bean.json
index ffb007e78e4..f67b2ec342e 100644
--- 
a/core/camel-core-model/src/generated/resources/org/apache/camel/model/app/bean.json
+++ 
b/core/camel-core-model/src/generated/resources/org/apache/camel/model/app/bean.json
@@ -18,9 +18,11 @@
     "destroyMethod": { "index": 3, "kind": "attribute", "displayName": 
"Destroy Method", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "The name of the custom destroy method to invoke on bean 
shutdown, such as when Camel is shutting down. The method must have no 
arguments, but may throw any exception." },
     "factoryMethod": { "index": 4, "kind": "attribute", "displayName": 
"Factory Method", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "Name of method to invoke when creating the bean via a factory 
bean." },
     "factoryBean": { "index": 5, "kind": "attribute", "displayName": "Factory 
Bean", "required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "description": "Name 
of factory bean (bean id) to use for creating the bean." },
-    "scriptLanguage": { "index": 6, "kind": "attribute", "displayName": 
"Script Language", "label": "advanced", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "description": "The script language to use when using inlined 
script for creating the bean, such as groovy, java, javascript etc." },
-    "constructors": { "index": 7, "kind": "element", "displayName": 
"Constructors", "required": false, "type": "object", "javaType": 
"java.util.Map<java.lang.Integer, java.lang.Object>", "deprecated": false, 
"autowired": false, "secret": false, "description": "Optional constructor 
arguments for creating the bean. Arguments correspond to specific index of the 
constructor argument list, starting from zero." },
-    "properties": { "index": 8, "kind": "element", "displayName": 
"Properties", "required": false, "type": "object", "javaType": 
"java.util.Map<java.lang.String, java.lang.Object>", "deprecated": false, 
"autowired": false, "secret": false, "description": "Optional properties to set 
on the created bean." },
-    "script": { "index": 9, "kind": "element", "displayName": "Script", 
"label": "advanced", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "The script to execute that creates the bean when using 
scripting languages. If the script use the prefix resource: such as 
resource:classpath:com\/foo\/myscript.groovy, 
resource:file:\/var\/myscript.groovy, then its loaded from the external 
resource." }
+    "builderClass": { "index": 6, "kind": "attribute", "displayName": "Builder 
Class", "required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "description": "Fully 
qualified class name of builder class to use for creating and configuring the 
bean. The builder will use the properties values to configure the bean." },
+    "builderMethod": { "index": 7, "kind": "attribute", "displayName": 
"Builder Method", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": "build", "description": "Name of method when using builder 
class. This method is invoked after configuring to create the actual bean. This 
method is often named build (used by default)." },
+    "scriptLanguage": { "index": 8, "kind": "attribute", "displayName": 
"Script Language", "label": "advanced", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "description": "The script language to use when using inlined 
script for creating the bean, such as groovy, java, javascript etc." },
+    "constructors": { "index": 9, "kind": "element", "displayName": 
"Constructors", "required": false, "type": "object", "javaType": 
"java.util.Map<java.lang.Integer, java.lang.Object>", "deprecated": false, 
"autowired": false, "secret": false, "description": "Optional constructor 
arguments for creating the bean. Arguments correspond to specific index of the 
constructor argument list, starting from zero." },
+    "properties": { "index": 10, "kind": "element", "displayName": 
"Properties", "required": false, "type": "object", "javaType": 
"java.util.Map<java.lang.String, java.lang.Object>", "deprecated": false, 
"autowired": false, "secret": false, "description": "Optional properties to set 
on the created bean." },
+    "script": { "index": 11, "kind": "element", "displayName": "Script", 
"label": "advanced", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "The script to execute that creates the bean when using 
scripting languages. If the script use the prefix resource: such as 
resource:classpath:com\/foo\/myscript.groovy, 
resource:file:\/var\/myscript.groovy, then its loaded from the external 
resource." }
   }
 }
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 6c1b8da40f4..ca09f9cf1e5 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
@@ -54,6 +54,11 @@ public class RegistryBeanDefinition implements ResourceAware 
{
     @XmlAttribute
     private String factoryBean;
     @XmlAttribute
+    private String builderClass;
+    @XmlAttribute
+    @Metadata(defaultValue = "build")
+    private String builderMethod;
+    @XmlAttribute
     @Metadata(label = "advanced")
     private String scriptLanguage;
     @XmlElement(name = "constructors")
@@ -134,6 +139,30 @@ public class RegistryBeanDefinition implements 
ResourceAware {
         this.factoryBean = factoryBean;
     }
 
+    public String getBuilderClass() {
+        return builderClass;
+    }
+
+    /**
+     * Fully qualified class name of builder class to use for creating and 
configuring the bean.
+     * The builder will use the properties values to configure the bean.
+     */
+    public void setBuilderClass(String builderClass) {
+        this.builderClass = builderClass;
+    }
+
+    public String getBuilderMethod() {
+        return builderMethod;
+    }
+
+    /**
+     * Name of method when using builder class. This method is invoked after 
configuring to create
+     * the actual bean. This method is often named build (used by default).
+     */
+    public void setBuilderMethod(String builderMethod) {
+        this.builderMethod = builderMethod;
+    }
+
     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 d5ea55476bd..db2af55817d 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
@@ -1645,6 +1645,8 @@ public class ModelParser extends BaseParser {
     protected RegistryBeanDefinition doParseRegistryBeanDefinition() throws 
IOException, XmlPullParserException {
         return doParse(new RegistryBeanDefinition(), (def, key, val) -> {
             switch (key) {
+                case "builderClass": def.setBuilderClass(val); break;
+                case "builderMethod": def.setBuilderMethod(val); break;
                 case "destroyMethod": def.setDestroyMethod(val); break;
                 case "factoryBean": def.setFactoryBean(val); break;
                 case "factoryMethod": def.setFactoryMethod(val); break;
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 0b1ae97db63..c8de5e968d0 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
@@ -2585,7 +2585,9 @@ public class ModelWriter extends BaseWriter {
         doWriteAttribute("factoryMethod", def.getFactoryMethod());
         doWriteAttribute("initMethod", def.getInitMethod());
         doWriteAttribute("scriptLanguage", def.getScriptLanguage());
+        doWriteAttribute("builderClass", def.getBuilderClass());
         doWriteAttribute("name", def.getName());
+        doWriteAttribute("builderMethod", def.getBuilderMethod());
         doWriteAttribute("destroyMethod", def.getDestroyMethod());
         doWriteAttribute("type", def.getType());
         doWriteAttribute("factoryBean", def.getFactoryBean());
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 f9de1b056d8..844d01839ee 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
@@ -2585,7 +2585,9 @@ public class ModelWriter extends BaseWriter {
         doWriteAttribute("factoryMethod", def.getFactoryMethod());
         doWriteAttribute("initMethod", def.getInitMethod());
         doWriteAttribute("scriptLanguage", def.getScriptLanguage());
+        doWriteAttribute("builderClass", def.getBuilderClass());
         doWriteAttribute("name", def.getName());
+        doWriteAttribute("builderMethod", def.getBuilderMethod());
         doWriteAttribute("destroyMethod", def.getDestroyMethod());
         doWriteAttribute("type", def.getType());
         doWriteAttribute("factoryBean", def.getFactoryBean());
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 8fec7a9903c..9e01da00d36 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
@@ -12308,6 +12308,8 @@ 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 = "builder-class", type = "string"),
+                    @YamlProperty(name = "builder-method", type = "string"),
                     @YamlProperty(name = "constructors", type = "object"),
                     @YamlProperty(name = "destroy-method", type = "string"),
                     @YamlProperty(name = "factory-bean", type = "string"),
@@ -12334,6 +12336,16 @@ public final class ModelDeserializers extends 
YamlDeserializerSupport {
         protected boolean setProperty(RegistryBeanDefinition target, String 
propertyKey,
                 String propertyName, Node node) {
             switch(propertyKey) {
+                case "builder-class": {
+                    String val = asText(node);
+                    target.setBuilderClass(val);
+                    break;
+                }
+                case "builder-method": {
+                    String val = asText(node);
+                    target.setBuilderMethod(val);
+                    break;
+                }
                 case "constructors": {
                     java.util.Map val = asMap(node);
                     target.setConstructors(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 ca2eddc7879..64fdaef4f16 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
@@ -147,7 +147,19 @@ public class BeansDeserializer extends 
YamlDeserializerSupport implements Constr
             if (target == null) {
                 throw new NoSuchBeanException(def.getName(), "Creating bean 
using script returned null");
             }
-
+        } else if (def.getBuilderClass() != null) {
+            // builder class and method
+            Class<?> clazz = 
context.getClassResolver().resolveMandatoryClass(def.getBuilderClass());
+            Object builder = context.getInjector().newInstance(clazz);
+            String bm = def.getBuilderMethod() != null ? 
def.getBuilderMethod() : "build";
+
+            // create bean via builder and assign as target output
+            target = PropertyBindingSupport.build()
+                    .withCamelContext(context)
+                    .withTarget(builder)
+                    .withRemoveParameters(true)
+                    .withProperties(def.getProperties())
+                    .build(Object.class, bm);
         } else {
             // factory bean/method
             if (def.getFactoryBean() != null && def.getFactoryMethod() != 
null) {
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 da067a148aa..1447e89ffa1 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
@@ -7942,6 +7942,12 @@
         "type" : "object",
         "additionalProperties" : false,
         "properties" : {
+          "builderClass" : {
+            "type" : "string"
+          },
+          "builderMethod" : {
+            "type" : "string"
+          },
           "constructors" : {
             "type" : "object"
           },
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 194b6bf9595..e7b05bf71e2 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.MyBeanBuilder
 import org.apache.camel.dsl.yaml.support.model.MyCtrBean
 import org.apache.camel.dsl.yaml.support.model.MyDestroyBean
 import org.apache.camel.dsl.yaml.support.model.MyFacBean
@@ -229,4 +230,24 @@ class BeansTest extends YamlTestSupport {
         }
     }
 
+    def "beans with builder class"() {
+        when:
+        loadRoutes """
+                - beans:
+                  - name: myBean
+                    type: ${MyBean.class.name}
+                    builderClass: ${MyBeanBuilder.class.name}
+                    builderMethod: createTheBean
+                    properties:
+                      field1: builder1 
+                      field2: builder2 
+            """
+
+        then:
+        with(context.registry.lookupByName('myBean'), MyBean) {
+            it.field1 == 'builder1'
+            it.field2 == 'builder2'
+        }
+    }
+
 }
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/model/MyBeanBuilder.groovy
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/model/MyBeanBuilder.groovy
new file mode 100644
index 00000000000..8bd930cb953
--- /dev/null
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/support/model/MyBeanBuilder.groovy
@@ -0,0 +1,46 @@
+/*
+ * 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 MyBeanBuilder {
+    private String field1
+    private String field2
+    private MyFooBar nested
+
+    MyBeanBuilder field1(String field1) {
+        this.field1 = field1
+        return this
+    }
+
+    MyBeanBuilder field2(String field2) {
+        this.field2 = field2
+        return this
+    }
+
+    MyBeanBuilder nested(MyFooBar fooBar) {
+        this.nested = fooBar;
+        return this
+    }
+
+    MyBean createTheBean() {
+        MyBean answer = new MyBean()
+        answer.field1 = field1
+        answer.field2 = field2
+        answer.nested = nested
+        return answer
+    }
+}

Reply via email to