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 4e0be8d0a142fecc63994868c9c147fe68e92e1e Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Thu May 23 06:03:42 2019 +0200 CAMEL-13557: Add property binding support to make it convenient to configure components and whatnot. --- .../camel/support/IntrospectionSupportTest.java | 90 +++++++++++++++++++++- .../camel/support/PropertyBindingSupportTest.java | 13 ++++ .../apache/camel/support/IntrospectionSupport.java | 21 +++-- .../camel/support/PropertyBindingSupport.java | 21 ++--- 4 files changed, 122 insertions(+), 23 deletions(-) diff --git a/core/camel-core/src/test/java/org/apache/camel/support/IntrospectionSupportTest.java b/core/camel-core/src/test/java/org/apache/camel/support/IntrospectionSupportTest.java index b2b87f5..874fe41 100644 --- a/core/camel-core/src/test/java/org/apache/camel/support/IntrospectionSupportTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/support/IntrospectionSupportTest.java @@ -134,7 +134,95 @@ public class IntrospectionSupportTest extends ContextTestSupport { return this; } } - + + @Test + public void testBuilderPatternWith() throws Exception { + MyBuilderPatternWithBean builderBean = new MyBuilderPatternWithBean(); + IntrospectionSupport.setProperty(context.getTypeConverter(), builderBean, "name", "Donald"); + IntrospectionSupport.setProperty(context.getTypeConverter(), builderBean, "age", "33"); + IntrospectionSupport.setProperty(context.getTypeConverter(), builderBean, "gold-customer", "true"); + assertEquals("Donald", builderBean.getName()); + assertEquals(33, builderBean.getAge()); + assertTrue(builderBean.isGoldCustomer()); + } + + public class MyBuilderPatternWithBean { + private String name; + private int age; + private boolean goldCustomer; + + public MyBuilderPatternWithBean withName(String name) { + this.name = name; + return this; + } + + public MyBuilderPatternWithBean withAge(int age) { + this.age = age; + return this; + } + + public MyBuilderPatternWithBean withGoldCustomer(boolean goldCustomer) { + this.goldCustomer = goldCustomer; + return this; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + + public boolean isGoldCustomer() { + return goldCustomer; + } + } + + @Test + public void testBuilderPattern() throws Exception { + MyBuilderPatternBean builderBean = new MyBuilderPatternBean(); + IntrospectionSupport.setProperty(context.getTypeConverter(), builderBean, "name", "Goofy"); + IntrospectionSupport.setProperty(context.getTypeConverter(), builderBean, "age", "34"); + IntrospectionSupport.setProperty(context.getTypeConverter(), builderBean, "gold-customer", "true"); + assertEquals("Goofy", builderBean.getName()); + assertEquals(34, builderBean.getAge()); + assertTrue(builderBean.isGoldCustomer()); + } + + public class MyBuilderPatternBean { + private String name; + private int age; + private boolean goldCustomer; + + public MyBuilderPatternBean name(String name) { + this.name = name; + return this; + } + + public MyBuilderPatternBean age(int age) { + this.age = age; + return this; + } + + public MyBuilderPatternBean goldCustomer(boolean goldCustomer) { + this.goldCustomer = goldCustomer; + return this; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + + public boolean isGoldCustomer() { + return goldCustomer; + } + } + @Test public void testIsSetterBuilderPatternSupport() throws Exception { Method setter = MyBuilderBean.class.getMethod("setName", String.class); 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 c55745f..86118be 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 @@ -44,12 +44,14 @@ public class PropertyBindingSupportTest extends ContextTestSupport { 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.gold-customer", "true"); PropertyBindingSupport.bindProperty(context, foo, "bar.work.id", "123"); PropertyBindingSupport.bindProperty(context, foo, "bar.work.name", "Acme"); 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()); } @@ -60,12 +62,14 @@ public class PropertyBindingSupportTest extends ContextTestSupport { PropertyBindingSupport.bindProperty(context, foo, "name", "James"); PropertyBindingSupport.bindProperty(context, foo, "bar.age", "33"); + PropertyBindingSupport.bindProperty(context, foo, "bar.gold-customer", "true"); PropertyBindingSupport.bindProperty(context, foo, "bar.rider", "true"); PropertyBindingSupport.bindProperty(context, foo, "bar.work", "#myWork"); assertEquals("James", foo.getName()); assertEquals(33, foo.getBar().getAge()); assertTrue(foo.getBar().isRider()); + assertTrue(foo.getBar().isGoldCustomer()); assertEquals(456, foo.getBar().getWork().getId()); assertEquals("Acme", foo.getBar().getWork().getName()); } @@ -95,6 +99,7 @@ public class PropertyBindingSupportTest extends ContextTestSupport { private int age; private boolean rider; private Company work; // has no default value but Camel can automatic create one if there is a setter + private boolean goldCustomer; public int getAge() { return age; @@ -119,6 +124,14 @@ public class PropertyBindingSupportTest extends ContextTestSupport { public void setWork(Company work) { this.work = work; } + + public boolean isGoldCustomer() { + return goldCustomer; + } + + public void setGoldCustomer(boolean goldCustomer) { + this.goldCustomer = goldCustomer; + } } public static class Company { diff --git a/core/camel-support/src/main/java/org/apache/camel/support/IntrospectionSupport.java b/core/camel-support/src/main/java/org/apache/camel/support/IntrospectionSupport.java index 02d2f47..8e4ea5f 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/IntrospectionSupport.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/IntrospectionSupport.java @@ -195,9 +195,14 @@ public final class IntrospectionSupport { Class<?> type = method.getReturnType(); int parameterCount = method.getParameterCount(); - // is it a getXXX method - if (name.startsWith("set") && name.length() >= 4 && Character.isUpperCase(name.charAt(3))) { - return parameterCount == 1 && (type.equals(Void.TYPE) || (allowBuilderPattern && method.getDeclaringClass().isAssignableFrom(type))); + // is it a setXXX method + boolean validName = name.startsWith("set") && name.length() >= 4 && Character.isUpperCase(name.charAt(3)); + if (validName) { + return parameterCount == 1 && type.equals(Void.TYPE); + } + // or if its a builder method + if (allowBuilderPattern && parameterCount == 1 && method.getDeclaringClass().isAssignableFrom(type)) { + return true; } return false; @@ -680,15 +685,19 @@ public final class IntrospectionSupport { public static Set<Method> findSetterMethods(Class<?> clazz, String name, boolean allowBuilderPattern) { Set<Method> candidates = new LinkedHashSet<>(); - // Build the method name. - name = "set" + StringHelper.capitalize(name, true); + // Build the method name + String builderName = "with" + StringHelper.capitalize(name, true); + String builderName2 = StringHelper.capitalize(name, true); + builderName2 = Character.toLowerCase(builderName2.charAt(0)) + builderName2.substring(1); + String setName = "set" + StringHelper.capitalize(name, true); while (clazz != Object.class) { // Since Object.class.isInstance all the objects, // here we just make sure it will be add to the bottom of the set. Method objectSetMethod = null; Method[] methods = clazz.getMethods(); for (Method method : methods) { - if (method.getName().equals(name) && isSetter(method, allowBuilderPattern)) { + boolean validName = method.getName().equals(setName) || allowBuilderPattern && method.getName().equals(builderName) || allowBuilderPattern && method.getName().equals(builderName2); + if (validName && isSetter(method, allowBuilderPattern)) { Class<?>[] params = method.getParameterTypes(); if (params[0].equals(Object.class)) { objectSetMethod = method; 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 85a98a1..66bb0b4 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 @@ -17,15 +17,10 @@ package org.apache.camel.support; import java.lang.reflect.Method; -import java.util.Collection; import java.util.Map; import java.util.Set; -import java.util.regex.Pattern; import org.apache.camel.CamelContext; -import org.apache.camel.TypeConverter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import static org.apache.camel.support.IntrospectionSupport.findSetterMethods; import static org.apache.camel.support.IntrospectionSupport.getOrElseProperty; @@ -34,7 +29,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>nested - Properties can be nested using the dot syntax (OGNL), eg foo.bar=123</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> * This implementations reuses parts of {@link IntrospectionSupport}. @@ -42,10 +37,6 @@ import static org.apache.camel.support.IntrospectionSupport.getOrElseProperty; public final class PropertyBindingSupport { // TODO: Add support for auto binding to singleton instance by type from registry (boolean on|off) - // TODO: builder pattern with naming prefix: withXXX - - private static final Pattern SECRETS = Pattern.compile(".*(passphrase|password|secretKey).*", Pattern.CASE_INSENSITIVE); - private static final Logger LOG = LoggerFactory.getLogger(PropertyBindingSupport.class); private PropertyBindingSupport() { } @@ -59,7 +50,7 @@ public final class PropertyBindingSupport { } public static boolean bindProperty(CamelContext camelContext, Object target, String name, Object value) throws Exception { - return setProperty(camelContext, camelContext.getTypeConverter(), target, name, value, null, true, true); + return setProperty(camelContext, target, name, value, null, true, true); } /** @@ -72,10 +63,9 @@ public final class PropertyBindingSupport { * 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. */ - private static boolean setProperty(CamelContext context, TypeConverter typeConverter, Object target, String name, Object value, String refName, + private static boolean setProperty(CamelContext context, Object target, String name, Object value, String refName, boolean allowBuilderPattern, boolean allowNestedProperties) throws Exception { Class<?> clazz = target.getClass(); - Collection<Method> setters; // if name has dot then we need to OGNL walk it if (allowNestedProperties && name.indexOf('.') > 0) { @@ -88,7 +78,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, true); + Set<Method> newSetters = findSetterMethods(newClass, part, allowBuilderPattern); if (newSetters.size() == 1) { Method method = newSetters.iterator().next(); Class<?> parameterType = method.getParameterTypes()[0]; @@ -119,8 +109,7 @@ public final class PropertyBindingSupport { } } - // TODO: At this point we can likely just call IntrospectionSupport directly - return IntrospectionSupport.setProperty(context, context.getTypeConverter(), target, name, value, refName, true); + return IntrospectionSupport.setProperty(context, context.getTypeConverter(), target, name, value, refName, allowBuilderPattern); } }