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