This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch 13557 in repository https://gitbox.apache.org/repos/asf/camel.git
commit 8262f0c3316e21a2ccc5e31d740cd727477c7714 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Thu May 23 06:38:33 2019 +0200 CAMEL-13557: Add property binding support to make it convenient to configure components and whatnot. --- .../java/org/apache/camel/main/MainSupport.java | 2 + .../camel/support/PropertyBindingSupportTest.java | 37 +++++++++++-- .../camel/support/PropertyBindingSupport.java | 61 +++++++++++++++------- 3 files changed, 78 insertions(+), 22 deletions(-) diff --git a/core/camel-core/src/main/java/org/apache/camel/main/MainSupport.java b/core/camel-core/src/main/java/org/apache/camel/main/MainSupport.java index fedb2cd..4a249dc 100644 --- a/core/camel-core/src/main/java/org/apache/camel/main/MainSupport.java +++ b/core/camel-core/src/main/java/org/apache/camel/main/MainSupport.java @@ -1261,6 +1261,8 @@ public abstract class MainSupport extends ServiceSupport { IntrospectionSupport.getProperties(component, properties, null); // TODO: Use PropertyBindingSupport to make it support this kind of use-case too + // TODO: Allow nested properties too + // TODO: Allow fluent builders // lookup complex types properties.forEach((k, v) -> { diff --git a/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportTest.java b/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportTest.java index 86118be..3f28037 100644 --- a/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportTest.java @@ -16,12 +16,16 @@ */ package org.apache.camel.support; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + import org.apache.camel.CamelContext; import org.apache.camel.ContextTestSupport; import org.junit.Test; /** - * Unit test for PropertyBindingSupport with nested properties + * Unit test for PropertyBindingSupport */ public class PropertyBindingSupportTest extends ContextTestSupport { @@ -34,19 +38,46 @@ public class PropertyBindingSupportTest extends ContextTestSupport { work.setName("Acme"); context.getRegistry().bind("myWork", work); + Properties placeholders = new Properties(); + placeholders.put("companyName", "Acme"); + placeholders.put("committer", "rider"); + context.getPropertiesComponent().setInitialProperties(placeholders); + return context; } @Test + public void testProperties() throws Exception { + Foo foo = new Foo(); + + Map<String, Object> prop = new HashMap<>(); + prop.put("name", "James"); + prop.put("bar.age", "33"); + prop.put("bar.{{committer}}", "true"); + prop.put("bar.gold-customer", "true"); + prop.put("bar.work.id", "123"); + prop.put("bar.work.name", "{{companyName}}"); + + PropertyBindingSupport.bindProperties(context, foo, prop); + + assertEquals("James", foo.getName()); + assertEquals(33, foo.getBar().getAge()); + assertTrue(foo.getBar().isRider()); + assertTrue(foo.getBar().isGoldCustomer()); + assertEquals(123, foo.getBar().getWork().getId()); + assertEquals("Acme", foo.getBar().getWork().getName()); + } + + @Test public void testNested() throws Exception { Foo foo = new Foo(); PropertyBindingSupport.bindProperty(context, foo, "name", "James"); PropertyBindingSupport.bindProperty(context, foo, "bar.age", "33"); - PropertyBindingSupport.bindProperty(context, foo, "bar.rider", "true"); + PropertyBindingSupport.bindProperty(context, foo, "bar.{{committer}}", "true"); PropertyBindingSupport.bindProperty(context, foo, "bar.gold-customer", "true"); PropertyBindingSupport.bindProperty(context, foo, "bar.work.id", "123"); - PropertyBindingSupport.bindProperty(context, foo, "bar.work.name", "Acme"); + PropertyBindingSupport.bindProperty(context, foo, "bar.work.name", "{{companyName}}"); assertEquals("James", foo.getName()); assertEquals(33, foo.getBar().getAge()); diff --git a/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java b/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java index 66bb0b4..d9bfb03 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java @@ -21,6 +21,7 @@ import java.util.Map; import java.util.Set; import org.apache.camel.CamelContext; +import org.apache.camel.RuntimeCamelException; import static org.apache.camel.support.IntrospectionSupport.findSetterMethods; import static org.apache.camel.support.IntrospectionSupport.getOrElseProperty; @@ -29,6 +30,7 @@ import static org.apache.camel.support.IntrospectionSupport.getOrElseProperty; * A convenient support class for binding String valued properties to an instance which * uses a set of conventions: * <ul> + * <li>property placeholders - Keys and values using Camels property placeholder will be resolved</li> * <li>nested - Properties can be nested using the dot syntax (OGNL and builder pattern using with as prefix), eg foo.bar=123</li> * <li>reference by id - Values can refer to other beans in the registry by prefixing with # syntax, eg #myBean</li> * </ul> @@ -41,34 +43,52 @@ public final class PropertyBindingSupport { private PropertyBindingSupport() { } + /** + * Binds the properties to the target object. + * + * @param camelContext the camel context + * @param target the target object + * @param properties the properties + * @return true if one or more properties was bound, false otherwise + */ public static boolean bindProperties(CamelContext camelContext, Object target, Map<String, Object> properties) throws Exception { - boolean answer = true; + boolean answer = false; for (Map.Entry<String, Object> entry : properties.entrySet()) { - answer &= bindProperty(camelContext, target, entry.getKey(), entry.getValue()); + answer |= bindProperty(camelContext, target, entry.getKey(), entry.getValue()); } return answer; } - public static boolean bindProperty(CamelContext camelContext, Object target, String name, Object value) throws Exception { - return setProperty(camelContext, target, name, value, null, true, true); - } - /** - * This method supports two modes to set a property: - * - * 1. Setting a property that has already been resolved, this is the case when {@code context} and {@code refName} are - * NULL and {@code value} is non-NULL. + * Binds the property to the target object. * - * 2. Setting a property that has not yet been resolved, the property will be resolved based on the suitable methods - * found matching the property name on the {@code target} bean. For this mode to be triggered the parameters - * {@code context} and {@code refName} must NOT be NULL, and {@code value} MUST be NULL. + * @param camelContext the camel context + * @param target the target object + * @param name name of property + * @param value value of property + * @return true if property was bound, false otherwise */ - private static boolean setProperty(CamelContext context, Object target, String name, Object value, String refName, - boolean allowBuilderPattern, boolean allowNestedProperties) throws Exception { + public static boolean bindProperty(CamelContext camelContext, Object target, String name, Object value) throws Exception { + if (target != null && name != null) { + return setProperty(camelContext, target, name, value); + } else { + return false; + } + } + + private static boolean setProperty(CamelContext context, Object target, String name, Object value) { Class<?> clazz = target.getClass(); + String refName = null; + + // resolve property placeholders + name = context.resolvePropertyPlaceholders(name); + if (value instanceof String) { + // resolve property placeholders + value = context.resolvePropertyPlaceholders(value.toString()); + } // if name has dot then we need to OGNL walk it - if (allowNestedProperties && name.indexOf('.') > 0) { + if (name.indexOf('.') > 0) { String[] parts = name.split("\\."); Object newTarget = target; Class<?> newClass = clazz; @@ -78,7 +98,7 @@ public final class PropertyBindingSupport { Object prop = getOrElseProperty(newTarget, part, null); if (prop == null) { // okay is there a setter so we can create a new instance and set it automatic - Set<Method> newSetters = findSetterMethods(newClass, part, allowBuilderPattern); + Set<Method> newSetters = findSetterMethods(newClass, part, true); if (newSetters.size() == 1) { Method method = newSetters.iterator().next(); Class<?> parameterType = method.getParameterTypes()[0]; @@ -98,7 +118,6 @@ public final class PropertyBindingSupport { } // okay we found a nested property, then lets change to use that target = newTarget; - clazz = newTarget.getClass(); name = parts[parts.length - 1]; if (value instanceof String) { if (EndpointHelper.isReferenceParameter(value.toString())) { @@ -109,7 +128,11 @@ public final class PropertyBindingSupport { } } - return IntrospectionSupport.setProperty(context, context.getTypeConverter(), target, name, value, refName, allowBuilderPattern); + try { + return IntrospectionSupport.setProperty(context, context.getTypeConverter(), target, name, value, refName, true); + } catch (Exception e) { + throw RuntimeCamelException.wrapRuntimeException(e); + } } }