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,