This is an automated email from the ASF dual-hosted git repository. nfilotto pushed a commit to branch CAMEL-16354/optimize-splitter in repository https://gitbox.apache.org/repos/asf/camel.git
commit eac6cb19211c1c48434c1f7cebd3353b77a723c0 Author: Nicolas Filotto <[email protected]> AuthorDate: Tue Oct 18 14:55:04 2022 +0200 CAMEL-16354: camel-core - Optimize Splitters using Scanner --- .../org/apache/camel/util/ObjectHelperTest.java | 40 ++++++++- .../org/apache/camel/support/ObjectHelper.java | 100 ++++++++++++++++++++- 2 files changed, 136 insertions(+), 4 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 4527d95187a..49a36639ea0 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 @@ -29,6 +29,8 @@ import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Properties; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -47,8 +49,17 @@ import org.apache.camel.support.CamelContextHelper; import org.apache.camel.support.DefaultMessage; import org.apache.camel.support.ObjectHelper; import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; public class ObjectHelperTest { @@ -1016,4 +1027,29 @@ public class ObjectHelperTest { assertEquals("foo", out2.get(0)); assertEquals("bar", out2.get(1)); } + + @Test + void testIterableWithNullContent() { + assertEquals("", StreamSupport.stream(ObjectHelper.createIterable(null, ";;").spliterator(), false) + .collect(Collectors.joining("-"))); + } + + @Test + void testIterableWithEmptyContent() { + assertEquals("", StreamSupport.stream(ObjectHelper.createIterable("", ";;").spliterator(), false) + .collect(Collectors.joining("-"))); + } + + @Test + void testIterableWithOneElement() { + assertEquals("foo", StreamSupport.stream(ObjectHelper.createIterable("foo", ";;").spliterator(), false) + .collect(Collectors.joining("-"))); + } + + @ParameterizedTest + @ValueSource(strings = { "foo;;bar", ";;foo;;bar", "foo;;bar;;", ";;foo;;bar;;" }) + void testIterableWithTwoElements(String content) { + assertEquals("foo-bar", StreamSupport.stream(ObjectHelper.createIterable(content, ";;").spliterator(), false) + .collect(Collectors.joining("-"))); + } } diff --git a/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java b/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java index 120b2af6a95..92accefbcd1 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java @@ -550,8 +550,10 @@ public final class ObjectHelper { int count = StringHelper.countChar(value, DEFAULT_DELIMITER_CHAR) + 1; return () -> StringHelper.splitOnCharacterAsIterator(value, DEFAULT_DELIMITER_CHAR, count); } + } else if (pattern) { + return () -> new Scanner(value, delimiter); } - return () -> new Scanner(value, delimiter); + return () -> new StringIterator(value, delimiter); } else if (allowEmptyValues || org.apache.camel.util.ObjectHelper.isNotEmpty(value)) { return Collections.singletonList(value); } else { @@ -770,9 +772,10 @@ public final class ObjectHelper { return (Iterable<String>) () -> StringHelper.splitOnCharacterAsIterator(s, DEFAULT_DELIMITER_CHAR, count); } - } else { + } else if (pattern) { return (Iterable<String>) () -> new Scanner(s, delimiter); } + return (Iterable<String>) () -> new StringIterator(s, delimiter); } else { return (Iterable<Object>) () -> { // use a plain iterator that returns the value as is as there are only a single value @@ -886,4 +889,97 @@ public final class ObjectHelper { return false; } + /** + * An {@link Iterator} to split an input {@code String} content according to a specific separator. + */ + private static class StringIterator implements Iterator<String> { + + /** + * Flag indicating that the indexes have already been computed. + */ + private boolean computed; + /** + * The current {@code from} index. + */ + private int from; + /** + * The current {@code to} index. + */ + private int to; + /** + * The content to split. + */ + private final String content; + /** + * The separator to use when splitting the content. + */ + private final String separator; + /** + * The length of the separator. + */ + private final int separatorLength; + /** + * The length of the part of the content to split. + */ + private final int contentLength; + + /** + * Construct a {@code StringIterator} with the specified content and separator. + * + * @param content + * @param separator + */ + StringIterator(String content, String separator) { + this.content = content; + this.separator = separator; + this.separatorLength = separator.length(); + boolean skipStart = content.startsWith(separator); + boolean skipEnd = content.endsWith(separator); + if (skipStart && skipEnd) { + from = separatorLength; + contentLength = content.length() - separatorLength; + } else if (skipStart) { + from = separatorLength; + this.contentLength = content.length(); + } else if (skipEnd) { + contentLength = content.length() - separatorLength; + } else { + this.contentLength = content.length(); + } + } + + @Override + public boolean hasNext() { + if (computed) { + return to != -1; + } else if (to == -1) { + return false; + } + int index = content.indexOf(separator, from); + if (index == -1 || index == contentLength) { + to = contentLength; + } else { + to = index; + } + computed = true; + return true; + } + + @Override + public String next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + String answer; + if (to == contentLength) { + answer = content.substring(from, contentLength); + to = -1; + } else { + answer = content.substring(from, to); + from = to + separatorLength; + } + computed = false; + return answer; + } + } }
