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 b5e06bde2e6b CAMEL-24775: camel-core - the type of a bean created by a
script or a builder is optional, in the model, the schemas and the loaders as
it is at runtime (#26513)
b5e06bde2e6b is described below
commit b5e06bde2e6bdbca6747a8b0b1137ab11f8db500
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Sep 16 18:22:54 2026 +0200
CAMEL-24775: camel-core - the type of a bean created by a script or a
builder is optional, in the model, the schemas and the loaders as it is at
runtime (#26513)
The type (class name) of a bean definition is no longer required in the
model, camel-spring.xsd, camel-xml-io.xsd, the YAML schema and the YAML loader
when the bean is created by a script or a builder, as it never was for the
runtime and the Java DSL; bind() creates route template and kamelet local beans
from a builderClass; a class or factory bean without a type fails with an
exception naming the bean instead of a NullPointerException.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
---
.../apache/camel/catalog/models/beanFactory.json | 2 +-
.../apache/camel/catalog/schemas/camel-spring.xsd | 5 +-
.../apache/camel/catalog/schemas/camel-xml-io.xsd | 5 +-
.../camel/catalog/schemas/camelYamlDsl-model.json | 3 +-
.../SpringTemplatedRouteScriptBeanNoTypeTest.java | 78 ++++++++++++++++++++
.../SpringTemplatedRouteScriptBeanNoTypeTest.xml | 56 +++++++++++++++
.../org/apache/camel/model/beanFactory.json | 2 +-
.../apache/camel/model/BeanFactoryDefinition.java | 5 +-
.../org/apache/camel/model/BeanModelHelper.java | 82 ++++++++++++++++++----
.../camel/builder/RouteTemplateLocalBeanTest.java | 51 ++++++++++++++
.../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc | 14 ++++
.../apache/camel/dsl/xml/io/XmlLoadAppTest.java | 71 +++++++++++++++++++
.../org/apache/camel/dsl/xml/io/camel-app16.xml | 39 ++++++++++
.../org/apache/camel/dsl/xml/io/camel-app17.xml | 38 ++++++++++
.../org/apache/camel/dsl/xml/io/camel-app18.xml | 35 +++++++++
.../dsl/yaml/deserializers/ModelDeserializers.java | 2 +-
.../dsl/yaml/deserializers/BeansDeserializer.java | 12 ++--
.../dsl/yaml/validator/YamlValidatorTest.java | 9 +++
.../test/resources/script-bean-without-type.yaml | 41 +++++++++++
.../resources/schema/camelYamlDsl-canonical.json | 4 +-
.../resources/schema/camelYamlDsl-model.json | 3 +-
.../generated/resources/schema/camelYamlDsl.json | 4 +-
.../org/apache/camel/dsl/yaml/BeansTest.groovy | 16 +++++
.../apache/camel/dsl/yaml/RouteTemplateTest.groovy | 62 ++++++++++++++++
24 files changed, 606 insertions(+), 33 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/beanFactory.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/beanFactory.json
index 352fcac1a5fa..c1991852dc79 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/beanFactory.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/beanFactory.json
@@ -13,7 +13,7 @@
},
"properties": {
"name": { "index": 0, "kind": "attribute", "displayName": "Name", "group":
"common", "required": true, "type": "string", "javaType": "java.lang.String",
"deprecated": false, "autowired": false, "secret": false, "description": "The
name of the bean (bean id)." },
- "type": { "index": 1, "kind": "attribute", "displayName": "Type", "group":
"common", "required": true, "type": "string", "javaType": "java.lang.String",
"deprecated": false, "autowired": false, "secret": false, "description": "The
class name (fully qualified) of the bean." },
+ "type": { "index": 1, "kind": "attribute", "displayName": "Type", "group":
"common", "required": false, "type": "string", "javaType": "java.lang.String",
"deprecated": false, "autowired": false, "secret": false, "description": "The
class name (fully qualified) of the bean. Required unless the bean is created
by a script (scriptLanguage) or a builder (builderClass), where the type is
optional and is then the type the bean is registered as." },
"initMethod": { "index": 2, "kind": "attribute", "displayName": "Init
Method", "group": "advanced", "label": "advanced", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "description": "The name of the custom initialization
method to invoke after setting bean properties. The method must have no
arguments, but may throw any exception." },
"destroyMethod": { "index": 3, "kind": "attribute", "displayName":
"Destroy Method", "group": "advanced", "label": "advanced", "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", "group": "advanced", "label": "advanced", "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." },
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 cf3e65e7ac17..7b80458c1dfe 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
@@ -3826,11 +3826,12 @@ The name of the bean (bean id).
</xs:documentation>
</xs:annotation>
</xs:attribute>
- <xs:attribute name="type" type="xs:string" use="required">
+ <xs:attribute name="type" type="xs:string">
<xs:annotation>
<xs:documentation xml:lang="en">
<![CDATA[
-The class name (fully qualified) of the bean.
+The class name (fully qualified) of the bean. Required unless the bean is
created by a script (scriptLanguage) or a
+builder (builderClass), where the type is optional and is then the type the
bean is registered as.
]]>
</xs:documentation>
</xs:annotation>
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-xml-io.xsd
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-xml-io.xsd
index 04336c3ce441..1c8cdde98ce6 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-xml-io.xsd
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-xml-io.xsd
@@ -2936,11 +2936,12 @@ The name of the bean (bean id).
</xs:documentation>
</xs:annotation>
</xs:attribute>
- <xs:attribute name="type" type="xs:string" use="required">
+ <xs:attribute name="type" type="xs:string">
<xs:annotation>
<xs:documentation xml:lang="en">
<![CDATA[
-The class name (fully qualified) of the bean.
+The class name (fully qualified) of the bean. Required unless the bean is
created by a script (scriptLanguage) or a
+builder (builderClass), where the type is optional and is then the type the
bean is registered as.
]]>
</xs:documentation>
</xs:annotation>
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camelYamlDsl-model.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camelYamlDsl-model.json
index 1bb90b40780e..d8c9a8704615 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camelYamlDsl-model.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camelYamlDsl-model.json
@@ -1450,9 +1450,8 @@
}, {
"name" : "type",
"type" : "string",
- "description" : "The class name (fully qualified) of the bean.",
+ "description" : "The class name (fully qualified) of the bean.
Required unless the bean is created by a script (scriptLanguage) or a builder
(builderClass), where the type is optional and is then the type the bean is
registered as.",
"title" : "Type",
- "required" : true,
"displayName" : "Type",
"kind" : "attribute",
"index" : 1,
diff --git
a/components/camel-spring-parent/camel-spring-xml/src/test/java/org/apache/camel/spring/routebuilder/SpringTemplatedRouteScriptBeanNoTypeTest.java
b/components/camel-spring-parent/camel-spring-xml/src/test/java/org/apache/camel/spring/routebuilder/SpringTemplatedRouteScriptBeanNoTypeTest.java
new file mode 100644
index 000000000000..b11bb834a8fa
--- /dev/null
+++
b/components/camel-spring-parent/camel-spring-xml/src/test/java/org/apache/camel/spring/routebuilder/SpringTemplatedRouteScriptBeanNoTypeTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.spring.routebuilder;
+
+import org.apache.camel.Handler;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.SpringTestSupport;
+import org.junit.jupiter.api.Test;
+import org.springframework.context.support.AbstractXmlApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * A templated route bean created by a script has no type (class name): the
Spring XSD must accept it, as the runtime
+ * does.
+ */
+public class SpringTemplatedRouteScriptBeanNoTypeTest extends
SpringTestSupport {
+
+ @Override
+ protected AbstractXmlApplicationContext createApplicationContext() {
+ return new ClassPathXmlApplicationContext(
+
"org/apache/camel/spring/routebuilder/SpringTemplatedRouteScriptBeanNoTypeTest.xml");
+ }
+
+ @Test
+ public void testScriptBeanWithoutType() throws Exception {
+ assertEquals(1, context.getRouteTemplateDefinitions().size());
+ assertEquals(2, context.getRoutes().size());
+
+ getMockEndpoint("mock:barVal").expectedBodiesReceived("-> Hello
John!");
+ template.sendBody("direct:fooVal", null);
+ MockEndpoint.assertIsSatisfied(context);
+ }
+
+ public static class MySpecialBean {
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Handler
+ public String addName(String body) {
+ return String.format("%s %s!", body, name);
+ }
+ }
+
+ public static class MyScriptBean {
+
+ public MyScriptBean create() {
+ return new MyScriptBean();
+ }
+
+ @Handler
+ public String prefix() {
+ return "-> Hello";
+ }
+ }
+}
diff --git
a/components/camel-spring-parent/camel-spring-xml/src/test/resources/org/apache/camel/spring/routebuilder/SpringTemplatedRouteScriptBeanNoTypeTest.xml
b/components/camel-spring-parent/camel-spring-xml/src/test/resources/org/apache/camel/spring/routebuilder/SpringTemplatedRouteScriptBeanNoTypeTest.xml
new file mode 100644
index 000000000000..978453305f5d
--- /dev/null
+++
b/components/camel-spring-parent/camel-spring-xml/src/test/resources/org/apache/camel/spring/routebuilder/SpringTemplatedRouteScriptBeanNoTypeTest.xml
@@ -0,0 +1,56 @@
+<?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://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd
+ http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+ <camelContext id="foo" xmlns="http://camel.apache.org/schema/spring">
+ <routeTemplate id="myTemplate" description="blah blah">
+ <templateParameter name="foo"/>
+ <templateParameter name="bar"/>
+ <route>
+ <from uri="direct:{{foo}}"/>
+ <to uri="bean:{{myScriptBean}}"/>
+ <to uri="bean:{{myBean}}"/>
+ <to uri="mock:{{bar}}"/>
+ </route>
+ </routeTemplate>
+ <templatedRoute routeTemplateRef="myTemplate" routeId="my-route">
+ <parameter name="foo" value="fooVal"/>
+ <parameter name="bar" value="barVal"/>
+ <bean name="myBean"
type="#class:org.apache.camel.spring.routebuilder.SpringTemplatedRouteScriptBeanNoTypeTest$MySpecialBean">
+ <properties>
+ <property key="name" value="John"/>
+ </properties>
+ </bean>
+ <!-- a bean created by a script needs no type (class name); the
XSD must allow it -->
+ <bean name="myScriptBean" scriptLanguage="bean">
+
<script>org.apache.camel.spring.routebuilder.SpringTemplatedRouteScriptBeanNoTypeTest$MyScriptBean?method=create</script>
+ </bean>
+ </templatedRoute>
+ <route>
+ <from uri="direct:a"/>
+ <to uri="log:foo"/>
+ </route>
+ </camelContext>
+
+</beans>
diff --git
a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/beanFactory.json
b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/beanFactory.json
index 352fcac1a5fa..c1991852dc79 100644
---
a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/beanFactory.json
+++
b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/beanFactory.json
@@ -13,7 +13,7 @@
},
"properties": {
"name": { "index": 0, "kind": "attribute", "displayName": "Name", "group":
"common", "required": true, "type": "string", "javaType": "java.lang.String",
"deprecated": false, "autowired": false, "secret": false, "description": "The
name of the bean (bean id)." },
- "type": { "index": 1, "kind": "attribute", "displayName": "Type", "group":
"common", "required": true, "type": "string", "javaType": "java.lang.String",
"deprecated": false, "autowired": false, "secret": false, "description": "The
class name (fully qualified) of the bean." },
+ "type": { "index": 1, "kind": "attribute", "displayName": "Type", "group":
"common", "required": false, "type": "string", "javaType": "java.lang.String",
"deprecated": false, "autowired": false, "secret": false, "description": "The
class name (fully qualified) of the bean. Required unless the bean is created
by a script (scriptLanguage) or a builder (builderClass), where the type is
optional and is then the type the bean is registered as." },
"initMethod": { "index": 2, "kind": "attribute", "displayName": "Init
Method", "group": "advanced", "label": "advanced", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "description": "The name of the custom initialization
method to invoke after setting bean properties. The method must have no
arguments, but may throw any exception." },
"destroyMethod": { "index": 3, "kind": "attribute", "displayName":
"Destroy Method", "group": "advanced", "label": "advanced", "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", "group": "advanced", "label": "advanced", "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." },
diff --git
a/core/camel-core-model/src/main/java/org/apache/camel/model/BeanFactoryDefinition.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/BeanFactoryDefinition.java
index 1a18f89b7cd7..a1c17d519853 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/BeanFactoryDefinition.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/BeanFactoryDefinition.java
@@ -56,8 +56,9 @@ public class BeanFactoryDefinition<P> implements
ResourceAware {
@XmlAttribute(required = true)
@Metadata(description = "The name of the bean (bean id).")
private String name;
- @XmlAttribute(required = true)
- @Metadata(description = "The class name (fully qualified) of the bean.")
+ @XmlAttribute
+ @Metadata(description = "The class name (fully qualified) of the bean.
Required unless the bean is created by a script (scriptLanguage)"
+ + " or a builder (builderClass), where the type is
optional and is then the type the bean is registered as.")
private String type;
@XmlAttribute
@Metadata(label = "advanced",
diff --git
a/core/camel-core-model/src/main/java/org/apache/camel/model/BeanModelHelper.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/BeanModelHelper.java
index c11221f1c63f..0ff14540a0a3 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/BeanModelHelper.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/BeanModelHelper.java
@@ -58,31 +58,44 @@ public final class BeanModelHelper {
public static Object newInstance(BeanFactoryDefinition def, CamelContext
context) throws Exception {
Object target;
+ boolean script = def.getScriptLanguage() != null && def.getScript() !=
null;
+ boolean viaBuilder = def.getBuilderClass() != null;
+
+ // the type (class name) is optional for a bean created by a script or
a builder
String type = def.getType();
- if (!type.startsWith("#")) {
+ if (type == null && !script && !viaBuilder) {
+ throw new IllegalArgumentException(
+ "Bean " + def.getName() + " must have a type (class name)
unless created by a script or a builder");
+ }
+ if (type != null && !type.startsWith("#")) {
type = "#class:" + type;
}
// script bean
- if (def.getScriptLanguage() != null && def.getScript() != null) {
- String script = resolveScript(context, def);
+ if (script) {
+ String text = resolveScript(context, def);
// create bean via the script
final Language lan =
context.resolveLanguage(def.getScriptLanguage());
final ScriptingLanguage slan = lan instanceof ScriptingLanguage sl
? sl : null;
- String fqn = def.getType();
- if (fqn.startsWith("#class:")) {
- fqn = fqn.substring(7);
+ final Class<?> clazz;
+ if (def.getType() != null) {
+ String fqn = def.getType();
+ if (fqn.startsWith("#class:")) {
+ fqn = fqn.substring(7);
+ }
+ clazz = context.getClassResolver().resolveMandatoryClass(fqn);
+ } else {
+ clazz = Object.class;
}
- final Class<?> clazz =
context.getClassResolver().resolveMandatoryClass(fqn);
if (slan != null) {
// scripting language should be evaluated with context as
binding
Map<String, Object> bindings = new HashMap<>();
bindings.put("context", context);
- target = slan.evaluate(script, bindings, clazz);
+ target = slan.evaluate(text, bindings, clazz);
} else {
Exchange dummy = ExchangeHelper.getDummy(context);
- String text =
ScriptHelper.resolveOptionalExternalScript(context, dummy, script);
- Expression exp = lan.createExpression(text);
+ String external =
ScriptHelper.resolveOptionalExternalScript(context, dummy, text);
+ Expression exp = lan.createExpression(external);
target = exp.evaluate(dummy, clazz);
}
@@ -90,7 +103,7 @@ public final class BeanModelHelper {
if (target == null) {
throw new NoSuchBeanException(def.getName(), "Creating bean
using script returned null");
}
- } else if (def.getBuilderClass() != null) {
+ } else if (viaBuilder) {
// builder class and method
Class<?> clazz =
context.getClassResolver().resolveMandatoryClass(def.getBuilderClass());
Object builder = context.getInjector().newInstance(clazz);
@@ -129,7 +142,7 @@ public final class BeanModelHelper {
}
// do not set properties when using #type as it uses an existing
shared bean
- boolean setProps = !type.startsWith("#type");
+ boolean setProps = type == null || !type.startsWith("#type");
if (setProps) {
// set optional properties on created bean
if (def.getProperties() != null && !def.getProperties().isEmpty())
{
@@ -240,6 +253,51 @@ public final class BeanModelHelper {
}
}));
}
+ } else if (def.getBuilderClass() != null) {
+ // builder class and method, the type (class name) is optional
+ final CamelContext camelContext =
routeTemplateContext.getCamelContext();
+ final Class<?> clazz;
+ if (def.getBeanClass() != null) {
+ clazz = def.getBeanClass();
+ } else if (def.getType() != null) {
+ String fqn = def.getType();
+ if (fqn.contains(":")) {
+ fqn = StringHelper.after(fqn, ":");
+ }
+ clazz =
camelContext.getClassResolver().resolveMandatoryClass(fqn);
+ } else {
+ clazz = Object.class;
+ }
+ // memorize so the bean is only created once and the local bean is
the same
+ // if a route template refers to the local bean multiple times
+ routeTemplateContext.bind(def.getName(), clazz,
Suppliers.memorize(() -> {
+ try {
+ Class<?> builderClass =
camelContext.getClassResolver().resolveMandatoryClass(def.getBuilderClass());
+ Object builder =
camelContext.getInjector().newInstance(builderClass);
+ String bm = def.getBuilderMethod() != null ?
def.getBuilderMethod() : "build";
+ // create bean via builder and assign as target output
+ Object local = PropertyBindingSupport.build()
+ .withCamelContext(camelContext)
+ .withTarget(builder)
+ .withRemoveParameters(true)
+ .withProperties(props)
+ .build(Object.class, bm);
+ // set the optional properties the builder did not take on
the created bean
+ if (!props.isEmpty()) {
+
PropertyBindingSupport.setPropertiesOnTarget(camelContext, local, props);
+ }
+ if (def.getInitMethod() != null) {
+ ObjectHelper.invokeMethodSafe(def.getInitMethod(),
local);
+ }
+ if (def.getDestroyMethod() != null) {
+
routeTemplateContext.registerDestroyMethod(def.getName(),
def.getDestroyMethod());
+ }
+ return local;
+ } catch (Exception e) {
+ throw new IllegalStateException(
+ "Cannot create bean: " + def.getName() + " using
builder: " + def.getBuilderClass(), e);
+ }
+ }));
} else if (def.getBeanClass() != null || def.getType() != null) {
String type = def.getType();
if (type == null) {
diff --git
a/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
index bbe7097c2c0a..ecfb6f622618 100644
---
a/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
+++
b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateLocalBeanTest.java
@@ -833,6 +833,42 @@ public class RouteTemplateLocalBeanTest extends
ContextTestSupport {
context.stop();
}
+ @Test
+ public void testLocalBeanBuilderClassWithoutType() throws Exception {
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+
routeTemplate("myTemplate").templateParameter("foo").templateParameter("bar")
+ .templateBean("myBar")
+ // a bean created by a builder needs no type (class
name)
+
.builderClass("org.apache.camel.builder.RouteTemplateLocalBeanTest$BuilderThreeProcessorBuilder")
+ .builderMethod("createProcessor")
+ .property("prefix", "MyPrefix ")
+ .end()
+ .from("direct:{{foo}}")
+ .to("bean:{{bar}}");
+ }
+ });
+
+ context.start();
+
+ TemplatedRouteBuilder.builder(context, "myTemplate")
+ .parameter("foo", "one")
+ .parameter("bar", "myBar")
+ .routeId("myRoute")
+ .add();
+
+ assertEquals(1, context.getRoutes().size());
+
+ Object out = template.requestBody("direct:one", "World");
+ assertEquals("MyPrefix Builder3 World", out);
+
+ // should not be a global bean
+ assertNull(context.getRegistry().lookupByName("myBar"));
+
+ context.stop();
+ }
+
@Test
public void testLocalBeanConstructorParameterInType() throws Exception {
context.addRoutes(new RouteBuilder() {
@@ -935,6 +971,21 @@ public class RouteTemplateLocalBeanTest extends
ContextTestSupport {
}
+ public static class BuilderThreeProcessorBuilder {
+
+ private String prefix = "";
+
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public BuilderThreeProcessor createProcessor() {
+ BuilderThreeProcessor answer = new BuilderThreeProcessor();
+ answer.setPrefix(prefix);
+ return answer;
+ }
+ }
+
public Processor createBuilderProcessor() {
return new BuilderProcessor();
}
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index b01b9bcc8dea..819de4a90f74 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -454,6 +454,20 @@ set here, because that would reject input that parses
today. Routes that genuine
an external DTD or parameter entity through this converter must supply their
own
`SAXParserFactory`.
+=== camel-core - the type of a bean created by a script or a builder is
optional
+
+The `type` (class name) of a bean definition — `bean` under `beans`,
`templateBean` of a route
+template, `bean` of a templated route — is no longer declared as required. It
was required since the
+attribute also selected how the bean is created; that moved to
`scriptLanguage` in Camel 4.1, and
+a bean created by a script (`scriptLanguage` and `script`) or a builder
(`builderClass`) needs no
+class name: the runtime registers it as the type of the object the script or
builder returns, as
+the Java DSL `templateBean(name, language, script)` always did.
+
+The XML schemas (`camel-spring.xsd`, `camel-xml-io.xsd`) and the YAML schema
no longer require
+`type`, so Spring XML and the YAML validator (`camel validate`) now accept
what the runtime already
+ran. A bean that is neither scripted nor built still needs a `type`, and the
error for a missing one
+is now an `IllegalArgumentException` naming the bean instead of a
`NullPointerException`.
+
=== Component deprecation
==== camel-minio
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 59aa66d385ec..60e49184b919 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
@@ -37,6 +37,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class XmlLoadAppTest {
@@ -261,6 +262,76 @@ public class XmlLoadAppTest {
}
}
+ @Test
+ public void testLoadCamelAppWithBeanScriptWithoutType() throws Exception {
+ try (DefaultCamelContext context = new DefaultCamelContext()) {
+ context.start();
+
+ Resource resource =
PluginHelper.getResourceLoader(context).resolveResource(
+ "/org/apache/camel/dsl/xml/io/camel-app16.xml");
+
+ RoutesLoader routesLoader = PluginHelper.getRoutesLoader(context);
+ routesLoader.preParseRoute(resource, false);
+ routesLoader.loadRoutes(resource);
+
+ assertNotNull(context.getRoute("r16"), "Loaded r16 route should be
there");
+
+ // the script created the bean without a type being declared
+ MockEndpoint y16 = context.getEndpoint("mock:y16",
MockEndpoint.class);
+ y16.expectedBodiesReceived("Hi World from groovy Uranus");
+ context.createProducerTemplate().sendBody("direct:x16", "I'm
Uranus");
+ y16.assertIsSatisfied();
+
+ context.stop();
+ }
+ }
+
+ @Test
+ public void testLoadCamelAppWithBeanBuilderClassWithoutType() throws
Exception {
+ try (DefaultCamelContext context = new DefaultCamelContext()) {
+ context.start();
+
+ Resource resource =
PluginHelper.getResourceLoader(context).resolveResource(
+ "/org/apache/camel/dsl/xml/io/camel-app17.xml");
+
+ RoutesLoader routesLoader = PluginHelper.getRoutesLoader(context);
+ routesLoader.preParseRoute(resource, false);
+ routesLoader.loadRoutes(resource);
+
+ assertNotNull(context.getRoute("r17"), "Loaded r17 route should be
there");
+
+ // the builder created the bean without a type being declared
+ MockEndpoint y17 = context.getEndpoint("mock:y17",
MockEndpoint.class);
+ y17.expectedBodiesReceived("Hi World. I am Camel and 44 years
old!");
+ context.createProducerTemplate().sendBody("direct:x17", "Hi");
+ y17.assertIsSatisfied();
+
+ context.stop();
+ }
+ }
+
+ @Test
+ public void testLoadCamelAppWithBeanWithoutTypeFails() throws Exception {
+ try (DefaultCamelContext context = new DefaultCamelContext()) {
+ context.start();
+
+ Resource resource =
PluginHelper.getResourceLoader(context).resolveResource(
+ "/org/apache/camel/dsl/xml/io/camel-app18.xml");
+
+ RoutesLoader routesLoader = PluginHelper.getRoutesLoader(context);
+ routesLoader.preParseRoute(resource, false);
+
+ // a bean that is neither scripted nor built has nothing to create
it from
+ Exception e = assertThrows(Exception.class, () ->
routesLoader.loadRoutes(resource));
+ Throwable cause = e.getCause() != null ? e.getCause() : e;
+ assertTrue(cause instanceof IllegalArgumentException, "Expected
IllegalArgumentException but was " + cause);
+ assertEquals("Bean xml-bean-from-registry must have a type (class
name) unless created by a script or a builder",
+ cause.getMessage());
+
+ context.stop();
+ }
+ }
+
@Test
public void testLoadCamelAppWithBeanBuilderClass() throws Exception {
try (DefaultCamelContext context = new DefaultCamelContext()) {
diff --git
a/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/dsl/xml/io/camel-app16.xml
b/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/dsl/xml/io/camel-app16.xml
new file mode 100644
index 000000000000..2a48259921ea
--- /dev/null
+++
b/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/dsl/xml/io/camel-app16.xml
@@ -0,0 +1,39 @@
+<?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/xml-io"
xmlns:s="http://www.springframework.org/schema/beans">
+
+ <!-- a bean created by a script needs no type (class name) -->
+ <bean name="xml-bean-from-registry" scriptLanguage="groovy">
+ <script>
+ b = new org.apache.camel.dsl.xml.io.beans.Greeter()
+ m = new org.apache.camel.dsl.xml.io.beans.GreeterMessage()
+ m.msg = 'Hi World from groovy'
+ b.message = m
+ return b
+ </script>
+ </bean>
+
+ <route id="r16">
+ <from uri="direct:x16"/>
+ <process ref="xml-bean-from-registry"/>
+ <to uri="mock:y16"/>
+ </route>
+
+</camel>
diff --git
a/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/dsl/xml/io/camel-app17.xml
b/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/dsl/xml/io/camel-app17.xml
new file mode 100644
index 000000000000..d075c9bd0c7f
--- /dev/null
+++
b/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/dsl/xml/io/camel-app17.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/xml-io"
xmlns:s="http://www.springframework.org/schema/beans">
+
+ <!-- a bean created by a builder needs no type (class name) -->
+ <bean name="xml-bean-from-registry"
+ builderClass="org.apache.camel.dsl.xml.io.beans.MyBeanBuilder"
builderMethod="createTheBean">
+ <properties>
+ <property key="field1" value="World"/>
+ <property key="field2" value="Camel"/>
+ <property key="age" value="44"/>
+ </properties>
+ </bean>
+
+ <route id="r17">
+ <from uri="direct:x17"/>
+ <bean ref="xml-bean-from-registry"/>
+ <to uri="mock:y17"/>
+ </route>
+
+</camel>
diff --git
a/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/dsl/xml/io/camel-app18.xml
b/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/dsl/xml/io/camel-app18.xml
new file mode 100644
index 000000000000..64ed4b2db801
--- /dev/null
+++
b/dsl/camel-xml-io-dsl/src/test/resources/org/apache/camel/dsl/xml/io/camel-app18.xml
@@ -0,0 +1,35 @@
+<?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/xml-io"
xmlns:s="http://www.springframework.org/schema/beans">
+
+ <!-- a bean that is neither scripted nor built needs a type -->
+ <bean name="xml-bean-from-registry">
+ <properties>
+ <property key="field1" value="World"/>
+ </properties>
+ </bean>
+
+ <route id="r18">
+ <from uri="direct:x18"/>
+ <bean ref="xml-bean-from-registry"/>
+ <to uri="mock:y18"/>
+ </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 a10bf691ca12..c911970b1d62 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
@@ -1293,7 +1293,7 @@ public final class ModelDeserializers extends
YamlDeserializerSupport {
@YamlProperty(name = "script", type = "string",
description = "The script to execute that creates the bean when using scripting
languages.", displayName = "Script"),
@YamlProperty(name = "scriptLanguage", type = "string",
description = "The script language to use when using inlined script for
creating the bean, such as groovy, java, javascript etc.", displayName =
"Script Language"),
@YamlProperty(name = "scriptPropertyPlaceholders", type =
"boolean", defaultValue = "true", description = "Whether the script should
support using Camel property placeholder syntax {{ }}.", displayName = "Script
Property Placeholders"),
- @YamlProperty(name = "type", type = "string", required =
true, description = "The class name (fully qualified) of the bean.",
displayName = "Type")
+ @YamlProperty(name = "type", type = "string", description
= "The class name (fully qualified) of the bean. Required unless the bean is
created by a script (scriptLanguage) or a builder (builderClass), where the
type is optional and is then the type the bean is registered as.", displayName
= "Type")
}
)
public static class BeanFactoryDefinitionDeserializer extends
YamlDeserializerBase<BeanFactoryDefinition> {
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 b754dc3f802d..92b4ef071ea1 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
@@ -69,14 +69,18 @@ public class BeansDeserializer extends
YamlDeserializerSupport implements Constr
}
ObjectHelper.notNull(bean.getName(), "The bean name must be set");
- ObjectHelper.notNull(bean.getType(), "The bean type must be set");
- if (!bean.getType().startsWith("#class:")) {
- bean.setType("#class:" + bean.getType());
- }
if (bean.getScriptLanguage() != null || bean.getScript() != null) {
ObjectHelper.notNull(bean.getScriptLanguage(), "The bean
script language must be set");
ObjectHelper.notNull(bean.getScript(), "The bean script must
be set");
}
+ boolean script = bean.getScriptLanguage() != null &&
bean.getScript() != null;
+ // the type (class name) is optional for a bean created by a
script or a builder
+ if (!script && bean.getBuilderClass() == null) {
+ ObjectHelper.notNull(bean.getType(), "The bean type must be
set");
+ }
+ if (bean.getType() != null &&
!bean.getType().startsWith("#class:")) {
+ bean.setType("#class:" + bean.getType());
+ }
// due to yaml-dsl is pre parsing beans which gets created eager
// and then later beans can be parsed again such as from Yaml dsl
files
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorTest.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorTest.java
index bc828f50c412..a9eb2ab4c132 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorTest.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorTest.java
@@ -58,6 +58,15 @@ public class YamlValidatorTest {
Assertions.assertTrue(report.get(0).getMessage().contains("setCheese"));
}
+ @Test
+ public void testScriptAndBuilderBeanWithoutType() throws Exception {
+ // CAMEL-24775: the type (class name) is optional for a bean created
by a script or a builder, in the
+ // registry beans and in a route template, as it is for the runtime
and the Java DSL
+ var report = validator.validate(new
File("src/test/resources/script-bean-without-type.yaml"));
+ Assertions.assertTrue(report.isEmpty(), "A scripted or built bean
needs no type but got: "
+ + report.stream().map(e ->
e.getMessage()).toList());
+ }
+
@Test
public void testTypeMismatchFiltersOneOfNoise() throws Exception {
var report = validator.validate(new
File("src/test/resources/type-mismatch.yaml"));
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/script-bean-without-type.yaml
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/script-bean-without-type.yaml
new file mode 100644
index 000000000000..157dcc2069ea
--- /dev/null
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/script-bean-without-type.yaml
@@ -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.
+#
+
+# a bean created by a script (scriptLanguage) or a builder (builderClass)
needs no type (class name)
+- beans:
+ - name: myBean
+ scriptLanguage: groovy
+ script: |
+ new java.util.ArrayList()
+ - name: myBuiltBean
+ builderClass: com.acme.MyBeanBuilder
+ properties:
+ field1: World
+- routeTemplate:
+ id: myTemplate
+ parameters:
+ - name: region
+ beans:
+ - name: myClient
+ scriptLanguage: groovy
+ script: |
+ "hello " + rtc.getProperty("region", String.class)
+ from:
+ uri: direct:start
+ steps:
+ - to:
+ uri: "log:{{myClient}}"
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-canonical.json
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-canonical.json
index c9283f62401e..62ed8fb88ff3 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-canonical.json
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-canonical.json
@@ -682,10 +682,10 @@
"type" : {
"type" : "string",
"title" : "Type",
- "description" : "The class name (fully qualified) of the bean."
+ "description" : "The class name (fully qualified) of the bean.
Required unless the bean is created by a script (scriptLanguage) or a builder
(builderClass), where the type is optional and is then the type the bean is
registered as."
}
},
- "required" : [ "name", "type" ]
+ "required" : [ "name" ]
},
"org.apache.camel.model.CacheDefinition" : {
"title" : "Cache",
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
index 1bb90b40780e..d8c9a8704615 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
@@ -1450,9 +1450,8 @@
}, {
"name" : "type",
"type" : "string",
- "description" : "The class name (fully qualified) of the bean.",
+ "description" : "The class name (fully qualified) of the bean.
Required unless the bean is created by a script (scriptLanguage) or a builder
(builderClass), where the type is optional and is then the type the bean is
registered as.",
"title" : "Type",
- "required" : true,
"displayName" : "Type",
"kind" : "attribute",
"index" : 1,
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 5a0e9ba16d5c..bfa94fc87e16 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
@@ -742,10 +742,10 @@
"type" : {
"type" : "string",
"title" : "Type",
- "description" : "The class name (fully qualified) of the bean."
+ "description" : "The class name (fully qualified) of the bean.
Required unless the bean is created by a script (scriptLanguage) or a builder
(builderClass), where the type is optional and is then the type the bean is
registered as."
}
},
- "required" : [ "name", "type" ]
+ "required" : [ "name" ]
},
"org.apache.camel.model.CacheDefinition" : {
"title" : "Cache",
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 d5e5f40af62e..6c1599cf6c17 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
@@ -230,6 +230,22 @@ class BeansTest extends YamlTestSupport {
}
}
+ def "beans with script without type"() {
+ when:
+ loadRoutes """
+ - beans:
+ - name: myBean
+ scriptLanguage: groovy
+ script: "var b = new ${MyBean.class.name}(); b.field1 =
'script1'; b.field2 = 'script2'; return b"
+ """
+
+ then:
+ with(context.registry.lookupByName('myBean'), MyBean) {
+ it.field1 == 'script1'
+ it.field2 == 'script2'
+ }
+ }
+
def "beans with script property placeholder default"() {
when:
context.getPropertiesComponent().addInitialProperty("cheese", "gauda")
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteTemplateTest.groovy
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteTemplateTest.groovy
index ef9f558abb74..5079010281be 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteTemplateTest.groovy
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteTemplateTest.groovy
@@ -18,6 +18,7 @@ package org.apache.camel.dsl.yaml
import org.apache.camel.component.mock.MockEndpoint
import org.apache.camel.dsl.yaml.support.YamlTestSupport
+import org.apache.camel.dsl.yaml.support.model.MyBeanBuilder
import org.apache.camel.dsl.yaml.support.model.MySetBody
import org.apache.camel.dsl.yaml.support.model.MyUppercaseProcessor
import org.apache.camel.impl.engine.DefaultRoute
@@ -133,6 +134,24 @@ class RouteTemplateTest extends YamlTestSupport {
steps:
- to: "direct:myId"
- to: "mock:result"
+ """),
+ asResource('script-without-type', """
+ - routeTemplate:
+ id: "myTemplate"
+ beans:
+ - name: "myProcessor"
+ scriptLanguage: "groovy"
+ script: "new
${MyUppercaseProcessor.class.name}()"
+ from:
+ uri: "direct:{{directName}}"
+ steps:
+ - process:
+ ref: "{{myProcessor}}"
+ - from:
+ uri: "direct:start"
+ steps:
+ - to: "direct:myId"
+ - to: "mock:result"
""")
]
}
@@ -181,6 +200,49 @@ class RouteTemplateTest extends YamlTestSupport {
MockEndpoint.assertIsSatisfied(context)
}
+ def "create template with builder bean without type"() {
+ setup:
+ loadRoutes """
+ - routeTemplate:
+ id: "myTemplate"
+ beans:
+ - name: "myBean"
+ builderClass: "${MyBeanBuilder.class.name}"
+ builderMethod: "createTheBean"
+ properties:
+ field1: "builder-hello"
+ from:
+ uri: "direct:{{directName}}"
+ steps:
+ - to: "bean:{{myBean}}?method=getField1"
+ - from:
+ uri: "direct:start"
+ steps:
+ - to: "direct:myId"
+ - to: "mock:result"
+ """
+
+ withMock('mock:result') {
+ expectedMessageCount 1
+ expectedBodiesReceived 'builder-hello'
+ }
+ when:
+ context.addRouteFromTemplate('myId', 'myTemplate', ['directName':
'myId'])
+ context.start()
+
+ withTemplate {
+ to('direct:start').withBody('hello').send()
+ }
+ then:
+ with(context.routeTemplateDefinitions[0], RouteTemplateDefinition) {
+ id == 'myTemplate'
+ templateBeans.size() == 1
+ templateBeans[0].type == null
+ }
+
+ MockEndpoint.assertIsSatisfied(context)
+ }
+
def "create template with properties"() {
when:
loadRoutes """