You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2019/05/24 10:12:44 UTC

[camel] 04/27: CAMEL-13557: Add property binding support to make it convenient to configure components and whatnot.

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 21f7433b2a3b89ffa65dad9bc66d818d4c89176c
Author: Claus Ibsen <cl...@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);
     }
 
 }