Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CAMEL-19386: Support object property on template bean #10205

Merged
merged 1 commit into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
public class MyLocalBean {

private String prefix;
private String suffix;

public String getPrefix() {
return prefix;
Expand All @@ -28,7 +29,15 @@ public void setPrefix(String prefix) {
this.prefix = prefix;
}

public String getSuffix() {
return suffix;
}

public void setSuffix(String suffix) {
this.suffix = suffix;
}

public String hello(String body) {
return prefix + " " + body;
return prefix + " " + body + suffix;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@ public void testLocalBean() throws Exception {
parameters.put("foo", "one");
parameters.put("bar", "cheese");
parameters.put("greeting", "Davs");
parameters.put("suffix", "!!!");
context.addRouteFromTemplate("first", "myTemplate", parameters);

MockEndpoint mock = getMockEndpoint("mock:cheese");
mock.expectedBodiesReceived("Davs World");
mock.expectedBodiesReceived("Davs World!!!");

template.sendBody("direct:one", "World");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@
<templateParameter name="foo"/>
<templateParameter name="bar"/>
<templateParameter name="greeting"/>
<templateParameter name="suffix"/>
<templateBean name="myBean" type="#class:org.apache.camel.spring.routebuilder.MyLocalBean">

<property key="prefix" value="{{greeting}}"/>
<properties>
<property key="suffix" value="{{suffix}}"/>
</properties>
</templateBean>
<route>
<from uri="direct:{{foo}}"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,10 @@ private static void bind(BeanFactoryDefinition<?, ?> beanFactory, RouteTemplateC
throws Exception {
final Map<String, Object> props = new HashMap<>();
if (beanFactory.getProperties() != null) {
beanFactory.getProperties().forEach(p -> props.put(p.getKey(), p.getValue()));
props.putAll(beanFactory.getProperties());
}
if (beanFactory.getPropertyDefinitions() != null) {
beanFactory.getPropertyDefinitions().forEach(p -> props.put(p.getKey(), p.getValue()));
}
if (beanFactory.getBeanSupplier() != null) {
if (props.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"type": { "index": 1, "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 an inlined code in the script section, such as using groovy." },
"beanType": { "index": 2, "kind": "attribute", "displayName": "Bean Type", "label": "advanced", "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": { "index": 3, "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": { "index": 4, "kind": "element", "displayName": "Script", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The script to execute that creates the bean when using scripting languages. If the script use the prefix resource: such as resource:classpath:com\/foo\/myscript.groovy, resource:file:\/var\/myscript.groovy, then its loaded from the external resource." }
"properties": { "index": 4, "kind": "element", "displayName": "Properties", "required": false, "type": "object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", "deprecated": false, "autowired": false, "secret": false, "description": "Optional properties to set on the created local bean" },
"script": { "index": 5, "kind": "element", "displayName": "Script", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The script to execute that creates the bean when using scripting languages. If the script use the prefix resource: such as resource:classpath:com\/foo\/myscript.groovy, resource:file:\/var\/myscript.groovy, then its loaded from the external resource." }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"type": { "index": 1, "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 an inlined code in the script section, such as using groovy." },
"beanType": { "index": 2, "kind": "attribute", "displayName": "Bean Type", "label": "advanced", "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": { "index": 3, "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": { "index": 4, "kind": "element", "displayName": "Script", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The script to execute that creates the bean when using scripting languages. If the script use the prefix resource: such as resource:classpath:com\/foo\/myscript.groovy, resource:file:\/var\/myscript.groovy, then its loaded from the external resource." }
"properties": { "index": 4, "kind": "element", "displayName": "Properties", "required": false, "type": "object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", "deprecated": false, "autowired": false, "secret": false, "description": "Optional properties to set on the created local bean" },
"script": { "index": 5, "kind": "element", "displayName": "Script", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The script to execute that creates the bean when using scripting languages. If the script use the prefix resource: such as resource:classpath:com\/foo\/myscript.groovy, resource:file:\/var\/myscript.groovy, then its loaded from the external resource." }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/
package org.apache.camel.model;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

Expand All @@ -25,8 +25,10 @@
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlTransient;
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import org.apache.camel.RouteTemplateContext;
import org.apache.camel.model.app.BeanPropertiesAdapter;
import org.apache.camel.spi.Metadata;

/**
Expand Down Expand Up @@ -56,7 +58,10 @@ public abstract class BeanFactoryDefinition<
@Metadata(label = "advanced")
private String beanType;
@XmlElement(name = "property")
private List<PropertyDefinition> properties;
private List<PropertyDefinition> propertyDefinitions;
@XmlElement(name = "properties")
@XmlJavaTypeAdapter(BeanPropertiesAdapter.class)
private Map<String, Object> properties;
@XmlElement(name = "script")
@Metadata(label = "advanced")
private String script;
Expand Down Expand Up @@ -120,17 +125,35 @@ public Class<?> getBeanClass() {
return beanClass;
}

public List<PropertyDefinition> getProperties() {
public Map<String, Object> getProperties() {
return properties;
}

/**
* Optional properties to set on the created local bean
*/
public void setProperties(List<PropertyDefinition> properties) {
public void setProperties(Map<String, Object> properties) {
this.properties = properties;
}

public List<PropertyDefinition> getPropertyDefinitions() {
return propertyDefinitions;
}

/**
* Optional properties to set on the created local bean
*/
public void setPropertyDefinitions(List<PropertyDefinition> propertyDefinitions) {
this.propertyDefinitions = propertyDefinitions;
}

public void addProperty(PropertyDefinition property) {
if (propertyDefinitions == null) {
propertyDefinitions = new LinkedList<>();
}
propertyDefinitions.add(property);
}

public RouteTemplateContext.BeanSupplier<Object> getBeanSupplier() {
return beanSupplier;
}
Expand Down Expand Up @@ -354,22 +377,19 @@ public P ognl(String script) {
*/
@SuppressWarnings("unchecked")
public T property(String key, String value) {
if (properties == null) {
properties = new ArrayList<>();
if (propertyDefinitions == null) {
propertyDefinitions = new LinkedList<>();
}
properties.add(new PropertyDefinition(key, value));
propertyDefinitions.add(new PropertyDefinition(key, value));
return (T) this;
}

/**
* Sets properties to set on the created local bean
*/
@SuppressWarnings("unchecked")
public T properties(Map<String, String> properties) {
if (this.properties == null) {
this.properties = new ArrayList<>();
}
properties.forEach((k, v) -> this.properties.add(new PropertyDefinition(k, v)));
public T properties(Map<String, Object> properties) {
this.properties = properties;
return (T) this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public class BeanPropertiesAdapter extends XmlAdapter<BeanPropertiesDefinition,

@Override
public Map<String, Object> unmarshal(BeanPropertiesDefinition v) {
if (v == null) {
return null;
}
Map<String, Object> result = new LinkedHashMap<>();
for (BeanPropertyDefinition pd : v.getProperties()) {
if (pd.getProperties() != null) {
Expand All @@ -41,6 +44,9 @@ public Map<String, Object> unmarshal(BeanPropertiesDefinition v) {
@Override
@SuppressWarnings("unchecked")
public BeanPropertiesDefinition marshal(Map<String, Object> v) {
if (v == null) {
return null;
}
final BeanPropertyDefinition[] result = new BeanPropertyDefinition[v.size()];
int pos = 0;
for (Map.Entry<String, Object> entry : v.entrySet()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1114,13 +1114,24 @@ protected <T extends BeanFactoryDefinition> AttributeHandler<T> beanFactoryDefin
protected <T extends BeanFactoryDefinition> ElementHandler<T> beanFactoryDefinitionElementHandler() {
return (def, key) -> {
switch (key) {
case "property": doAdd(doParsePropertyDefinition(), def.getProperties(), def::setProperties); break;
case "properties": def.setProperties(new BeanPropertiesAdapter().unmarshal(doParseBeanPropertiesDefinition())); break;
case "property": doAdd(doParsePropertyDefinition(), def.getPropertyDefinitions(), def::setPropertyDefinitions); break;
case "script": def.setScript(doParseText()); break;
default: return false;
}
return true;
};
}
protected BeanPropertiesDefinition doParseBeanPropertiesDefinition() throws IOException, XmlPullParserException {
return doParse(new BeanPropertiesDefinition(),
noAttributeHandler(), (def, key) -> {
if ("property".equals(key)) {
doAdd(doParseBeanPropertyDefinition(), def.getProperties(), def::setProperties);
return true;
}
return false;
}, noValueHandler());
}
protected RouteTemplateContextRefDefinition doParseRouteTemplateContextRefDefinition() throws IOException, XmlPullParserException {
return doParse(new RouteTemplateContextRefDefinition(), (def, key, val) -> {
if ("ref".equals(key)) {
Expand Down Expand Up @@ -1630,16 +1641,6 @@ protected RegistryBeanDefinition doParseRegistryBeanDefinition() throws IOExcept
return false;
}, noValueHandler());
}
protected BeanPropertiesDefinition doParseBeanPropertiesDefinition() throws IOException, XmlPullParserException {
return doParse(new BeanPropertiesDefinition(),
noAttributeHandler(), (def, key) -> {
if ("property".equals(key)) {
doAdd(doParseBeanPropertyDefinition(), def.getProperties(), def::setProperties);
return true;
}
return false;
}, noValueHandler());
}
protected BeanPropertyDefinition doParseBeanPropertyDefinition() throws IOException, XmlPullParserException {
return doParse(new BeanPropertyDefinition(), (def, key, val) -> {
switch (key) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1075,8 +1075,9 @@ protected void doWriteBeanFactoryDefinitionAttributes(
protected void doWriteBeanFactoryDefinitionElements(
BeanFactoryDefinition<?, ?> def)
throws IOException {
doWriteList(null, "property", def.getPropertyDefinitions(), this::doWritePropertyDefinition);
doWriteElement("script", def.getScript(), this::doWriteString);
doWriteList(null, "property", def.getProperties(), this::doWritePropertyDefinition);
doWriteElement("properties", new BeanPropertiesAdapter().marshal(def.getProperties()), this::doWriteBeanPropertiesDefinition);
}
protected void doWriteBeanFactoryDefinition(
String name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
*/
package org.apache.camel.dsl.yaml.deserializers;

import java.util.stream.Collectors;

import org.apache.camel.dsl.yaml.common.YamlDeserializerBase;
import org.apache.camel.model.BeanFactoryDefinition;
import org.apache.camel.model.PropertyDefinition;
Expand Down Expand Up @@ -52,14 +50,11 @@ protected boolean setProperty(
case "property": {
java.util.List<PropertyDefinition> val
= asFlatList(node, PropertyDefinition.class);
target.setProperties(val);
target.setPropertyDefinitions(val);
break;
}
case "properties": {
target.setProperties(
asMap(node).entrySet().stream()
.map(e -> new PropertyDefinition(e.getKey(), (String) e.getValue()))
.collect(Collectors.toList()));
target.setProperties(asMap(node));
break;
}
case "script": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
@YamlProperty(name = "parameters",
type = "array:org.apache.camel.model.RouteTemplateParameterDefinition"),
@YamlProperty(name = "beans",
type = "array:org.apache.camel.model.app.RegistryBeanDefinition")
type = "array:org.apache.camel.model.RouteTemplateBeanDefinition")
})
public class RouteTemplateDefinitionDeserializer extends YamlDeserializerBase<RouteTemplateDefinition> {
public RouteTemplateDefinitionDeserializer() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
@YamlProperty(name = "parameters",
type = "array:org.apache.camel.model.TemplatedRouteParameterDefinition"),
@YamlProperty(name = "beans",
type = "array:org.apache.camel.model.app.RegistryBeanDefinition")
type = "array:org.apache.camel.model.TemplatedRouteBeanDefinition")
})
public class TemplatedRouteDefinitionDeserializer extends YamlDeserializerBase<TemplatedRouteDefinition> {
public TemplatedRouteDefinitionDeserializer() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2553,7 +2553,7 @@
"beans" : {
"type" : "array",
"items" : {
"$ref" : "#/items/definitions/org.apache.camel.model.app.RegistryBeanDefinition"
"$ref" : "#/items/definitions/org.apache.camel.model.RouteTemplateBeanDefinition"
}
},
"from" : {
Expand Down Expand Up @@ -3022,7 +3022,7 @@
"beans" : {
"type" : "array",
"items" : {
"$ref" : "#/items/definitions/org.apache.camel.model.app.RegistryBeanDefinition"
"$ref" : "#/items/definitions/org.apache.camel.model.TemplatedRouteBeanDefinition"
}
},
"parameters" : {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2463,7 +2463,7 @@
"beans" : {
"type" : "array",
"items" : {
"$ref" : "#/items/definitions/org.apache.camel.model.app.RegistryBeanDefinition"
"$ref" : "#/items/definitions/org.apache.camel.model.RouteTemplateBeanDefinition"
}
},
"from" : {
Expand Down Expand Up @@ -2932,7 +2932,7 @@
"beans" : {
"type" : "array",
"items" : {
"$ref" : "#/items/definitions/org.apache.camel.model.app.RegistryBeanDefinition"
"$ref" : "#/items/definitions/org.apache.camel.model.TemplatedRouteBeanDefinition"
}
},
"parameters" : {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,18 @@ class KameletLoaderTest extends YamlTestSupport {
x-descriptors:
- 'urn:alm:descriptor:com.tectonic.ui:checkbox'
template:
beans:
- name: kameletBean
type: org.apache.camel.dsl.yaml.KameletBean
property:
- key: kbProp
value: kbValue
- name: kameletBean2
type: org.apache.camel.dsl.yaml.KameletBean
properties:
kbProp2: kbValue2
kbObjProp:
kbObjPropProp: kbObjPropPropVal
from:
uri: "kamelet:source"
steps:
Expand Down Expand Up @@ -93,11 +105,11 @@ class KameletLoaderTest extends YamlTestSupport {

with(route) {
input.endpointUri == 'kamelet:source'
input.lineNumber == 35
input.lineNumber == 47
outputs.size() == 1
with (outputs[0], ToDefinition) {
endpointUri ==~ /aws2-s3:.*/
lineNumber == 38
lineNumber == 50
}
}
}
Expand Down