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 + } +}
