This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push: new a3ac6af2d7c CAMEL-18856: camel-main - Unable to declare java.util.List bean a3ac6af2d7c is described below commit a3ac6af2d7c557786741e59cd49e8491a96f170b Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Wed Jan 4 09:04:09 2023 +0100 CAMEL-18856: camel-main - Unable to declare java.util.List bean --- .../org/apache/camel/util/ObjectHelperTest.java | 21 ++++++++++++++ .../org/apache/camel/main/BaseMainSupport.java | 11 ++++++-- .../java/org/apache/camel/main/MainHelper.java | 31 +++++++-------------- .../java/org/apache/camel/main/MainBeansTest.java | 30 ++++++++++++++++++++ .../camel/support/PropertyBindingSupport.java | 32 +++++++++------------- .../java/org/apache/camel/util/ObjectHelper.java | 25 +++++++++++++++++ .../java/org/apache/camel/util/StringHelper.java | 9 ++++++ 7 files changed, 116 insertions(+), 43 deletions(-) diff --git a/core/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java b/core/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java index 6818c586a77..4b48a7f9a5d 100644 --- a/core/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java @@ -48,6 +48,7 @@ import org.apache.camel.impl.DefaultCamelContext; import org.apache.camel.support.CamelContextHelper; import org.apache.camel.support.DefaultMessage; import org.apache.camel.support.ObjectHelper; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -1078,4 +1079,24 @@ public class ObjectHelperTest { StreamSupport.stream(ObjectHelper.createIterable(content, ";+", false, true).spliterator(), false) .collect(Collectors.joining("-"))); } + + @Test + public void testAddListByIndex() { + List<Object> list = new ArrayList<>(); + org.apache.camel.util.ObjectHelper.addListByIndex(list, 0, "aaa"); + org.apache.camel.util.ObjectHelper.addListByIndex(list, 2, "ccc"); + org.apache.camel.util.ObjectHelper.addListByIndex(list, 1, "bbb"); + + Assertions.assertEquals(3, list.size()); + Assertions.assertEquals("aaa", list.get(0)); + Assertions.assertEquals("bbb", list.get(1)); + Assertions.assertEquals("ccc", list.get(2)); + + org.apache.camel.util.ObjectHelper.addListByIndex(list, 99, "zzz"); + Assertions.assertEquals(100, list.size()); + Assertions.assertNull(list.get(4)); + Assertions.assertNull(list.get(50)); + Assertions.assertNull(list.get(98)); + Assertions.assertEquals("zzz", list.get(99)); + } } 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 31a46faa36c..329eac41901 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 @@ -1409,8 +1409,13 @@ public abstract class BaseMainSupport extends BaseService { // create map beans if none already exists for (String name : beansMap) { if (camelContext.getRegistry().lookupByName(name) == null) { - // register bean as a map - Map<String, Object> bean = new LinkedHashMap<>(); + + // is the config list or map style + OrderedLocationProperties config = MainHelper.extractProperties(properties, name + "[", "]", false); + boolean list = config.keySet().stream().map(Object::toString).allMatch(StringHelper::isDigit); + + // register bean as a list or map + Object bean = list ? new ArrayList<>() : new LinkedHashMap<>(); if (logSummary) { LOG.info("Binding bean: {} (type: {}) to the registry", name, ObjectHelper.classCanonicalName(bean)); } else { @@ -1432,7 +1437,7 @@ public abstract class BaseMainSupport extends BaseService { setPropertiesOnTarget(camelContext, bean, config, optionPrefix + name + ".", failIfNotSet, ignoreCase, autoConfiguredProperties); } - // then set properties per bean (map style) + // then set properties per bean (map/list style) for (String name : beansMap) { Object bean = camelContext.getRegistry().lookupByName(name); if (bean == null) { diff --git a/core/camel-main/src/main/java/org/apache/camel/main/MainHelper.java b/core/camel-main/src/main/java/org/apache/camel/main/MainHelper.java index d4eb6aa1bdc..df8dcf85cd2 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/MainHelper.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/MainHelper.java @@ -493,29 +493,16 @@ public final class MainHelper { } public static OrderedLocationProperties extractProperties(OrderedLocationProperties properties, String optionPrefix) { - if (properties == null) { - return new OrderedLocationProperties(); - } - OrderedLocationProperties rc = new OrderedLocationProperties(); - - Set<Object> toRemove = new HashSet<>(); - for (var entry : properties.entrySet()) { - String key = entry.getKey().toString(); - String loc = properties.getLocation(key); - if (key.startsWith(optionPrefix)) { - Object value = properties.get(key); - key = key.substring(optionPrefix.length()); - rc.put(loc, key, value); - toRemove.add(entry.getKey()); - } - } - toRemove.forEach(properties::remove); - - return rc; + return extractProperties(properties, optionPrefix, null, true); } public static OrderedLocationProperties extractProperties( OrderedLocationProperties properties, String optionPrefix, String optionSuffix) { + return extractProperties(properties, optionPrefix, optionSuffix, true); + } + + public static OrderedLocationProperties extractProperties( + OrderedLocationProperties properties, String optionPrefix, String optionSuffix, boolean remove) { if (properties == null) { return new OrderedLocationProperties(); } @@ -528,11 +515,13 @@ public final class MainHelper { if (key.startsWith(optionPrefix)) { Object value = properties.get(key); key = key.substring(optionPrefix.length()); - if (key.endsWith(optionSuffix)) { + if (optionSuffix != null && key.endsWith(optionSuffix)) { key = key.substring(0, key.length() - optionSuffix.length()); } rc.put(loc, key, value); - toRemove.add(entry.getKey()); + if (remove) { + toRemove.add(entry.getKey()); + } } } toRemove.forEach(properties::remove); diff --git a/core/camel-main/src/test/java/org/apache/camel/main/MainBeansTest.java b/core/camel-main/src/test/java/org/apache/camel/main/MainBeansTest.java index dd704b2faae..6fa07348eb1 100644 --- a/core/camel-main/src/test/java/org/apache/camel/main/MainBeansTest.java +++ b/core/camel-main/src/test/java/org/apache/camel/main/MainBeansTest.java @@ -16,6 +16,7 @@ */ package org.apache.camel.main; +import java.util.List; import java.util.Map; import org.apache.camel.CamelContext; @@ -23,6 +24,7 @@ import org.apache.camel.builder.RouteBuilder; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertSame; @@ -141,6 +143,34 @@ public class MainBeansTest { main.stop(); } + @Test + public void testBindBeansListSquare() throws Exception { + Main main = new Main(); + main.configure().addRoutesBuilder(new MyRouteBuilder()); + + // defining a list bean (un-ordered) + main.addProperty("camel.beans.myprojects[0]", "Camel"); + main.addProperty("camel.beans.myprojects[2]", "Quarkus"); + main.addProperty("camel.beans.myprojects[1]", "Kafka"); + + main.start(); + + CamelContext camelContext = main.getCamelContext(); + assertNotNull(camelContext); + + Object bean = camelContext.getRegistry().lookupByName("myprojects"); + assertNotNull(bean); + assertInstanceOf(List.class, bean); + + List<?> list = (List<?>) bean; + assertEquals(3, list.size()); + assertEquals("Camel", list.get(0)); + assertEquals("Kafka", list.get(1)); + assertEquals("Quarkus", list.get(2)); + + main.stop(); + } + @Test public void testBindBeansMapSquareDotKey() throws Exception { Main main = new Main(); 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 6ce1abb5b92..1288a6ea9b6 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 @@ -499,6 +499,18 @@ public final class PropertyBindingSupport { ((Map) target).put(key, value); bound = true; } + // if the target value is a list type (and key is digit), + // then we can skip reflection and set the entry + if (!bound && List.class.isAssignableFrom(target.getClass()) && StringHelper.isDigit(key)) { + try { + // key must be digit + int idx = Integer.parseInt(key); + org.apache.camel.util.ObjectHelper.addListByIndex((List) target, idx, value); + bound = true; + } catch (NumberFormatException e) { + // ignore + } + } if (!bound && reflection) { // fallback to reflection based bound = setSimplePropertyViaReflection(camelContext, target, key, value, fluentBuilder, allowPrivateSetter, @@ -585,25 +597,7 @@ public final class PropertyBindingSupport { List list = (List) obj; if (isNotEmpty(lookupKey)) { int idx = Integer.parseInt(lookupKey); - if (idx < list.size()) { - list.set(idx, value); - } else if (idx == list.size()) { - list.add(value); - } else { - // If the list implementation is based on an array, we - // can increase tha capacity to the required value to - // avoid potential re-allocation weh invoking List::add. - // - // Note that ArrayList is the default List impl that - // is automatically created if the property is null. - if (list instanceof ArrayList) { - ((ArrayList) list).ensureCapacity(idx + 1); - } - while (list.size() < idx) { - list.add(null); - } - list.add(idx, value); - } + org.apache.camel.util.ObjectHelper.addListByIndex(list, idx, value); } else { list.add(value); } diff --git a/core/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java b/core/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java index e1afbbaea1f..35d8efe3466 100644 --- a/core/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java +++ b/core/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java @@ -1316,4 +1316,29 @@ public final class ObjectHelper { return objects != null ? Arrays.asList(objects) : Collections.emptyList(); } + /** + * Adds the value to the list at the given index + */ + public static void addListByIndex(List<Object> list, int idx, Object value) { + if (idx < list.size()) { + list.set(idx, value); + } else if (idx == list.size()) { + list.add(value); + } else { + // If the list implementation is based on an array, we + // can increase tha capacity to the required value to + // avoid potential re-allocation when invoking List::add. + // + // Note that ArrayList is the default List impl that + // is automatically created if the property is null. + if (list instanceof ArrayList) { + ((ArrayList<?>) list).ensureCapacity(idx + 1); + } + while (list.size() < idx) { + list.add(null); + } + list.add(idx, value); + } + } + } diff --git a/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java b/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java index aff3b0bf298..26fb5d61bb0 100644 --- a/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java +++ b/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java @@ -1156,4 +1156,13 @@ public final class StringHelper { } } + public static boolean isDigit(String s) { + for (char ch : s.toCharArray()) { + if (!Character.isDigit(ch)) { + return false; + } + } + return true; + } + }