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 8b6af4a CAMEL-16608: Kamelet local bean - Using script should allow
to define return type of created bean
8b6af4a is described below
commit 8b6af4ada9fd3c42a0e3f8e09d5a0c7bf852db51
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri May 14 07:43:26 2021 +0200
CAMEL-16608: Kamelet local bean - Using script should allow to define
return type of created bean
---
.../kamelet/KameletLocalBeanClassThreeTest.java | 2 +-
.../java/org/apache/camel/impl/DefaultModel.java | 4 +-
.../org/apache/camel/model/templateBean.json | 1 +
.../camel/model/RouteTemplateBeanDefinition.java | 143 +++++++++++++++------
.../camel/model/RouteTemplateDefinition.java | 21 +++
.../camel/builder/RouteTemplateLocalBeanTest.java | 4 +-
.../java/org/apache/camel/xml/in/ModelParser.java | 1 +
.../modules/ROOT/pages/route-template.adoc | 42 +++++-
.../dsl/yaml/deserializers/ModelDeserializers.java | 6 +
.../src/generated/resources/camel-yaml-dsl.json | 3 +
.../apache/camel/dsl/yaml/RouteTemplateTest.groovy | 19 +++
11 files changed, 198 insertions(+), 48 deletions(-)
diff --git
a/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassThreeTest.java
b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassThreeTest.java
index 5d4b3f8..c50fe1f 100644
---
a/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassThreeTest.java
+++
b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanClassThreeTest.java
@@ -47,7 +47,7 @@ public class KameletLocalBeanClassThreeTest extends
CamelTestSupport {
routeTemplate("whereTo")
.templateParameter("bar")
.templateBean("myBar")
- .type(MyBar.class)
+ .typeClass(MyBar.class)
.property("bar", "{{bar}}")
.end()
.from("kamelet:source")
diff --git
a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
index 4311416..56196e7 100644
---
a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
+++
b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
@@ -360,7 +360,9 @@ public class DefaultModel implements Model {
} else if (b.getScript() != null) {
final String script = b.getScript().getScript();
final Language lan = camelContext.resolveLanguage(b.getType());
- final Class<?> clazz = b.getBeanClass() != null ?
b.getBeanClass() : Object.class;
+ final Class<?> clazz = b.getBeanType() != null
+ ?
camelContext.getClassResolver().resolveMandatoryClass(b.getBeanType())
+ : b.getBeanClass() != null ? b.getBeanClass() :
Object.class;
final ScriptingLanguage slan = lan instanceof
ScriptingLanguage ? (ScriptingLanguage) lan : null;
if (slan != null) {
// scripting language should be evaluated with route
template context as binding
diff --git
a/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateBean.json
b/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateBean.json
index 9f2c566..991833d 100644
---
a/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateBean.json
+++
b/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateBean.json
@@ -13,6 +13,7 @@
"properties": {
"name": { "kind": "attribute", "displayName": "Name", "required": true,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "description": "Bean name" },
"type": { "kind": "attribute", "displayName": "Type", "required": true,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "description": "What type to use for
creating the bean. Can be one of:
#class,#type,bean,groovy,joor,language,mvel,ognl. #class or #type then the bean
is created via the fully qualified classname, such as #class:com.foo.MyBean The
others are scripting languages that gives more power to create the bean with
[...]
+ "beanType": { "kind": "attribute", "displayName": "Bean Type", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "description": "To set the type (fully
qualified class name) of the returned bean created by the script. Knowing the
type of the bean can be needed when dependency injection by type is in use, or
when looking in registry via class type." },
"property": { "kind": "element", "displayName": "Property", "required":
false, "type": "array", "javaType":
"java.util.List<org.apache.camel.model.PropertyDefinition>", "deprecated":
false, "autowired": false, "secret": false, "description": "Optional properties
to set on the created local bean" },
"script": { "kind": "element", "displayName": "Script", "required": false,
"type": "object", "javaType":
"org.apache.camel.model.RouteTemplateScriptDefinition", "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/RouteTemplateBeanDefinition.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateBeanDefinition.java
index 10b76b3..31fbbdb 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateBeanDefinition.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateBeanDefinition.java
@@ -43,6 +43,8 @@ public class RouteTemplateBeanDefinition {
private String name;
@XmlAttribute(required = true)
private String type;
+ @XmlAttribute
+ private String beanType;
@XmlElement(name = "property")
private List<PropertyDefinition> properties;
@XmlElement(name = "script")
@@ -75,14 +77,6 @@ public class RouteTemplateBeanDefinition {
this.name = name;
}
- public Class<?> getBeanClass() {
- return beanClass;
- }
-
- public void setBeanType(Class<?> beanType) {
- this.beanClass = beanType;
- }
-
public String getType() {
return type;
}
@@ -99,6 +93,34 @@ public class RouteTemplateBeanDefinition {
this.type = type;
}
+ public String getBeanType() {
+ return beanType;
+ }
+
+ /**
+ * To set the type (fully qualified class name) of the returned bean
created by the script.
+ *
+ * Knowing the type of the bean can be needed when dependency injection by
type is in use, or when looking in
+ * registry via class type.
+ */
+ public void setBeanType(String beanType) {
+ this.beanType = beanType;
+ }
+
+ /**
+ * To set the type (fully qualified class name) of the returned bean
created by the script.
+ *
+ * Knowing the type of the bean can be needed when dependency injection by
type is in use, or when looking in
+ * registry via class type.
+ */
+ public void setBeanType(Class<?> beanType) {
+ this.beanClass = beanType;
+ }
+
+ public Class<?> getBeanClass() {
+ return beanClass;
+ }
+
public List<PropertyDefinition> getProperties() {
return properties;
}
@@ -150,24 +172,87 @@ public class RouteTemplateBeanDefinition {
// ----------------------------------------------------
/**
+ * What type to use for creating the bean. Can be one of:
#class,#type,bean,groovy,joor,language,mvel,ognl.
+ *
+ * #class or #type then the bean is created via the fully qualified
classname, such as #class:com.foo.MyBean
+ *
+ * The others are scripting languages that gives more power to create the
bean with an inlined code in the script
+ * section, such as using groovy.
+ */
+ public RouteTemplateBeanDefinition type(String prefix, Class<?> type) {
+ if (prefix.startsWith("#type") || prefix.startsWith("#class")) {
+ if (!prefix.endsWith(":")) {
+ prefix = prefix + ":";
+ }
+ setType(prefix + type.getName());
+ } else {
+ // its a script
+ setType(prefix);
+ }
+ setBeanType(type);
+ return this;
+ }
+
+ /**
+ * What type to use for creating the bean. Can be one of:
#class,#type,bean,groovy,joor,language,mvel,ognl.
+ *
+ * #class or #type then the bean is created via the fully qualified
classname, such as #class:com.foo.MyBean
+ *
+ * The others are scripting languages that gives more power to create the
bean with an inlined code in the script
+ * section, such as using groovy.
+ */
+ public RouteTemplateBeanDefinition type(String type) {
+ if (!type.startsWith("#type:") && !type.startsWith("#class:")) {
+ type = "#class:" + type;
+ }
+ setType(type);
+ return this;
+ }
+
+ /**
* Creates the bean from the given class type
*
* @param type the type of the class to create as bean
*/
- public RouteTemplateDefinition beanClass(Class<?> type) {
+ public RouteTemplateBeanDefinition typeClass(Class<?> type) {
setType("#class:" + type.getName());
- return parent;
+ return this;
}
/**
- * Lookup in the registry for bean instances of the given type, and if
there is a single instance of the given type,
- * then that bean will be used as the local bean (danger this bean is
shared)
+ * Creates the bean from the given class type
*
- * @param type the type of the class to lookup in the registry
+ * @param type the type of the class to create as bean
*/
- public RouteTemplateDefinition beanType(Class<?> type) {
- setType("#type:" + type.getName());
- return parent;
+ public RouteTemplateBeanDefinition typeClass(String type) {
+ setType("#class:" + type);
+ return this;
+ }
+
+ /**
+ * To set the return type of the script (fully qualified class name).
+ *
+ * Knowing the type of the bean can be needed when dependency injection by
type is in use, or when looking in
+ * registry via class type.
+ *
+ * @param type the fully qualified type of the returned bean from the
script
+ */
+ public RouteTemplateBeanDefinition beanType(Class<?> type) {
+ setBeanType(type);
+ return this;
+ }
+
+ /**
+ * To set the return type of the script (fully qualified class name).
+ *
+ * Knowing the type of the bean can be needed when dependency injection by
type is in use, or when looking in
+ * registry via class type.
+ *
+ * @param type the fully qualified type of the returned bean from the
script
+ */
+ public RouteTemplateBeanDefinition beanType(String type) {
+ setBeanType(type);
+ return this;
}
/**
@@ -239,32 +324,6 @@ public class RouteTemplateBeanDefinition {
}
/**
- * What type to use for creating the bean. Can be one of:
#class,#type,bean,groovy,joor,language,mvel,ognl.
- *
- * #class or #type then the bean is created via the fully qualified
classname, such as #class:com.foo.MyBean
- *
- * The others are scripting languages that gives more power to create the
bean with an inlined code in the script
- * section, such as using groovy.
- */
- public RouteTemplateBeanDefinition type(String type) {
- if (!type.startsWith("#type:") && !type.startsWith("#class:")) {
- type = "#class:" + type;
- }
- setType(type);
- return this;
- }
-
- /**
- * Creates the bean from the given class type
- *
- * @param type the type of the class to create as bean
- */
- public RouteTemplateBeanDefinition type(Class<?> type) {
- beanClass(type);
- return this;
- }
-
- /**
* Calls a MvEL script for creating the local template bean
*
* If the script use the prefix <tt>resource:</tt> such as
<tt>resource:classpath:com/foo/myscript.groovy</tt>,
diff --git
a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java
index 26ae044..eeb96d7 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java
@@ -302,6 +302,27 @@ public class RouteTemplateDefinition extends
OptionalIdentifiedDefinition {
}
/**
+ * Adds a local bean the route template uses
+ *
+ * @param name the name of the bean
+ * @param type the type of the bean to associate the binding
+ * @param language the language to use
+ * @param script the script to use for creating the local bean
+ */
+ public RouteTemplateDefinition templateBean(String name, Class<?> type,
String language, String script) {
+ if (templateBeans == null) {
+ templateBeans = new ArrayList<>();
+ }
+ RouteTemplateBeanDefinition def = new RouteTemplateBeanDefinition();
+ def.setName(name);
+ def.setBeanType(type);
+ def.setType(language);
+ def.setScript(script);
+ templateBeans.add(def);
+ return this;
+ }
+
+ /**
* Adds a local bean the route template uses (via fluent builder)
*
* @param name the name of the bean
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 ef50ef3..0f9dbe5 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
@@ -554,7 +554,7 @@ public class RouteTemplateLocalBeanTest extends
ContextTestSupport {
@Override
public void configure() throws Exception {
routeTemplate("myTemplate").templateParameter("foo").templateParameter("bar")
-
.templateBean("myBar").beanClass(BuilderProcessor.class)
+
.templateBean("myBar").typeClass(BuilderProcessor.class).end()
.from("direct:{{foo}}")
.to("bean:{{bar}}");
}
@@ -593,7 +593,7 @@ public class RouteTemplateLocalBeanTest extends
ContextTestSupport {
@Override
public void configure() throws Exception {
routeTemplate("myTemplate").templateParameter("foo").templateParameter("bar").templateParameter("hi")
- .templateBean("myBar").property("prefix",
"{{hi}}").beanClass(BuilderThreeProcessor.class)
+ .templateBean("myBar").property("prefix",
"{{hi}}").typeClass(BuilderThreeProcessor.class).end()
.from("direct:{{foo}}")
.to("bean:{{bar}}");
}
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 7acb0c7..723e0d1 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
@@ -1024,6 +1024,7 @@ public class ModelParser extends BaseParser {
protected RouteTemplateBeanDefinition doParseRouteTemplateBeanDefinition()
throws IOException, XmlPullParserException {
return doParse(new RouteTemplateBeanDefinition(), (def, key, val) -> {
switch (key) {
+ case "beanType": def.setBeanType(val); break;
case "name": def.setName(val); break;
case "type": def.setType(val); break;
default: return false;
diff --git a/docs/user-manual/modules/ROOT/pages/route-template.adoc
b/docs/user-manual/modules/ROOT/pages/route-template.adoc
index cb8afef..4668ce3 100644
--- a/docs/user-manual/modules/ROOT/pages/route-template.adoc
+++ b/docs/user-manual/modules/ROOT/pages/route-template.adoc
@@ -247,7 +247,7 @@ routeTemplate("barTemplate")
.templateParameter("bar")
.templateParameter("street")
.templateBean("myBar")
- .type("com.foo.MyBar")
+ .typeClass("com.foo.MyBar")
.property("name", "{{bar}}")
.property("address", "{{street}}")
.end()
@@ -260,7 +260,7 @@ With Java DSL you can also refer to the bean class using
type safe way:
[source,java]
----
.templateBean("myBar")
- .type(MyBar.class)
+ .typeClass(MyBar.class)
.property("name", "{{bar}}")
.property("address", "{{street}}")
.end()
@@ -448,6 +448,44 @@ public static S3Client createS3Client(RouteTemplateContext
rtc) {
If you are using pure Java code (both template and creating local bean),
then you can create the local bean using Java lambda style as previously
documented.
+==== Configuring the type of the created bean
+
+When using scripting languages to create the local bean, then Camel would not
know what type (fully qualified class name)
+then created bean is. The type is therefore unassigned (is set as
`java.lang.Object`) which is a slight limitation.
+
+If you use dependency injection by type, or have the need for looking up the
local bean from the Camel `Registry` via its type,
+then you must provide this information in the route template with `beanType`
as shown:
+
+[source,xml]
+----
+<camelContext>
+ <routeTemplate id="s3template">
+ <templateParameter name="region"/>
+ <templateParameter name="bucket"/>
+ <templateBean name="myClient" type="bean"
beanType="software.amazon.awssdk.services.s3.S3Client">
+ <script>com.foo.MyAwsHelper?method=createS3Client</script>
+ </templateBean>
+ <route>
+ <from uri="direct:s3-store"/>
+ <to uri="aws2-s3:{{bucket}}?amazonS3Client=#{{myClient}}"/>
+ </route>
+ </routeTemplate>
+</camelContext>
+----
+
+And in Java DSL you can do:
+
+[source,java]
+----
+routeTemplate("s3template")
+ .templateParameter("region")
+ .templateParameter("bucket")
+ .templateBean("myClient", S3Client.class, "bean",
"com.foo.MyAwsHelper?method=createS3Client")
+ .from("direct:s3-store")
+ // must refer to the bean with {{myClient}}
+ .to("aws2-s3:{{bucket}}?amazonS3Client=#{{myClient}}")
+----
+
== Configuring route templates when creating route
There may be some special situations where you want to be able to do some
custom configuration/code when
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 4c30fdf..bf4bf0f 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
@@ -11785,6 +11785,7 @@ public final class ModelDeserializers extends
YamlDeserializerSupport {
order =
org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
nodes = "template-bean",
properties = {
+ @YamlProperty(name = "bean-type", type = "string"),
@YamlProperty(name = "name", type = "string", required =
true),
@YamlProperty(name = "property", type =
"array:org.apache.camel.model.PropertyDefinition"),
@YamlProperty(name = "script", type =
"object:org.apache.camel.model.RouteTemplateScriptDefinition"),
@@ -11810,6 +11811,11 @@ public final class ModelDeserializers extends
YamlDeserializerSupport {
protected boolean setProperty(RouteTemplateBeanDefinition target,
String propertyKey,
String propertyName, Node node) {
switch(propertyKey) {
+ case "bean-type": {
+ String val = asText(node);
+ target.setBeanType(val);
+ break;
+ }
case "name": {
String val = asText(node);
target.setName(val);
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json
index 58863262a..9b37036 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json
@@ -2065,6 +2065,9 @@
}, {
"type" : "object",
"properties" : {
+ "bean-type" : {
+ "type" : "string"
+ },
"name" : {
"type" : "string"
},
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 449e6e2..74f030a 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
@@ -110,6 +110,25 @@ class RouteTemplateTest extends YamlTestSupport {
- to: "direct:myId"
- to: "mock:result"
"""),
+ asResource('script-bean-type', """
+ - template:
+ id: "myTemplate"
+ beans:
+ - name: "myProcessor"
+ type: "groovy"
+ bean-type: "org.apache.camel.Processor"
+ script: "new
${MyUppercaseProcessor.class.name}()"
+ from:
+ uri: "direct:{{directName}}"
+ steps:
+ - process:
+ ref: "{{myProcessor}}"
+ - from:
+ uri: "direct:start"
+ steps:
+ - to: "direct:myId"
+ - to: "mock:result"
+ """),
asResource('script-block', """
- template:
id: "myTemplate"