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 2020/08/23 13:56:40 UTC
[camel] 01/03: CAMEL-15452: PropertyBindingSupport - Add reflection
on|off option
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 86222649961f03b5d1d242ed8ef4cd46ad9163da
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Aug 23 15:33:39 2020 +0200
CAMEL-15452: PropertyBindingSupport - Add reflection on|off option
---
.../PropertyBindingSupportConfigurerTest.java | 35 ++++++++++-
.../camel/support/PropertyBindingSupportTest.java | 24 ++++++--
.../camel/support/PropertyBindingSupport.java | 68 +++++++++++++---------
3 files changed, 95 insertions(+), 32 deletions(-)
diff --git a/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportConfigurerTest.java b/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportConfigurerTest.java
index f6f44b4..b2b2332 100644
--- a/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportConfigurerTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportConfigurerTest.java
@@ -172,7 +172,7 @@ public class PropertyBindingSupportConfigurerTest extends ContextTestSupport {
}
@Test
- public void testPropertiesOptionallKeyMandatory() throws Exception {
+ public void testPropertiesOptionalKeyMandatory() throws Exception {
Bar bar = new Bar();
Map<String, Object> prop = new HashMap<>();
@@ -220,6 +220,39 @@ public class PropertyBindingSupportConfigurerTest extends ContextTestSupport {
}
@Test
+ public void testPropertiesNoReflection() throws Exception {
+ BeanIntrospection bi = context.adapt(ExtendedCamelContext.class).getBeanIntrospection();
+ bi.setExtendedStatistics(true);
+ bi.setLoggingLevel(LoggingLevel.WARN);
+
+ Bar bar = new Bar();
+
+ Map<String, Object> prop = new HashMap<>();
+ prop.put("age", "33");
+ prop.put("{{committer}}", "true");
+ prop.put("gold-customer", "true");
+ prop.put("work.id", "123");
+ prop.put("work.name", "{{companyName}}");
+
+ myConfigurer.reset();
+ PropertyBindingSupport.build().withReflection(false).withConfigurer(myConfigurer).withIgnoreCase(true).bind(context, bar, prop);
+ assertEquals(6, myConfigurer.getCounter());
+
+ assertEquals(33, bar.getAge());
+ assertTrue(bar.isRider());
+ assertTrue(bar.isGoldCustomer());
+ assertEquals(0, bar.getWork().getId());
+ assertNull(bar.getWork().getName());
+
+ assertEquals(2, prop.size());
+ assertEquals("123", prop.get("work.id"));
+ assertEquals("{{companyName}}", prop.get("work.name"));
+
+ // reflection is turned off
+ assertEquals(0, bi.getInvokedCounter());
+ }
+
+ @Test
public void testConfigurerShouldNotFailForAnonymousClasses() throws Exception {
PropertyBindingSupport.autowireSingletonPropertiesFromRegistry(context, new Bar() {
@Override
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 371eccf..39c512c 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
@@ -27,11 +27,8 @@ import org.apache.camel.spi.Injector;
import org.apache.camel.spi.PropertiesComponent;
import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertSame;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
+
+import static org.junit.jupiter.api.Assertions.*;
/**
* Unit test for PropertyBindingSupport
@@ -141,6 +138,23 @@ public class PropertyBindingSupportTest extends ContextTestSupport {
}
@Test
+ public void testPropertiesNoReflection() throws Exception {
+ Foo foo = new Foo();
+
+ Map<String, Object> prop = new HashMap<>();
+ prop.put("name", "James");
+ prop.put("bar.AGE", "33");
+
+ PropertyBindingSupport.build().withReflection(false).bind(context, foo, prop);
+
+ assertNull(foo.getName());
+ assertEquals(0, foo.getBar().getAge());
+
+ // should not bind any properties as reflection is off
+ assertEquals(2, prop.size());
+ }
+
+ @Test
public void testPropertiesIgnoreCase() throws Exception {
Foo foo = new Foo();
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 37306e2..b08f65b 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
@@ -104,6 +104,7 @@ public final class PropertyBindingSupport {
private boolean allowPrivateSetter = true;
private boolean ignoreCase;
private String optionPrefix;
+ private boolean reflection = true;
private PropertyConfigurer configurer;
/**
@@ -240,6 +241,14 @@ public final class PropertyBindingSupport {
}
/**
+ * Whether to allow using reflection (when there is no configurer available).
+ */
+ public Builder withReflection(boolean reflection) {
+ this.reflection = reflection;
+ return this;
+ }
+
+ /**
* Binds the properties to the target object, and removes the property that was bound from properties.
*
* @return true if one or more properties was bound
@@ -255,7 +264,7 @@ public final class PropertyBindingSupport {
return doBindProperties(camelContext, target, removeParameters ? properties : new HashMap<>(properties),
optionPrefix, ignoreCase, true, mandatory,
- nesting, deepNesting, fluentBuilder, allowPrivateSetter, reference, placeholder, configurer);
+ nesting, deepNesting, fluentBuilder, allowPrivateSetter, reference, placeholder, reflection, configurer);
}
/**
@@ -273,7 +282,7 @@ public final class PropertyBindingSupport {
return doBindProperties(context, obj, removeParameters ? prop : new HashMap<>(prop),
optionPrefix, ignoreCase, true, mandatory,
- nesting, deepNesting, fluentBuilder, allowPrivateSetter, reference, placeholder, configurer);
+ nesting, deepNesting, fluentBuilder, allowPrivateSetter, reference, placeholder, reflection, configurer);
}
/**
@@ -290,7 +299,7 @@ public final class PropertyBindingSupport {
properties.put(key, value);
return doBindProperties(camelContext, target, properties, optionPrefix, ignoreCase, true, mandatory,
- nesting, deepNesting, fluentBuilder, allowPrivateSetter, reference, placeholder, configurer);
+ nesting, deepNesting, fluentBuilder, allowPrivateSetter, reference, placeholder, reflection, configurer);
}
}
@@ -621,7 +630,8 @@ public final class PropertyBindingSupport {
* 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
- * @param configurer to use an optional {@link org.apache.camel.spi.PropertyConfigurer} to configure the
+ * @param reflection whether to allow using reflection (when there is no configurer available).
+ * @param configurer to use an optional {@link PropertyConfigurer} to configure the
* properties
* @return true if one or more properties was bound
*/
@@ -630,7 +640,7 @@ public final class PropertyBindingSupport {
String optionPrefix, boolean ignoreCase, boolean removeParameter, boolean mandatory,
boolean nesting, boolean deepNesting, boolean fluentBuilder, boolean allowPrivateSetter,
boolean reference, boolean placeholder,
- PropertyConfigurer configurer) {
+ boolean reflection, PropertyConfigurer configurer) {
if (properties == null || properties.isEmpty()) {
return false;
@@ -642,24 +652,30 @@ public final class PropertyBindingSupport {
properties = new OptionPrefixMap(properties, optionPrefix);
}
- // need to process them in specific order so use a sorted map
- // and use our comparator
- SortedMap<String, Object> sorted = new TreeMap<>(new PropertyBindingKeyComparator(properties));
- sorted.putAll(properties);
+ Map<String, Object> sorted;
+ if (properties.size() > 1) {
+ // need to process them in specific order so use a sorted map
+ // and use our comparator
+ sorted = new TreeMap<>(new PropertyBindingKeyComparator(properties));
+ sorted.putAll(properties);
+ } else {
+ // no need to sort as there is only 1 element
+ sorted = properties;
+ }
// process each property and bind it
for (Map.Entry<String, Object> entry : sorted.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
- // if nesting is not allowed, then only bind properties without dots (ONGL graph)
+ // if nesting is not allowed, then only bind properties without dots (OGNL graph)
if (!nesting && key.indexOf('.') != -1) {
continue;
}
// attempt to bind the property
boolean hit = doBuildPropertyOgnlPath(camelContext, target, key, value, deepNesting, fluentBuilder,
- allowPrivateSetter, ignoreCase, reference, placeholder, mandatory, configurer);
+ allowPrivateSetter, ignoreCase, reference, placeholder, mandatory, reflection, configurer);
if (hit && removeParameter) {
properties.remove(key);
}
@@ -673,7 +689,7 @@ public final class PropertyBindingSupport {
final CamelContext camelContext, final Object originalTarget, String name, final Object value,
boolean deepNesting, boolean fluentBuilder, boolean allowPrivateSetter,
boolean ignoreCase, boolean reference, boolean placeholder, boolean mandatory,
- PropertyConfigurer configurer) {
+ boolean reflection, PropertyConfigurer configurer) {
boolean optional = name.startsWith("?");
if (optional) {
@@ -705,7 +721,7 @@ public final class PropertyBindingSupport {
if (configurer != null) {
prop = getOrCreatePropertyOgnlPathViaConfigurer(camelContext, newTarget, part, ignoreCase, configurer);
}
- if (prop == null) {
+ if (prop == null && reflection) {
// no configurer or not possible with configurer so fallback and use reflection
prop = getOrCreatePropertyOgnlPathViaReflection(camelContext, newTarget, part, ignoreCase);
}
@@ -719,7 +735,7 @@ public final class PropertyBindingSupport {
prop = attemptCreateNewInstanceViaConfigurer(camelContext, newTarget, part, ignoreCase,
configurer);
}
- if (prop == null) {
+ if (prop == null && reflection) {
// no configurer or not possible with configurer so fallback and use reflection
prop = attemptCreateNewInstanceViaReflection(camelContext, newTarget, newClass, part, fluentBuilder,
allowPrivateSetter,
@@ -767,7 +783,7 @@ public final class PropertyBindingSupport {
// we have walked down to the last part of the ognl path and are ready to set the last piece with the value
// now this is actually also a bit complex so lets use another method for that
return doSetPropertyValue(camelContext, newTarget, newName, value, ignoreCase, mandatory,
- fluentBuilder, allowPrivateSetter, reference, placeholder, optional, configurer);
+ fluentBuilder, allowPrivateSetter, reference, placeholder, optional, reflection, configurer);
}
private static Object attemptCreateNewInstanceViaReflection(
@@ -849,7 +865,7 @@ public final class PropertyBindingSupport {
boolean ignoreCase, boolean mandatory,
boolean fluentBuilder, boolean allowPrivateSetter,
boolean reference, boolean placeholder, boolean optional,
- PropertyConfigurer configurer) {
+ boolean reflection, PropertyConfigurer configurer) {
String key = name;
Object text = value;
@@ -866,7 +882,7 @@ public final class PropertyBindingSupport {
// prepare the value before it is bound
try {
Object str = resolveValue(camelContext, target, key, text, ignoreCase, fluentBuilder,
- allowPrivateSetter, configurer);
+ allowPrivateSetter, reflection, configurer);
// resolve property placeholders
if (str instanceof String) {
// resolve property placeholders
@@ -887,7 +903,7 @@ public final class PropertyBindingSupport {
if (configurer != null) {
bound = setPropertyCollectionViaConfigurer(camelContext, target, key, value, ignoreCase, configurer);
}
- if (!bound) {
+ if (!bound && reflection) {
// fallback to reflection based
bound = setPropertyCollectionViaReflection(camelContext, target, key, value, ignoreCase, reference);
}
@@ -896,10 +912,10 @@ public final class PropertyBindingSupport {
if (configurer != null) {
bound = setSimplePropertyViaConfigurer(camelContext, target, key, value, ignoreCase, configurer);
}
- if (!bound) {
+ if (!bound && reflection) {
// fallback to reflection based
bound = setSimplePropertyViaReflection(camelContext, target, key, value, fluentBuilder, allowPrivateSetter,
- reference, ignoreCase);
+ reflection, ignoreCase);
}
}
@@ -961,7 +977,7 @@ public final class PropertyBindingSupport {
if (value instanceof String) {
String str = value.toString();
if (reference && isReferenceParameter(str)) {
- Object bean = CamelContextHelper.lookup(context, str.toString().substring(1));
+ Object bean = CamelContextHelper.lookup(context, str.substring(1));
if (bean != null) {
value = bean;
}
@@ -1157,7 +1173,7 @@ public final class PropertyBindingSupport {
private static Object resolveAutowired(
CamelContext context, Object target, String name, Object value,
boolean ignoreCase, boolean fluentBuilder, boolean allowPrivateSetter,
- PropertyConfigurer configurer)
+ boolean reflection, PropertyConfigurer configurer)
throws Exception {
if (value instanceof String) {
@@ -1169,7 +1185,7 @@ public final class PropertyBindingSupport {
// favour using configurer
parameterType = (Class<?>) ((PropertyConfigurerGetter) configurer).getAllOptions(target).get(name);
}
- if (parameterType == null) {
+ if (parameterType == null && reflection) {
// fallback to reflection
Method method
= findBestSetterMethod(context, target.getClass(), name, fluentBuilder, allowPrivateSetter,
@@ -1204,7 +1220,7 @@ public final class PropertyBindingSupport {
private static Object resolveValue(
CamelContext context, Object target, String name, Object value,
boolean ignoreCase, boolean fluentBuilder, boolean allowPrivateSetter,
- PropertyConfigurer configurer)
+ boolean reflection, PropertyConfigurer configurer)
throws Exception {
if (value instanceof String) {
String str = value.toString();
@@ -1220,7 +1236,7 @@ public final class PropertyBindingSupport {
}
} else if (str.equals("#autowired")) {
value = resolveAutowired(context, target, name, value, ignoreCase, fluentBuilder, allowPrivateSetter,
- configurer);
+ reflection, configurer);
} else {
value = resolveBean(context, name, value);
}
@@ -1242,7 +1258,7 @@ public final class PropertyBindingSupport {
refName = "#" + ((String) value).substring(6);
value = null;
} else if (str.equals("#autowired")) {
- value = resolveAutowired(context, target, name, value, ignoreCase, fluentBuilder, allowPrivateSetter, null);
+ value = resolveAutowired(context, target, name, value, ignoreCase, fluentBuilder, allowPrivateSetter, true, null);
} else if (isReferenceParameter(str)) {
// special for reference (we should not do this for options that are String type)
// this is only required for reflection (as configurer does this automatic in a more safe way)