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 e37c4a4dcc04ee14e5bf0008dfc9973da92e4af8 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Wed Jun 26 09:25:09 2019 +0200 CAMEL-13681: Property binding support should have support for ignore case in property keys --- .../camel/support/IntrospectionSupportTest.java | 2 +- .../camel/support/PropertyBindingSupportTest.java | 51 +++++++ .../java/org/apache/camel/main/MainSupport.java | 19 ++- .../apache/camel/support/IntrospectionSupport.java | 96 +++++++++---- .../camel/support/PropertyBindingSupport.java | 153 ++++++++++++++------- 5 files changed, 239 insertions(+), 82 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 debe26b..6043a6c 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 @@ -552,7 +552,7 @@ public class IntrospectionSupportTest extends ContextTestSupport { @Test public void testFindSetterMethodsOrderedByParameterType() throws Exception { - List<Method> setters = IntrospectionSupport.findSetterMethodsOrderedByParameterType(MyOverloadedBean.class, "bean", false, false); + List<Method> setters = IntrospectionSupport.findSetterMethodsOrderedByParameterType(MyOverloadedBean.class, "bean", false, false, false); assertNotNull(setters); assertEquals(2, setters.size()); 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 fdc9c7a..588f3ec 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 @@ -68,6 +68,32 @@ public class PropertyBindingSupportTest extends ContextTestSupport { assertTrue(foo.getBar().isGoldCustomer()); assertEquals(123, foo.getBar().getWork().getId()); assertEquals("Acme", foo.getBar().getWork().getName()); + + assertTrue("Should bind all properties", prop.isEmpty()); + } + + @Test + public void testPropertiesIgnoreCase() 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, true); + + 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()); + + assertTrue("Should bind all properties", prop.isEmpty()); } @Test @@ -96,6 +122,31 @@ public class PropertyBindingSupportTest extends ContextTestSupport { } @Test + public void testBindPropertiesWithOptionPrefixIgnoreCase() throws Exception { + Foo foo = new Foo(); + + Map<String, Object> prop = new HashMap<>(); + prop.put("my.prefix.name", "James"); + prop.put("my.PREFIX.bar.AGE", "33"); + prop.put("my.prefix.bar.{{committer}}", "true"); + prop.put("My.prefix.bar.Gold-custoMER", "true"); + prop.put("mY.prefix.bar.work.ID", "123"); + prop.put("my.prEFIx.bar.Work.Name", "{{companyName}}"); + prop.put("my.other.prefix.something", "test"); + + PropertyBindingSupport.bindProperties(context, foo, prop, "my.prefix.", true); + + 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()); + assertTrue(prop.containsKey("my.other.prefix.something")); + assertEquals(1, prop.size()); + } + + @Test public void testNested() throws Exception { Foo foo = new Foo(); diff --git a/core/camel-main/src/main/java/org/apache/camel/main/MainSupport.java b/core/camel-main/src/main/java/org/apache/camel/main/MainSupport.java index 3f80690..c9e3ce1 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/MainSupport.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/MainSupport.java @@ -63,7 +63,6 @@ import org.slf4j.LoggerFactory; import static org.apache.camel.support.ObjectHelper.invokeMethod; import static org.apache.camel.util.ReflectionHelper.findMethod; -import static org.apache.camel.util.StringHelper.dashToCamelCase; import static org.apache.camel.util.StringHelper.matches; /** @@ -833,7 +832,7 @@ public abstract class MainSupport extends ServiceSupport { } if (!properties.isEmpty()) { LOG.info("Auto configuring CamelContext from loaded properties: {}", properties.size()); - setCamelProperties(camelContext, camelContext, properties, true); + setPropertiesOnTarget(camelContext, camelContext, properties, true, true); } if (!hystrixProperties.isEmpty()) { LOG.info("Auto configuring Hystrix EIP from loaded properties: {}", hystrixProperties.size()); @@ -843,7 +842,7 @@ public abstract class MainSupport extends ServiceSupport { hystrix = new HystrixConfigurationDefinition(); model.setHystrixConfiguration(hystrix); } - setCamelProperties(camelContext, hystrix, hystrixProperties, true); + setPropertiesOnTarget(camelContext, hystrix, hystrixProperties, true, true); } if (!restProperties.isEmpty()) { LOG.info("Auto configuring Rest DSL from loaded properties: {}", restProperties.size()); @@ -853,7 +852,7 @@ public abstract class MainSupport extends ServiceSupport { rest = new RestConfiguration(); model.setRestConfiguration(rest); } - setCamelProperties(camelContext, rest, restProperties, true); + setPropertiesOnTarget(camelContext, rest, restProperties, true, true); } } @@ -920,7 +919,7 @@ public abstract class MainSupport extends ServiceSupport { for (Object obj : properties.keySet()) { Map<String, Object> values = properties.get(obj); - setCamelProperties(camelContext, obj, values, true); + setPropertiesOnTarget(camelContext, obj, values, true, true); } } @@ -957,7 +956,7 @@ public abstract class MainSupport extends ServiceSupport { if (!properties.isEmpty()) { LOG.info("Auto configuring main from loaded properties: {}", properties.size()); - setCamelProperties(camelContext, config, properties, true); + setPropertiesOnTarget(camelContext, config, properties, true, true); } } @@ -1059,7 +1058,7 @@ public abstract class MainSupport extends ServiceSupport { for (Object obj : properties.keySet()) { Map<String, Object> values = properties.get(obj); - setCamelProperties(camelContext, obj, values, true); + setPropertiesOnTarget(camelContext, obj, values, true, true); } } @@ -1095,7 +1094,7 @@ public abstract class MainSupport extends ServiceSupport { setRouteBuilderClasses(existing); } - private static boolean setCamelProperties(CamelContext context, Object target, Map<String, Object> properties, boolean failIfNotSet) throws Exception { + private static boolean setPropertiesOnTarget(CamelContext context, Object target, Map<String, Object> properties, boolean failIfNotSet, boolean ignoreCase) throws Exception { ObjectHelper.notNull(context, "context"); ObjectHelper.notNull(target, "target"); ObjectHelper.notNull(properties, "properties"); @@ -1111,10 +1110,10 @@ public abstract class MainSupport extends ServiceSupport { LOG.debug("Setting property {} on {} with value {}", name, target, stringValue); if (failIfNotSet) { - PropertyBindingSupport.bindMandatoryProperty(context, target, name, stringValue); + PropertyBindingSupport.bindMandatoryProperty(context, target, name, stringValue, ignoreCase); rc = true; } else { - boolean hit = PropertyBindingSupport.bindProperty(context, target, name, stringValue); + boolean hit = PropertyBindingSupport.bindProperty(context, target, name, stringValue, ignoreCase); if (hit) { it.remove(); rc = true; 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 d2b325a..21c5d9a 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 @@ -365,30 +365,64 @@ public final class IntrospectionSupport { } } - public static Object getProperty(Object target, String property) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + public static Object getProperty(Object target, String propertyName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { ObjectHelper.notNull(target, "target"); - ObjectHelper.notNull(property, "property"); + ObjectHelper.notNull(propertyName, "property"); - property = property.substring(0, 1).toUpperCase(Locale.ENGLISH) + property.substring(1); + propertyName = propertyName.substring(0, 1).toUpperCase(Locale.ENGLISH) + propertyName.substring(1); Class<?> clazz = target.getClass(); - Method method = getPropertyGetter(clazz, property); + Method method = getPropertyGetter(clazz, propertyName); return method.invoke(target); } - public static Object getOrElseProperty(Object target, String property, Object defaultValue) { + public static Object getOrElseProperty(Object target, String propertyName, Object defaultValue) { + return getOrElseProperty(target, propertyName, defaultValue, false); + } + + public static Object getOrElseProperty(Object target, String propertyName, Object defaultValue, boolean ignoreCase) { try { - return getProperty(target, property); + if (ignoreCase) { + Class<?> clazz = target.getClass(); + Method method = getPropertyGetter(clazz, propertyName, true); + if (method != null) { + return method.invoke(target); + } else { + // not found so return default value + return defaultValue; + } + } else { + return getProperty(target, propertyName); + } } catch (Exception e) { return defaultValue; } } public static Method getPropertyGetter(Class<?> type, String propertyName) throws NoSuchMethodException { - if (isPropertyIsGetter(type, propertyName)) { - return type.getMethod("is" + StringHelper.capitalize(propertyName, true)); + return getPropertyGetter(type, propertyName, false); + } + + public static Method getPropertyGetter(Class<?> type, String propertyName, boolean ignoreCase) throws NoSuchMethodException { + if (ignoreCase) { + Method[] methods = type.getDeclaredMethods(); + for (Method m : methods) { + if (isGetter(m)) { + if (m.getName().startsWith("is") && m.getName().substring(2).equalsIgnoreCase(propertyName)) { + return m; + } else if (m.getName().startsWith("get") && m.getName().substring(3).equalsIgnoreCase(propertyName)) { + return m; + } + } + } + // not found + return null; } else { - return type.getMethod("get" + StringHelper.capitalize(propertyName, true)); + if (isPropertyIsGetter(type, propertyName)) { + return type.getMethod("is" + StringHelper.capitalize(propertyName, true)); + } else { + return type.getMethod("get" + StringHelper.capitalize(propertyName, true)); + } } } @@ -539,7 +573,7 @@ public final class IntrospectionSupport { */ public static boolean setProperty(CamelContext context, TypeConverter typeConverter, Object target, String name, Object value, String refName, boolean allowBuilderPattern) throws Exception { - return setProperty(context, typeConverter, target, name, value, refName, allowBuilderPattern, false); + return setProperty(context, typeConverter, target, name, value, refName, allowBuilderPattern, false, false); } /** @@ -555,7 +589,7 @@ public final class IntrospectionSupport { * {@code context} and {@code refName} must NOT be NULL, and {@code value} MUST be NULL. */ public static boolean setProperty(CamelContext context, TypeConverter typeConverter, Object target, String name, Object value, String refName, - boolean allowBuilderPattern, boolean allowPrivateSetter) throws Exception { + boolean allowBuilderPattern, boolean allowPrivateSetter, boolean ignoreCase) throws Exception { // does the property name include a lookup key, then we need to set the property as a map or list if (name.contains("[") && name.endsWith("]")) { @@ -563,10 +597,10 @@ public final class IntrospectionSupport { String lookupKey = name.substring(pos + 1, name.length() - 1); String key = name.substring(0, pos); - Object obj = IntrospectionSupport.getOrElseProperty(target, key, null); + Object obj = IntrospectionSupport.getOrElseProperty(target, key, null, ignoreCase); if (obj == null) { // it was supposed to be a list or map, but its null, so lets create a new list or map and set it automatically - Method getter = IntrospectionSupport.getPropertyGetter(target.getClass(), key); + Method getter = IntrospectionSupport.getPropertyGetter(target.getClass(), key, ignoreCase); if (getter != null) { // what type does it have Class<?> returnType = getter.getReturnType(); @@ -616,10 +650,10 @@ public final class IntrospectionSupport { // we need to lookup the value from the registry if (context != null && refName != null && value == null) { - setters = findSetterMethodsOrderedByParameterType(clazz, name, allowBuilderPattern, allowPrivateSetter); + setters = findSetterMethodsOrderedByParameterType(clazz, name, allowBuilderPattern, allowPrivateSetter, ignoreCase); } else { // find candidates of setter methods as there can be overloaded setters - setters = findSetterMethods(clazz, name, value, allowBuilderPattern, allowPrivateSetter); + setters = findSetterMethods(clazz, name, value, allowBuilderPattern, allowPrivateSetter, ignoreCase); } if (setters.isEmpty()) { return false; @@ -740,22 +774,22 @@ public final class IntrospectionSupport { public static boolean setProperty(CamelContext context, Object target, String name, Object value) throws Exception { // allow build pattern as a setter as well - return setProperty(context, context != null ? context.getTypeConverter() : null, target, name, value, null, true, false); + return setProperty(context, context != null ? context.getTypeConverter() : null, target, name, value, null, true, false, false); } public static boolean setProperty(CamelContext context, TypeConverter typeConverter, Object target, String name, Object value) throws Exception { // allow build pattern as a setter as well - return setProperty(context, typeConverter, target, name, value, null, true, false); + return setProperty(context, typeConverter, target, name, value, null, true, false, false); } public static boolean setProperty(TypeConverter typeConverter, Object target, String name, Object value) throws Exception { // allow build pattern as a setter as well - return setProperty(null, typeConverter, target, name, value, null, true, false); + return setProperty(null, typeConverter, target, name, value, null, true, false, false); } @Deprecated public static boolean setProperty(Object target, String name, Object value, boolean allowBuilderPattern) throws Exception { - return setProperty(null, null, target, name, value, null, allowBuilderPattern, false); + return setProperty(null, null, target, name, value, null, allowBuilderPattern, false, false); } @Deprecated @@ -764,7 +798,8 @@ public final class IntrospectionSupport { return setProperty(target, name, value, true); } - public static Set<Method> findSetterMethods(Class<?> clazz, String name, boolean allowBuilderPattern, boolean allowPrivateSetter) { + public static Set<Method> findSetterMethods(Class<?> clazz, String name, + boolean allowBuilderPattern, boolean allowPrivateSetter, boolean ignoreCase) { Set<Method> candidates = new LinkedHashSet<>(); // Build the method name @@ -778,7 +813,16 @@ public final class IntrospectionSupport { Method objectSetMethod = null; Method[] methods = allowPrivateSetter ? clazz.getDeclaredMethods() : clazz.getMethods(); for (Method method : methods) { - boolean validName = method.getName().equals(setName) || allowBuilderPattern && method.getName().equals(builderName) || allowBuilderPattern && method.getName().equals(builderName2); + boolean validName; + if (ignoreCase) { + validName = method.getName().equalsIgnoreCase(setName) + || allowBuilderPattern && method.getName().equalsIgnoreCase(builderName) + || allowBuilderPattern && method.getName().equalsIgnoreCase(builderName2); + } else { + validName = method.getName().equals(setName) + || allowBuilderPattern && method.getName().equals(builderName) + || allowBuilderPattern && method.getName().equals(builderName2); + } if (validName) { if (isSetter(method, allowBuilderPattern)) { Class<?>[] params = method.getParameterTypes(); @@ -798,8 +842,9 @@ public final class IntrospectionSupport { return candidates; } - static Set<Method> findSetterMethods(Class<?> clazz, String name, Object value, boolean allowBuilderPattern, boolean allowPrivateSetter) { - Set<Method> candidates = findSetterMethods(clazz, name, allowBuilderPattern, allowPrivateSetter); + static Set<Method> findSetterMethods(Class<?> clazz, String name, Object value, + boolean allowBuilderPattern, boolean allowPrivateSetter, boolean ignoreCase) { + Set<Method> candidates = findSetterMethods(clazz, name, allowBuilderPattern, allowPrivateSetter, ignoreCase); if (candidates.isEmpty()) { return candidates; @@ -824,10 +869,11 @@ public final class IntrospectionSupport { } } - static List<Method> findSetterMethodsOrderedByParameterType(Class<?> target, String propertyName, boolean allowBuilderPattern, boolean allowPrivateSetter) { + static List<Method> findSetterMethodsOrderedByParameterType(Class<?> target, String propertyName, + boolean allowBuilderPattern, boolean allowPrivateSetter, boolean ignoreCase) { List<Method> answer = new LinkedList<>(); List<Method> primitives = new LinkedList<>(); - Set<Method> setters = findSetterMethods(target, propertyName, allowBuilderPattern, allowPrivateSetter); + Set<Method> setters = findSetterMethods(target, propertyName, allowBuilderPattern, allowPrivateSetter, ignoreCase); for (Method setter : setters) { Class<?> parameterType = setter.getParameterTypes()[0]; if (PRIMITIVE_CLASSES.contains(parameterType)) { 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 40752a0..0d32d91 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.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -43,6 +44,7 @@ import static org.apache.camel.util.ObjectHelper.isNotEmpty; * <li>reference by type - Values can refer to singleton beans by their type in the registry by prefixing with #type: syntax, eg #type:com.foo.MyClassType</li> * <li>autowire by type - Values can refer to singleton beans by auto wiring by setting the value to #autowired</li> * <li>reference new class - Values can refer to creating new beans by their class name by prefixing with #class, eg #class:com.foo.MyClassType</li> + * <li>ignore case - Whether to ignore case for property keys<li> * </ul> * <p/> * This implementations reuses parts of {@link IntrospectionSupport}. @@ -60,6 +62,7 @@ public final class PropertyBindingSupport { private boolean placeholder = true; private boolean fluentBuilder = true; private boolean allowPrivateSetter = true; + private boolean ignoreCase = false; private String optionPrefix; /** @@ -107,8 +110,16 @@ public final class PropertyBindingSupport { * Whether properties should be filtered by prefix. * * Note that the prefix is removed from the key before the property is bound. */ - public Builder withOptionPrefix(String optionPrefix) { - this.optionPrefix = optionPrefix; + public Builder withAllowPrivateSetter(boolean allowPrivateSetter) { + this.allowPrivateSetter = allowPrivateSetter; + return this; + } + + /** + * Whether to ignore case in the property names (keys). + */ + public Builder withIgnoreCase(boolean ignoreCase) { + this.ignoreCase = ignoreCase; return this; } @@ -116,8 +127,8 @@ public final class PropertyBindingSupport { * Whether properties should be filtered by prefix. * * Note that the prefix is removed from the key before the property is bound. */ - public Builder withAllowPrivateSetter(boolean allowPrivateSetter) { - this.allowPrivateSetter = allowPrivateSetter; + public Builder withOptionPrefix(String optionPrefix) { + this.optionPrefix = optionPrefix; return this; } @@ -134,7 +145,8 @@ public final class PropertyBindingSupport { org.apache.camel.util.ObjectHelper.notNull(target, "target"); org.apache.camel.util.ObjectHelper.notNull(properties, "properties"); - return bindProperties(camelContext, target, properties, optionPrefix, nesting, deepNesting, fluentBuilder, allowPrivateSetter, reference, placeholder); + return bindProperties(camelContext, target, properties, optionPrefix, ignoreCase, nesting, deepNesting, + fluentBuilder, allowPrivateSetter, reference, placeholder); } } @@ -215,7 +227,7 @@ public final class PropertyBindingSupport { for (Map.Entry<String, Object> entry : properties.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); - Class<?> type = getGetterType(target, key); + Class<?> type = getGetterType(target, key, false); boolean skip = parents.contains(value) || value instanceof CamelContext; if (skip) { @@ -242,7 +254,7 @@ public final class PropertyBindingSupport { // attempt to create new instances to walk down the tree if its null (deepNesting option) if (value == null && deepNesting) { // okay is there a setter so we can create a new instance and set it automatic - Method method = findBestSetterMethod(target.getClass(), key, true, true); + Method method = findBestSetterMethod(target.getClass(), key, true, true, false); if (method != null) { Class<?> parameterType = method.getParameterTypes()[0]; if (parameterType != null && org.apache.camel.util.ObjectHelper.hasDefaultPublicNoArgConstructor(parameterType)) { @@ -283,6 +295,19 @@ public final class PropertyBindingSupport { } /** + * Binds the properties to the target object, and removes the property that was bound from properties. + * + * @param camelContext the camel context + * @param target the target object + * @param properties the properties where the bound properties will be removed from + * @param ignoreCase whether to ignore case for property keys + * @return true if one or more properties was bound + */ + public static boolean bindProperties(CamelContext camelContext, Object target, Map<String, Object> properties, boolean ignoreCase) { + return bindProperties(camelContext, target, properties, null, ignoreCase, true, true, true, true, true, true); + } + + /** * Binds the properties with the given prefix to the target object, and removes the property that was bound from properties. * Note that the prefix is removed from the key before the property is bound. * @@ -293,29 +318,22 @@ public final class PropertyBindingSupport { * @return true if one or more properties was bound */ public static boolean bindProperties(CamelContext camelContext, Object target, Map<String, Object> properties, String optionPrefix) { - return bindProperties(camelContext, target, properties, optionPrefix, true, true, true, true, true, true); + return bindProperties(camelContext, target, properties, optionPrefix, false); } /** * Binds the properties with the given prefix to the target object, and removes the property that was bound from properties. + * Note that the prefix is removed from the key before the property is bound. * - * @param camelContext the camel context - * @param target the target object - * @param properties the properties where the bound properties will be removed from - * @param nesting whether nesting is in use - * @param deepNesting whether deep nesting is in use, where Camel will attempt to walk as deep as possible by creating new objects in the OGNL graph if - * a property has a setter and the object can be created from a default no-arg constructor. - * @param fluentBuilder whether fluent builder is allowed as a valid getter/setter - * @param allowPrivateSetter whether autowiring components allows to use private setter method when setting the value - * @param reference whether reference parameter (syntax starts with #) is in use - * @param placeholder whether to use Camels property placeholder to resolve placeholders on keys and values - * @return true if one or more properties was bound + * @param camelContext the camel context + * @param target the target object + * @param properties the properties where the bound properties will be removed from + * @param optionPrefix the prefix used to filter properties + * @param ignoreCase whether to ignore case for property keys + * @return true if one or more properties was bound */ - public static boolean bindProperties(CamelContext camelContext, Object target, Map<String, Object> properties, - boolean nesting, boolean deepNesting, boolean fluentBuilder, boolean allowPrivateSetter, - boolean reference, boolean placeholder) { - - return bindProperties(camelContext, target, properties, null, nesting, deepNesting, fluentBuilder, allowPrivateSetter, reference, placeholder); + public static boolean bindProperties(CamelContext camelContext, Object target, Map<String, Object> properties, String optionPrefix, boolean ignoreCase) { + return bindProperties(camelContext, target, properties, optionPrefix, ignoreCase, true, true, true, true, true, true); } /** @@ -326,6 +344,7 @@ public final class PropertyBindingSupport { * @param target the target object * @param properties the properties where the bound properties will be removed from * @param optionPrefix the prefix used to filter properties + * @param ignoreCase whether to ignore case for property keys * @param nesting whether nesting is in use * @param deepNesting whether deep nesting is in use, where Camel will attempt to walk as deep as possible by creating new objects in the OGNL graph if * a property has a setter and the object can be created from a default no-arg constructor. @@ -336,7 +355,7 @@ public final class PropertyBindingSupport { * @return true if one or more properties was bound */ public static boolean bindProperties(CamelContext camelContext, Object target, Map<String, Object> properties, - String optionPrefix, + String optionPrefix, boolean ignoreCase, boolean nesting, boolean deepNesting, boolean fluentBuilder, boolean allowPrivateSetter, boolean reference, boolean placeholder) { org.apache.camel.util.ObjectHelper.notNull(camelContext, "camelContext"); @@ -347,19 +366,25 @@ public final class PropertyBindingSupport { // must set reference parameters first before the other bindings setReferenceProperties(camelContext, target, properties); + String uOptionPrefix = ""; + if (ignoreCase && isNotEmpty(optionPrefix)) { + uOptionPrefix = optionPrefix.toUpperCase(Locale.US); + } + for (Iterator<Map.Entry<String, Object>> iter = properties.entrySet().iterator(); iter.hasNext();) { Map.Entry<String, Object> entry = iter.next(); String key = entry.getKey(); Object value = entry.getValue(); if (isNotEmpty(optionPrefix)) { - if (!key.startsWith(optionPrefix)) { + boolean match = key.startsWith(optionPrefix) || ignoreCase && key.toUpperCase(Locale.US).startsWith(uOptionPrefix); + if (!match) { continue; } key = key.substring(optionPrefix.length()); } - if (bindProperty(camelContext, target, key, value, nesting, deepNesting, fluentBuilder, allowPrivateSetter, reference, placeholder)) { + if (bindProperty(camelContext, target, key, value, ignoreCase, nesting, deepNesting, fluentBuilder, allowPrivateSetter, reference, placeholder)) { iter.remove(); rc = true; } @@ -378,9 +403,23 @@ public final class PropertyBindingSupport { * @return true if property was bound, false otherwise */ public static boolean bindProperty(CamelContext camelContext, Object target, String name, Object value) { + return bindProperty(camelContext, target, name, value, false); + } + + /** + * Binds the property to the target object. + * + * @param camelContext the camel context + * @param target the target object + * @param name name of property + * @param value value of property + * @param ignoreCase whether to ignore case for property keys + * @return true if property was bound, false otherwise + */ + public static boolean bindProperty(CamelContext camelContext, Object target, String name, Object value, boolean ignoreCase) { try { if (target != null && name != null) { - return setProperty(camelContext, target, name, value, false, true, true, true, true, true, true); + return setProperty(camelContext, target, name, value, false, ignoreCase, true, true, true, true, true, true); } } catch (Exception e) { throw new PropertyBindingException(target, name, e); @@ -390,10 +429,11 @@ public final class PropertyBindingSupport { } private static boolean bindProperty(CamelContext camelContext, Object target, String name, Object value, - boolean nesting, boolean deepNesting, boolean fluentBuilder, boolean allowPrivateSetter, boolean reference, boolean placeholder) { + boolean ignoreCase, boolean nesting, boolean deepNesting, boolean fluentBuilder, + boolean allowPrivateSetter, boolean reference, boolean placeholder) { try { if (target != null && name != null) { - return setProperty(camelContext, target, name, value, false, nesting, deepNesting, fluentBuilder, allowPrivateSetter, reference, placeholder); + return setProperty(camelContext, target, name, value, false, ignoreCase, nesting, deepNesting, fluentBuilder, allowPrivateSetter, reference, placeholder); } } catch (Exception e) { throw new PropertyBindingException(target, name, e); @@ -411,9 +451,22 @@ public final class PropertyBindingSupport { * @param value value of property */ public static void bindMandatoryProperty(CamelContext camelContext, Object target, String name, Object value) { + bindMandatoryProperty(camelContext, target, name, value, false); + } + + /** + * Binds the mandatory property to the target object (will fail if not set/bound). + * + * @param camelContext the camel context + * @param target the target object + * @param name name of property + * @param value value of property + * @param ignoreCase whether to ignore case for property keys + */ + public static void bindMandatoryProperty(CamelContext camelContext, Object target, String name, Object value, boolean ignoreCase) { try { if (target != null && name != null) { - boolean bound = setProperty(camelContext, target, name, value, true, true, true, true, true, true, true); + boolean bound = setProperty(camelContext, target, name, value, true, ignoreCase, true, true, true, true, true, true); if (!bound) { throw new PropertyBindingException(target, name); } @@ -424,8 +477,8 @@ public final class PropertyBindingSupport { } private static boolean setProperty(CamelContext context, Object target, String name, Object value, boolean mandatory, - boolean nesting, boolean deepNesting, boolean fluentBuilder, boolean allowPrivateSetter, - boolean reference, boolean placeholder) throws Exception { + boolean ignoreCase, boolean nesting, boolean deepNesting, boolean fluentBuilder, + boolean allowPrivateSetter, boolean reference, boolean placeholder) throws Exception { String refName = null; if (placeholder) { @@ -448,14 +501,14 @@ public final class PropertyBindingSupport { // we should only iterate until until 2nd last so we use -1 in the for loop for (int i = 0; i < parts.length - 1; i++) { String part = parts[i]; - Object prop = getOrElseProperty(newTarget, part, null); + Object prop = getOrElseProperty(newTarget, part, null, ignoreCase); if (prop == null) { if (!deepNesting) { // okay we cannot go further down break; } // okay is there a setter so we can create a new instance and set it automatic - Method method = findBestSetterMethod(newClass, part, fluentBuilder, allowPrivateSetter); + Method method = findBestSetterMethod(newClass, part, fluentBuilder, allowPrivateSetter, ignoreCase); if (method != null) { Class<?> parameterType = method.getParameterTypes()[0]; Object instance = null; @@ -509,7 +562,7 @@ public final class PropertyBindingSupport { } } else if (value.toString().equals("#autowired")) { // we should get the type from the setter - Method method = findBestSetterMethod(target.getClass(), name, fluentBuilder, allowPrivateSetter); + Method method = findBestSetterMethod(target.getClass(), name, fluentBuilder, allowPrivateSetter, ignoreCase); if (method != null) { Class<?> parameterType = method.getParameterTypes()[0]; if (parameterType != null) { @@ -526,7 +579,7 @@ public final class PropertyBindingSupport { } } - boolean hit = IntrospectionSupport.setProperty(context, context.getTypeConverter(), target, name, value, refName, fluentBuilder, allowPrivateSetter); + boolean hit = IntrospectionSupport.setProperty(context, context.getTypeConverter(), target, name, value, refName, fluentBuilder, allowPrivateSetter, ignoreCase); if (!hit && mandatory) { // there is no setter with this given name, so lets report this as a problem throw new IllegalArgumentException("Cannot find setter method: " + name + " on bean: " + target + " when binding property: " + ognlPath); @@ -534,7 +587,7 @@ public final class PropertyBindingSupport { return hit; } - private static Object getOrElseProperty(Object target, String property, Object defaultValue) { + private static Object getOrElseProperty(Object target, String property, Object defaultValue, boolean ignoreCase) { String key = property; String lookupKey = null; @@ -545,7 +598,7 @@ public final class PropertyBindingSupport { key = property.substring(0, pos); } - Object answer = IntrospectionSupport.getOrElseProperty(target, key, defaultValue); + Object answer = IntrospectionSupport.getOrElseProperty(target, key, defaultValue, ignoreCase); if (answer instanceof Map && lookupKey != null) { Map map = (Map) answer; answer = map.getOrDefault(lookupKey, defaultValue); @@ -566,16 +619,17 @@ public final class PropertyBindingSupport { return answer != null ? answer : defaultValue; } - private static Method findBestSetterMethod(Class clazz, String name, boolean fluentBuilder, boolean allowPrivateSetter) { + private static Method findBestSetterMethod(Class clazz, String name, + boolean fluentBuilder, boolean allowPrivateSetter, boolean ignoreCase) { // is there a direct setter? - Set<Method> candidates = findSetterMethods(clazz, name, fluentBuilder, allowPrivateSetter); + Set<Method> candidates = findSetterMethods(clazz, name, false, allowPrivateSetter, ignoreCase); if (candidates.size() == 1) { return candidates.iterator().next(); } // okay now try with builder pattern if (fluentBuilder) { - candidates = findSetterMethods(clazz, name, fluentBuilder, allowPrivateSetter); + candidates = findSetterMethods(clazz, name, fluentBuilder, allowPrivateSetter, ignoreCase); if (candidates.size() == 1) { return candidates.iterator().next(); } @@ -584,11 +638,18 @@ public final class PropertyBindingSupport { return null; } - private static Class getGetterType(Object target, String name) { + private static Class getGetterType(Object target, String name, boolean ignoreCase) { try { - Method getter = IntrospectionSupport.getPropertyGetter(target.getClass(), name); - if (getter != null) { - return getter.getReturnType(); + if (ignoreCase) { + Method getter = IntrospectionSupport.getPropertyGetter(target.getClass(), name, true); + if (getter != null) { + return getter.getReturnType(); + } + } else { + Method getter = IntrospectionSupport.getPropertyGetter(target.getClass(), name); + if (getter != null) { + return getter.getReturnType(); + } } } catch (NoSuchMethodException e) { // ignore