You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by lb...@apache.org on 2019/12/09 16:42:59 UTC
[camel] branch camel-3.0.x updated: CAMEL-14268: Component auto
configuration fails in Java 11
This is an automated email from the ASF dual-hosted git repository.
lburgazzoli pushed a commit to branch camel-3.0.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-3.0.x by this push:
new 3fa8043 CAMEL-14268: Component auto configuration fails in Java 11
3fa8043 is described below
commit 3fa80434504118d3071ba259ffb012d3e0d720b5
Author: lburgazzoli <lb...@gmail.com>
AuthorDate: Mon Dec 9 10:37:06 2019 +0100
CAMEL-14268: Component auto configuration fails in Java 11
---
.../org/apache/camel/main/BaseMainSupport.java | 130 ++++++++++-----------
.../camel/main/MainComponentConfigurationTest.java | 54 +++++++++
.../camel/main/support/MyDummyComponent.java | 67 +++++++++++
.../main/support/MyDummyComponentConfigurer.java | 52 +++++++++
.../camel/main/support/MyDummyConfiguration.java | 52 +++++++++
.../camel/support/PropertyBindingSupport.java | 74 ++++++------
6 files changed, 329 insertions(+), 100 deletions(-)
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index 991e6ab..7b5e8ea 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -21,7 +21,6 @@ import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
@@ -122,15 +121,13 @@ public abstract class BaseMainSupport extends ServiceSupport {
}
protected static boolean setPropertiesOnTarget(CamelContext context, Object target, Map<String, Object> properties,
- String optionKey, String optionPrefix, boolean failIfNotSet, boolean ignoreCase,
+ String optionPrefix, boolean failIfNotSet, boolean ignoreCase,
Map<String, String> autoConfiguredProperties) throws Exception {
ObjectHelper.notNull(context, "context");
ObjectHelper.notNull(target, "target");
ObjectHelper.notNull(properties, "properties");
boolean rc = false;
- Iterator it = properties.entrySet().iterator();
-
PropertyConfigurer configurer = null;
if (target instanceof Component) {
// the component needs to be initialized to have the configurer ready
@@ -138,41 +135,47 @@ public abstract class BaseMainSupport extends ServiceSupport {
configurer = ((Component) target).getComponentPropertyConfigurer();
}
- while (it.hasNext()) {
- Map.Entry<String, Object> entry = (Map.Entry) it.next();
- String name = entry.getKey();
- Object value = entry.getValue();
- String stringValue = value != null ? value.toString() : null;
- String key = name;
- if (optionPrefix != null && optionKey != null) {
- key = optionPrefix + optionKey;
- } else if (optionPrefix != null) {
- key = optionPrefix + name;
- }
+ try {
+ // keep a reference of the original keys
+ Map<String, Object> backup = new LinkedHashMap<>(properties);
+
+ rc = PropertyBindingSupport.build()
+ .withMandatory(failIfNotSet)
+ .withRemoveParameters(true)
+ .withConfigurer(configurer)
+ .withIgnoreCase(ignoreCase)
+ .bind(context, target, properties);
+
+ for (Map.Entry<String, Object> entry: backup.entrySet()) {
+ if (entry.getValue() != null && !properties.containsKey(entry.getKey())) {
+ String prefix = optionPrefix;
+ if (prefix != null && !prefix.endsWith(".")) {
+ prefix = "." + prefix;
+ }
- LOG.debug("Configuring property: {}={} on bean: {}", key, stringValue, target);
- try {
- boolean hit;
- if (failIfNotSet) {
- PropertyBindingSupport.build().withMandatory(true).withConfigurer(configurer).withIgnoreCase(ignoreCase).bind(context, target, name, stringValue);
- hit = true;
- } else {
- hit = PropertyBindingSupport.build().withConfigurer(configurer).withIgnoreCase(true).bind(context, target, name, stringValue);
- }
- if (hit) {
- it.remove();
- rc = true;
- LOG.debug("Configured property: {}={} on bean: {}", key, stringValue, target);
- autoConfiguredProperties.put(key, stringValue);
+ LOG.debug("Configured property: {}{}={} on bean: {}", prefix, entry.getKey(), entry.getValue(), target);
+ autoConfiguredProperties.put(prefix + entry.getKey(), entry.getValue().toString());
}
- } catch (PropertyBindingException e) {
- if (failIfNotSet) {
- // enrich the error with more precise details with option prefix and key
- throw new PropertyBindingException(e.getTarget(), e.getPropertyName(), e.getValue(), optionPrefix, optionKey, e.getCause());
- } else {
- LOG.debug("Error configuring property (" + key + ") with name: " + name + ") on bean: " + target
- + " with value: " + stringValue + ". This exception is ignored as failIfNotSet=false.", e);
+ }
+ } catch (PropertyBindingException e) {
+ String key = e.getOptionKey();
+ if (key == null) {
+ String prefix = e.getOptionPrefix();
+ if (prefix != null && !prefix.endsWith(".")) {
+ prefix = "." + prefix;
}
+
+ key = prefix != null
+ ? prefix + "." + e.getPropertyName()
+ : e.getPropertyName();
+ }
+
+ if (failIfNotSet) {
+ // enrich the error with more precise details with option prefix and key
+ throw new PropertyBindingException(e.getTarget(), e.getPropertyName(), e.getValue(), optionPrefix, key, e.getCause());
+ } else {
+ LOG.debug("Error configuring property (" + key + ") with name: " + e.getPropertyName() + ") on bean: " + target
+ + " with value: " + e.getValue() + ". This exception is ignored as failIfNotSet=false.", e);
}
}
@@ -707,7 +710,7 @@ public abstract class BaseMainSupport extends ServiceSupport {
}
if (!contextProperties.isEmpty()) {
LOG.debug("Auto-configuring CamelContext from loaded properties: {}", contextProperties.size());
- setPropertiesOnTarget(camelContext, camelContext, contextProperties, null, "camel.context.",
+ setPropertiesOnTarget(camelContext, camelContext, contextProperties, "camel.context.",
mainConfigurationProperties.isAutoConfigurationFailFast(), true, autoConfiguredProperties);
}
if (!hystrixProperties.isEmpty()) {
@@ -718,7 +721,7 @@ public abstract class BaseMainSupport extends ServiceSupport {
hystrix = new HystrixConfigurationDefinition();
model.setHystrixConfiguration(hystrix);
}
- setPropertiesOnTarget(camelContext, hystrix, hystrixProperties, null, "camel.hystrix.",
+ setPropertiesOnTarget(camelContext, hystrix, hystrixProperties, "camel.hystrix.",
mainConfigurationProperties.isAutoConfigurationFailFast(), true, autoConfiguredProperties);
}
if (!resilience4jProperties.isEmpty()) {
@@ -729,7 +732,7 @@ public abstract class BaseMainSupport extends ServiceSupport {
resilience4j = new Resilience4jConfigurationDefinition();
model.setResilience4jConfiguration(resilience4j);
}
- setPropertiesOnTarget(camelContext, resilience4j, resilience4jProperties, null, "camel.resilience4j.",
+ setPropertiesOnTarget(camelContext, resilience4j, resilience4jProperties, "camel.resilience4j.",
mainConfigurationProperties.isAutoConfigurationFailFast(), true, autoConfiguredProperties);
}
if (!restProperties.isEmpty()) {
@@ -740,7 +743,7 @@ public abstract class BaseMainSupport extends ServiceSupport {
rest = new RestConfiguration();
model.setRestConfiguration(rest);
}
- setPropertiesOnTarget(camelContext, rest, restProperties, null, "camel.rest.",
+ setPropertiesOnTarget(camelContext, rest, restProperties, "camel.rest.",
mainConfigurationProperties.isAutoConfigurationFailFast(), true, autoConfiguredProperties);
}
@@ -799,9 +802,8 @@ public abstract class BaseMainSupport extends ServiceSupport {
if (!properties.isEmpty()) {
LOG.debug("Auto-configuring properties component from loaded properties: {}", properties.size());
- setPropertiesOnTarget(camelContext, camelContext.getPropertiesComponent(), properties, null,
- "camel.component.properties.", mainConfigurationProperties.isAutoConfigurationFailFast(),
- true, autoConfiguredProperties);
+ setPropertiesOnTarget(camelContext, camelContext.getPropertiesComponent(), properties, "camel.component.properties.",
+ mainConfigurationProperties.isAutoConfigurationFailFast(), true, autoConfiguredProperties);
}
// log which options was not set
@@ -838,7 +840,7 @@ public abstract class BaseMainSupport extends ServiceSupport {
if (!properties.isEmpty()) {
LOG.debug("Auto-configuring main from loaded properties: {}", properties.size());
- setPropertiesOnTarget(camelContext, config, properties, null, "camel.main.",
+ setPropertiesOnTarget(camelContext, config, properties, "camel.main.",
mainConfigurationProperties.isAutoConfigurationFailFast(), true, autoConfiguredProperties);
}
@@ -923,11 +925,15 @@ public abstract class BaseMainSupport extends ServiceSupport {
LOG.debug("Auto-configuring {} components/dataformat/languages from loaded properties: {}", properties.size(), total);
}
- for (PropertyOptionKey pok : properties.keySet()) {
- Map<String, Object> values = properties.get(pok);
- String optionKey = pok.getKey().substring(pok.getOptionPrefix().length());
- setPropertiesOnTarget(camelContext, pok.getInstance(), values, optionKey, pok.getOptionPrefix(),
- mainConfigurationProperties.isAutoConfigurationFailFast(), true, autoConfiguredProperties);
+ for (Map.Entry<PropertyOptionKey, Map<String, Object>> entry: properties.entrySet()) {
+ setPropertiesOnTarget(
+ camelContext,
+ entry.getKey().getInstance(),
+ entry.getValue(),
+ entry.getKey().getOptionPrefix(),
+ mainConfigurationProperties.isAutoConfigurationFailFast(),
+ true,
+ autoConfiguredProperties);
}
// log which options was not set
@@ -936,7 +942,7 @@ public abstract class BaseMainSupport extends ServiceSupport {
Map<String, Object> values = properties.get(pok);
values.forEach((k, v) -> {
String stringValue = v != null ? v.toString() : null;
- LOG.warn("Property ({}={}) not auto-configured with name: {} on bean: {} with value: {}", pok.getKey(), stringValue, k, pok.getInstance(), stringValue);
+ LOG.warn("Property ({}={}) not auto-configured with name: {} on bean: {} with value: {}", pok.getOptionPrefix() + "." + k, stringValue, k, pok.getInstance(), stringValue);
});
}
}
@@ -1010,19 +1016,12 @@ public abstract class BaseMainSupport extends ServiceSupport {
}
private static final class PropertyOptionKey {
-
- private final String key;
private final Object instance;
private final String optionPrefix;
- private PropertyOptionKey(String key, Object instance, String optionPrefix) {
- this.key = key;
- this.instance = instance;
- this.optionPrefix = optionPrefix;
- }
-
- public String getKey() {
- return key;
+ private PropertyOptionKey(Object instance, String optionPrefix) {
+ this.instance = ObjectHelper.notNull(instance, "instance");
+ this.optionPrefix = ObjectHelper.notNull(optionPrefix, "optionPrefix");
}
public Object getInstance() {
@@ -1038,16 +1037,17 @@ public abstract class BaseMainSupport extends ServiceSupport {
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (!(o instanceof PropertyOptionKey)) {
return false;
}
- PropertyOptionKey that = (PropertyOptionKey) o;
- return key.equals(that.key) && instance.equals(that.instance);
+ PropertyOptionKey key = (PropertyOptionKey) o;
+ return Objects.equals(instance, key.instance)
+ && Objects.equals(optionPrefix, key.optionPrefix);
}
@Override
public int hashCode() {
- return Objects.hash(key, instance);
+ return Objects.hash(instance, optionPrefix);
}
}
@@ -1093,7 +1093,7 @@ public abstract class BaseMainSupport extends ServiceSupport {
validateOptionAndValue(key, option, value);
- PropertyOptionKey pok = new PropertyOptionKey(key, target, prefix);
+ PropertyOptionKey pok = new PropertyOptionKey(target, prefix);
Map<String, Object> values = properties.computeIfAbsent(pok, k -> new LinkedHashMap<>());
// we ignore case for property keys (so we should store them in canonical style
diff --git a/core/camel-main/src/test/java/org/apache/camel/main/MainComponentConfigurationTest.java b/core/camel-main/src/test/java/org/apache/camel/main/MainComponentConfigurationTest.java
new file mode 100644
index 0000000..a2360ba
--- /dev/null
+++ b/core/camel-main/src/test/java/org/apache/camel/main/MainComponentConfigurationTest.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.main;
+
+import java.util.Properties;
+
+import org.apache.camel.main.support.MyDummyComponent;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class MainComponentConfigurationTest extends Assert {
+ @Test
+ public void testComponentConfiguration() {
+ Properties properties = new Properties();
+ properties.setProperty("camel.component.dummy.configuration.log", "true");
+ properties.setProperty("camel.component.dummy.component-value", "component-value");
+ properties.setProperty("camel.component.dummy.configuration.nested.value", "nested-value");
+ properties.setProperty("camel.component.dummy.configuration", "#class:org.apache.camel.main.support.MyDummyConfiguration");
+
+ Main main = new Main();
+ try {
+ MyDummyComponent dummy = new MyDummyComponent(false);
+
+ main.bind("dummy", dummy);
+ main.setOverrideProperties(properties);
+ main.setDefaultPropertyPlaceholderLocation("false");
+ main.start();
+
+ assertEquals("component-value", dummy.getComponentValue());
+
+ assertNotNull(dummy.getConfiguration());
+ assertTrue(dummy.getConfiguration().isLog());
+ assertNotNull(dummy.getConfiguration().getNested());
+ assertEquals("nested-value", dummy.getConfiguration().getNested().getValue());
+ } finally {
+ main.stop();
+ }
+ }
+}
+
diff --git a/core/camel-main/src/test/java/org/apache/camel/main/support/MyDummyComponent.java b/core/camel-main/src/test/java/org/apache/camel/main/support/MyDummyComponent.java
new file mode 100644
index 0000000..9b3d73f
--- /dev/null
+++ b/core/camel-main/src/test/java/org/apache/camel/main/support/MyDummyComponent.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.main.support;
+
+import java.util.Map;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.spi.PropertyConfigurer;
+import org.apache.camel.spi.annotations.Component;
+import org.apache.camel.support.DefaultComponent;
+
+@Component("dummy")
+public class MyDummyComponent extends DefaultComponent {
+ private MyDummyConfiguration configuration;
+ private boolean configurer;
+ private String componentValue;
+
+ public MyDummyComponent(boolean configurer) {
+ this.configurer = configurer;
+ }
+
+ public MyDummyConfiguration getConfiguration() {
+ return configuration;
+ }
+
+ public void setConfiguration(MyDummyConfiguration configuration) {
+ this.configuration = configuration;
+ }
+
+ // this method makes camel no able to find a suitable setter
+ public void setConfiguration(Object configuration) {
+ this.configuration = (MyDummyConfiguration)configuration;
+ }
+
+ public String getComponentValue() {
+ return componentValue;
+ }
+
+ public MyDummyComponent setComponentValue(String componentValue) {
+ this.componentValue = componentValue;
+ return this;
+ }
+
+ @Override
+ protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public PropertyConfigurer getComponentPropertyConfigurer() {
+ return configurer ? new MyDummyComponentConfigurer() : null;
+ }
+}
diff --git a/core/camel-main/src/test/java/org/apache/camel/main/support/MyDummyComponentConfigurer.java b/core/camel-main/src/test/java/org/apache/camel/main/support/MyDummyComponentConfigurer.java
new file mode 100644
index 0000000..9751c7b
--- /dev/null
+++ b/core/camel-main/src/test/java/org/apache/camel/main/support/MyDummyComponentConfigurer.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.main.support;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.support.component.PropertyConfigurerSupport;
+
+public class MyDummyComponentConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer {
+ @Override
+ public boolean configure(CamelContext camelContext, Object component, String name, Object value, boolean ignoreCase) {
+ if (ignoreCase) {
+ return doConfigureIgnoreCase(camelContext, component, name, value);
+ } else {
+ return doConfigure(camelContext, component, name, value);
+ }
+ }
+
+ private static boolean doConfigure(CamelContext camelContext, Object component, String name, Object value) {
+ switch (name) {
+ case "configuration":
+ ((MyDummyComponent) component).setConfiguration(property(camelContext, MyDummyConfiguration.class, value));
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private static boolean doConfigureIgnoreCase(CamelContext camelContext, Object component, String name, Object value) {
+ switch (name.toLowerCase()) {
+ case "configuration":
+ ((MyDummyComponent) component).setConfiguration(property(camelContext, MyDummyConfiguration.class, value));
+ return true;
+ default:
+ return false;
+ }
+ }
+}
diff --git a/core/camel-main/src/test/java/org/apache/camel/main/support/MyDummyConfiguration.java b/core/camel-main/src/test/java/org/apache/camel/main/support/MyDummyConfiguration.java
new file mode 100644
index 0000000..153dadf
--- /dev/null
+++ b/core/camel-main/src/test/java/org/apache/camel/main/support/MyDummyConfiguration.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.main.support;
+
+public class MyDummyConfiguration {
+ private boolean log;
+ private NestedConfig nested;
+
+ public boolean isLog() {
+ return log;
+ }
+
+ public MyDummyConfiguration setLog(boolean log) {
+ this.log = log;
+ return this;
+ }
+
+ public NestedConfig getNested() {
+ return nested;
+ }
+
+ public void setNested(NestedConfig nested) {
+ this.nested = nested;
+ }
+
+ public static class NestedConfig {
+ private String value;
+
+ public String getValue() {
+ return value;
+ }
+
+ public NestedConfig setValue(String value) {
+ this.value = value;
+ return this;
+ }
+ }
+}
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 4d101c1..1c8205d 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
@@ -19,6 +19,7 @@ package org.apache.camel.support;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -471,7 +472,9 @@ public final class PropertyBindingSupport {
org.apache.camel.util.ObjectHelper.notNull(camelContext, "camelContext");
org.apache.camel.util.ObjectHelper.notNull(target, "target");
org.apache.camel.util.ObjectHelper.notNull(properties, "properties");
- boolean rc = false;
+
+ final String uOptionPrefix = ignoreCase && isNotEmpty(optionPrefix) ? optionPrefix.toUpperCase(Locale.US) : "";
+ final int size = properties.size();
if (configurer instanceof GeneratedPropertyConfigurer) {
GeneratedPropertyConfigurer gen = (GeneratedPropertyConfigurer) configurer;
@@ -480,12 +483,9 @@ public final class PropertyBindingSupport {
Map.Entry<String, Object> entry = iter.next();
String key = entry.getKey();
Object value = entry.getValue();
- boolean valid = true;
- if (nesting) {
- // property configurer does not support nested names so skip if the name has a dot
- valid = key.indexOf('.') == -1;
- }
- if (valid) {
+
+ // property configurer does not support nested names so skip if the name has a dot
+ if (key.indexOf('.') != -1) {
try {
// GeneratedPropertyConfigurer works by invoking the methods directly but it does
// not resolve property placeholders eventually defined in the value before invoking
@@ -497,7 +497,6 @@ public final class PropertyBindingSupport {
boolean hit = gen.configure(camelContext, target, key, value, ignoreCase);
if (removeParameter && hit) {
iter.remove();
- rc = true;
}
} catch (Exception e) {
throw new PropertyBindingException(target, key, value, e);
@@ -507,39 +506,44 @@ public final class PropertyBindingSupport {
}
// must set reference parameters first before the other bindings
- int size = properties.size();
setReferenceProperties(camelContext, target, properties);
- rc |= properties.size() != size;
-
- 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)) {
- boolean match = key.startsWith(optionPrefix) || ignoreCase && key.toUpperCase(Locale.US).startsWith(uOptionPrefix);
- if (!match) {
- continue;
+ // sort the keys by nesting level so when moving to the nest level all the
+ // propertis of the curent level are bound to the target. This allow the
+ // properties binging engine to be indipendent to the order of properrties.
+ //
+ // As example:
+ //
+ // configuration.my-property = myCustomValue
+ // configuration = #class:my.custom.Config
+ //
+ // 'configuration.my-property' has lower precedence over 'configuration' as
+ // it is one level deep and will be set after all the properties of the current
+ // level are set which allow `my-property` to be set of the right instance.
+ properties.keySet().stream()
+ .sorted(Comparator.comparingInt(s -> StringHelper.countChar(s, '.')))
+ .forEach(key -> {
+ final Object value = properties.get(key);
+
+ if (isNotEmpty(optionPrefix)) {
+ boolean match = key.startsWith(optionPrefix) || ignoreCase && key.toUpperCase(Locale.US).startsWith(uOptionPrefix);
+ if (!match) {
+ return;
+ }
+ key = key.substring(optionPrefix.length());
}
- key = key.substring(optionPrefix.length());
- }
- boolean bound = bindProperty(camelContext, target, key, value, ignoreCase, nesting, deepNesting, fluentBuilder, allowPrivateSetter, reference, placeholder);
- if (bound && removeParameter) {
- iter.remove();
- rc = true;
- }
- if (mandatory && !bound) {
- throw new PropertyBindingException(target, key, value);
+ boolean bound = bindProperty(camelContext, target, key, value, ignoreCase, nesting, deepNesting, fluentBuilder, allowPrivateSetter, reference, placeholder);
+ if (bound && removeParameter) {
+ properties.remove(key);
+ }
+ if (mandatory && !bound) {
+ throw new PropertyBindingException(target, key, value);
+ }
}
- }
+ );
- return rc;
+ return properties.size() != size;
}
private static boolean bindProperty(CamelContext camelContext, Object target, String name, Object value,