org.apache.camel.support.ObjectHelper Maven / Gradle / Ivy
The newest version!
/*
* 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.support;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.TreeMap;
import java.util.WeakHashMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Ordered;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.StreamCache;
import org.apache.camel.TypeConverter;
import org.apache.camel.WrappedFile;
import org.apache.camel.util.ReflectionHelper;
import org.apache.camel.util.Scanner;
import org.apache.camel.util.StringHelper;
/**
* A number of useful helper methods for working with Objects
*/
public final class ObjectHelper {
static {
PARENTHESIS_PATTERN = Pattern.compile(",(?!(?:[^\\(,]|[^\\)],[^\\)])+\\))");
}
private static final Pattern PARENTHESIS_PATTERN;
private static final String DEFAULT_DELIMITER = ",";
private static final char DEFAULT_DELIMITER_CHAR = ',';
/**
* Utility classes should not have a public constructor.
*/
private ObjectHelper() {
}
/**
* A helper method for comparing objects for equality in which it uses type coercion to coerce types between the
* left and right values. This allows you test for equality for example with a String and Integer type as Camel will
* be able to coerce the types.
*/
public static boolean typeCoerceEquals(TypeConverter converter, Object leftValue, Object rightValue) {
return typeCoerceEquals(converter, leftValue, rightValue, false);
}
/**
* A helper method for comparing objects for equality in which it uses type coercion to coerce types between the
* left and right values. This allows you test for equality for example with a String and Integer type as Camel will
* be able to coerce the types.
*/
public static boolean typeCoerceEquals(TypeConverter converter, Object leftValue, Object rightValue, boolean ignoreCase) {
// sanity check
if (leftValue == null || rightValue == null) {
return evalNulls(leftValue, rightValue);
}
// optimize for common combinations of comparing numbers
if (leftValue instanceof String) {
return typeCoerceString(converter, leftValue, rightValue, ignoreCase);
} else if (rightValue instanceof String str &&
(leftValue instanceof Integer || leftValue instanceof Long) && isNumber(str)) {
return typeCoerceIntLong(leftValue, str);
} else if (leftValue instanceof Integer && rightValue instanceof Integer) {
return integerPairComparison(leftValue, rightValue);
} else if (leftValue instanceof Long && rightValue instanceof Long) {
return longPairComparison(leftValue, rightValue);
} else if (leftValue instanceof Double && rightValue instanceof Double) {
return doublePairComparison(leftValue, rightValue);
} else if (rightValue instanceof String string && leftValue instanceof Boolean booleanValue) {
return booleanStringComparison(booleanValue, string);
}
// try without type coerce
return tryConverters(converter, leftValue, rightValue, ignoreCase);
}
private static boolean typeCoerceString(TypeConverter converter, Object leftValue, Object rightValue, boolean ignoreCase) {
if (rightValue instanceof String string) {
return typeCoerceStringPair((String) leftValue, string, ignoreCase);
} else if ((rightValue instanceof Integer || rightValue instanceof Long) &&
isNumber((String) leftValue)) {
return typeCoerceILString((String) leftValue, rightValue);
} else if (rightValue instanceof Double doubleValue && isFloatingNumber((String) leftValue)) {
return stringDoubleComparison((String) leftValue, doubleValue);
} else if (rightValue instanceof Boolean) {
return stringBooleanComparison(leftValue, rightValue);
}
return tryConverters(converter, leftValue, rightValue, ignoreCase);
}
private static boolean evalNulls(Object leftValue, Object rightValue) {
// they are equal
if (leftValue == rightValue) {
return true;
}
// only one of them is null so they are not equal
return false;
}
private static boolean tryConverters(TypeConverter converter, Object leftValue, Object rightValue, boolean ignoreCase) {
final boolean isEqual = org.apache.camel.util.ObjectHelper.equal(leftValue, rightValue, ignoreCase);
if (isEqual) {
return true;
}
// are they same type, if so return false as the equals returned false
if (leftValue.getClass().isInstance(rightValue)) {
return false;
}
// convert left to right
StreamCache sc = null;
try {
if (leftValue instanceof StreamCache streamCache) {
sc = streamCache;
}
Object value = converter.tryConvertTo(rightValue.getClass(), leftValue);
final boolean isEqualLeftToRight = org.apache.camel.util.ObjectHelper.equal(value, rightValue, ignoreCase);
if (isEqualLeftToRight) {
return true;
}
// convert right to left
if (rightValue instanceof StreamCache streamCache) {
sc = streamCache;
}
value = converter.tryConvertTo(leftValue.getClass(), rightValue);
return org.apache.camel.util.ObjectHelper.equal(leftValue, value, ignoreCase);
} finally {
if (sc != null) {
sc.reset();
}
}
}
private static boolean booleanStringComparison(Boolean leftBool, String rightValue) {
Boolean rightBool = Boolean.valueOf(rightValue);
return leftBool.compareTo(rightBool) == 0;
}
private static boolean doublePairComparison(Object leftValue, Object rightValue) {
return doublePairComparison((Double) leftValue, (Double) rightValue);
}
private static boolean doublePairComparison(Double leftValue, Double rightValue) {
return leftValue.compareTo(rightValue) == 0;
}
private static boolean longPairComparison(Object leftValue, Object rightValue) {
return longPairComparison((Long) leftValue, (Long) rightValue);
}
private static boolean longPairComparison(Long leftValue, Long rightValue) {
return leftValue.compareTo(rightValue) == 0;
}
private static boolean integerPairComparison(Object leftValue, Object rightValue) {
return integerPairComparison((Integer) leftValue, (Integer) rightValue);
}
private static boolean integerPairComparison(Integer leftValue, Integer rightValue) {
return leftValue.compareTo(rightValue) == 0;
}
private static boolean stringBooleanComparison(Object leftValue, Object rightValue) {
return stringBooleanComparison((String) leftValue, (Boolean) rightValue);
}
private static boolean stringBooleanComparison(String leftValue, Boolean rightValue) {
Boolean leftBool = Boolean.valueOf(leftValue);
return leftBool.compareTo(rightValue) == 0;
}
private static boolean stringDoubleComparison(String leftValue, Double rightValue) {
return doublePairComparison(Double.valueOf(leftValue), rightValue);
}
private static boolean typeCoerceIntLong(Object leftValue, String rightValue) {
if (leftValue instanceof Integer) {
return integerPairComparison((Integer) leftValue, Integer.valueOf(rightValue));
} else {
return longPairComparison((Long) leftValue, Long.valueOf(rightValue));
}
}
private static boolean typeCoerceILString(String leftValue, Object rightValue) {
if (rightValue instanceof Integer) {
return integerPairComparison(Integer.valueOf(leftValue), (Integer) rightValue);
} else {
return longPairComparison(Long.valueOf(leftValue), (Long) rightValue);
}
}
private static boolean typeCoerceStringPair(String leftNum, String rightNum, boolean ignoreCase) {
if (isNumber(leftNum) && isNumber(rightNum)) {
// favour to use numeric comparison
return longPairComparison(Long.parseLong(leftNum), Long.parseLong(rightNum));
}
if (ignoreCase) {
return leftNum.compareToIgnoreCase(rightNum) == 0;
} else {
return leftNum.compareTo(rightNum) == 0;
}
}
/**
* A helper method for comparing objects for inequality in which it uses type coercion to coerce types between the
* left and right values. This allows you test for inequality for example with a String and Integer type as Camel
* will be able to coerce the types.
*/
public static boolean typeCoerceNotEquals(TypeConverter converter, Object leftValue, Object rightValue) {
return !typeCoerceEquals(converter, leftValue, rightValue);
}
/**
* A helper method for comparing objects ordering in which it uses type coercion to coerce types between the left
* and right values. This allows you test for ordering for example with a String and Integer type as Camel will be
* able to coerce the types.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static int typeCoerceCompare(TypeConverter converter, Object leftValue, Object rightValue) {
// optimize for common combinations of comparing numbers
if (leftValue instanceof String leftNum && rightValue instanceof String rightNum) {
return typeCoerceCompareStringString(leftNum, rightNum);
} else if (leftValue instanceof Integer leftNum && rightValue instanceof Integer rightNum) {
return leftNum.compareTo(rightNum);
} else if (leftValue instanceof Long leftNum && rightValue instanceof Long rightNum) {
return leftNum.compareTo(rightNum);
} else if (leftValue instanceof Double leftNum && rightValue instanceof Double rightNum) {
return leftNum.compareTo(rightNum);
} else if (leftValue instanceof Float leftNum && rightValue instanceof Float rightNum) {
return leftNum.compareTo(rightNum);
} else if ((rightValue instanceof Integer || rightValue instanceof Long) &&
leftValue instanceof String leftStr && isNumber(leftStr)) {
if (rightValue instanceof Integer rightNum) {
Integer leftNum = Integer.valueOf(leftStr);
return leftNum.compareTo(rightNum);
} else {
Long leftNum = Long.valueOf(leftStr);
Long rightNum = (Long) rightValue;
return leftNum.compareTo(rightNum);
}
} else if (rightValue instanceof String &&
(leftValue instanceof Integer || leftValue instanceof Long) && isNumber((String) rightValue)) {
if (leftValue instanceof Integer leftNum) {
Integer rightNum = Integer.valueOf((String) rightValue);
return leftNum.compareTo(rightNum);
} else {
Long leftNum = (Long) leftValue;
Long rightNum = Long.valueOf((String) rightValue);
return leftNum.compareTo(rightNum);
}
} else if (rightValue instanceof Double rightNum && leftValue instanceof String
&& isFloatingNumber((String) leftValue)) {
Double leftNum = Double.valueOf((String) leftValue);
return leftNum.compareTo(rightNum);
} else if (rightValue instanceof Float rightNum && leftValue instanceof String
&& isFloatingNumber((String) leftValue)) {
Float leftNum = Float.valueOf((String) leftValue);
return leftNum.compareTo(rightNum);
} else if (rightValue instanceof Boolean rightBool && leftValue instanceof String) {
Boolean leftBool = Boolean.valueOf((String) leftValue);
return leftBool.compareTo(rightBool);
} else if (rightValue instanceof String && leftValue instanceof Boolean leftBool) {
Boolean rightBool = Boolean.valueOf((String) rightValue);
return leftBool.compareTo(rightBool);
}
// if both values is numeric then compare using numeric
Long leftNum = converter.tryConvertTo(Long.class, leftValue);
Long rightNum = converter.tryConvertTo(Long.class, rightValue);
if (leftNum != null && rightNum != null) {
return leftNum.compareTo(rightNum);
}
// also try with floating point numbers
Double leftDouble = converter.tryConvertTo(Double.class, leftValue);
Double rightDouble = converter.tryConvertTo(Double.class, rightValue);
if (leftDouble != null && rightDouble != null) {
return leftDouble.compareTo(rightDouble);
}
// prefer to NOT coerce to String so use the type which is not String
// for example if we are comparing String vs Integer then prefer to coerce to Integer
// as all types can be converted to String which does not work well for comparison
// as eg "10" < 6 would return true, where as 10 < 6 will return false.
// if they are both String then it doesn't matter
if (rightValue instanceof String) {
// if right is String and left is not then flip order (remember to * -1 the result then)
return typeCoerceCompare(converter, rightValue, leftValue) * -1;
}
// prefer to coerce to the right hand side at first
if (rightValue instanceof Comparable rightComparable) {
Object value = converter.tryConvertTo(rightValue.getClass(), leftValue);
if (value != null) {
return rightComparable.compareTo(value) * -1;
}
}
// then fallback to the left hand side
if (leftValue instanceof Comparable leftComparable) {
Object value = converter.tryConvertTo(leftValue.getClass(), rightValue);
if (value != null) {
return leftComparable.compareTo(value);
}
}
// use regular compare
return compare(leftValue, rightValue);
}
private static int typeCoerceCompareStringString(String leftNum, String rightNum) {
// prioritize non-floating numbers first
Long num1 = isNumber(leftNum) ? Long.parseLong(leftNum) : null;
Long num2 = isNumber(rightNum) ? Long.parseLong(rightNum) : null;
Double dec1 = num1 == null && isFloatingNumber(leftNum) ? Double.parseDouble(leftNum) : null;
Double dec2 = num2 == null && isFloatingNumber(rightNum) ? Double.parseDouble(rightNum) : null;
if (num1 != null && num2 != null) {
return num1.compareTo(num2);
} else if (dec1 != null && dec2 != null) {
return dec1.compareTo(dec2);
}
// okay mixed but we need to convert to floating
if (num1 != null && dec2 != null) {
dec1 = Double.parseDouble(leftNum);
return dec1.compareTo(dec2);
} else if (num2 != null && dec1 != null) {
dec2 = Double.parseDouble(rightNum);
return dec1.compareTo(dec2);
}
// fallback to string comparison
return leftNum.compareTo(rightNum);
}
/**
* Checks whether the text is an integer number
*/
public static boolean isNumber(String text) {
final int startPos = findStartPosition(text);
if (startPos < 0) {
return false;
}
for (int i = startPos; i < text.length(); i++) {
char ch = text.charAt(i);
if (!Character.isDigit(ch)) {
return false;
}
}
return true;
}
private static int findStartPosition(String text) {
if (text == null || text.isEmpty()) {
// invalid
return -1;
}
int startPos = 0;
if (text.charAt(0) == '-') {
if (text.length() == 1) {
// invalid
return -1;
}
// skip leading negative
startPos = 1;
}
return startPos;
}
/**
* Checks whether the text is a float point number
*/
public static boolean isFloatingNumber(String text) {
final int startPos = findStartPosition(text);
if (startPos < 0) {
return false;
}
boolean dots = false;
boolean digits = false;
char ch = 0;
for (int i = startPos; i < text.length(); i++) {
ch = text.charAt(i);
if (!Character.isDigit(ch)) {
if (ch == '.') {
if (dots) {
return false;
}
dots = true;
} else {
return false;
}
} else {
digits = true;
}
}
// there must be digits and not start or end with a dot
return digits && text.charAt(startPos) != '.' && ch != '.';
}
/**
* A helper method to invoke a method via reflection and wrap any exceptions as {@link RuntimeCamelException}
* instances
*
* @param method the method to invoke
* @param instance the object instance (or null for static methods)
* @param parameters the parameters to the method
* @return the result of the method invocation
*/
public static Object invokeMethod(Method method, Object instance, Object... parameters) {
try {
if (parameters != null) {
return method.invoke(instance, parameters);
} else {
return method.invoke(instance);
}
} catch (IllegalAccessException e) {
throw new RuntimeCamelException(e);
} catch (InvocationTargetException e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e.getCause());
}
}
/**
* A helper method to invoke a method via reflection in a safe way by allowing to invoke methods that are not
* accessible by default and wrap any exceptions as {@link RuntimeCamelException} instances
*
* @param method the method to invoke
* @param instance the object instance (or null for static methods)
* @param parameters the parameters to the method
* @return the result of the method invocation
*/
public static Object invokeMethodSafe(Method method, Object instance, Object... parameters)
throws InvocationTargetException, IllegalAccessException {
Object answer;
if (!method.isAccessible()) {
method.setAccessible(true);
}
if (parameters != null) {
answer = method.invoke(instance, parameters);
} else {
answer = method.invoke(instance);
}
return answer;
}
/**
* A helper method to invoke a method via reflection in a safe way by allowing to invoke methods that are not
* accessible by default and wrap any exceptions as {@link RuntimeCamelException} instances
*
* @param name the method name
* @param instance the object instance (or null for static methods)
* @param parameters the parameters to the method
* @return the result of the method invocation
*/
public static Object invokeMethodSafe(String name, Object instance, Object... parameters)
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
// find method first
Class>[] arr = null;
if (parameters != null) {
arr = new Class[parameters.length];
for (int i = 0; i < parameters.length; i++) {
Object p = parameters[i];
if (p != null) {
arr[i] = p.getClass();
}
}
}
Method m = ReflectionHelper.findMethod(instance.getClass(), name, arr);
if (m != null) {
return invokeMethodSafe(m, instance, parameters);
} else {
throw new NoSuchMethodException(name);
}
}
/**
* A helper method to create a new instance of a type using the default constructor arguments.
*/
public static T newInstance(Class type) {
try {
return type.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeCamelException(e);
}
}
/**
* A helper method to create a new instance of a type using the default constructor arguments.
*/
public static T newInstance(Class> actualType, Class expectedType) {
try {
Object value = actualType.getDeclaredConstructor().newInstance();
return org.apache.camel.util.ObjectHelper.cast(expectedType, value);
} catch (Exception e) {
throw new RuntimeCamelException(e);
}
}
/**
* A helper method for performing an ordered comparison on the objects handling nulls and objects which do not
* handle sorting gracefully
*/
public static int compare(Object a, Object b) {
return compare(a, b, false);
}
/**
* A helper method for performing an ordered comparison on the objects handling nulls and objects which do not
* handle sorting gracefully
*
* @param a the first object
* @param b the second object
* @param ignoreCase ignore case for string comparison
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static int compare(Object a, Object b, boolean ignoreCase) {
if (a == b) {
return 0;
}
if (a == null) {
return -1;
}
if (b == null) {
return 1;
}
if (a instanceof Ordered orderedA && b instanceof Ordered orderedB) {
return orderedA.getOrder() - orderedB.getOrder();
}
if (ignoreCase && a instanceof String strA && b instanceof String strB) {
return strA.compareToIgnoreCase(strB);
}
if (a instanceof Comparable comparable) {
return comparable.compareTo(b);
}
int answer = a.getClass().getName().compareTo(b.getClass().getName());
if (answer == 0) {
answer = a.hashCode() - b.hashCode();
}
return answer;
}
/**
* Calling the Callable with the setting of TCCL with the camel context application classloader.
*
* @param call the Callable instance
* @param exchange the exchange
* @return the result of Callable return
*/
public static Object callWithTCCL(Callable> call, Exchange exchange) throws Exception {
ClassLoader apcl = null;
if (exchange != null && exchange.getContext() != null) {
apcl = exchange.getContext().getApplicationContextClassLoader();
}
return callWithTCCL(call, apcl);
}
/**
* Calling the Callable with the setting of TCCL with a given classloader.
*
* @param call the Callable instance
* @param classloader the class loader
* @return the result of Callable return
*/
public static Object callWithTCCL(Callable> call, ClassLoader classloader) throws Exception {
final ClassLoader tccl = Thread.currentThread().getContextClassLoader();
try {
if (classloader != null) {
Thread.currentThread().setContextClassLoader(classloader);
}
return call.call();
} finally {
Thread.currentThread().setContextClassLoader(tccl);
}
}
/**
* Creates an iterable over the value if the value is a collection, an Object[], a String with values separated by
* comma, or a primitive type array; otherwise to simplify the caller's code, we just create a singleton collection
* iterator over a single value
*
* Will default use comma for String separating String values. This method does not allow empty values
*
* @param value the value
* @return the iterable
*/
public static Iterable> createIterable(Object value) {
return createIterable(value, DEFAULT_DELIMITER);
}
/**
* Creates an iterable over the value if the value is a collection, an Object[], a String with values separated by
* the given delimiter, or a primitive type array; otherwise to simplify the caller's code, we just create a
* singleton collection iterator over a single value
*
* This method does not allow empty values
*
* @param value the value
* @param delimiter delimiter for separating String values
* @return the iterable
*/
public static Iterable> createIterable(Object value, String delimiter) {
return createIterable(value, delimiter, false);
}
public static Iterable createIterable(String value) {
return createIterable(value, DEFAULT_DELIMITER);
}
public static Iterable createIterable(String value, String delimiter) {
return createIterable(value, delimiter, false);
}
public static Iterable createIterable(String value, String delimiter, boolean allowEmptyValues) {
return createIterable(value, delimiter, allowEmptyValues, false);
}
public static Iterable createIterable(String value, String delimiter, boolean allowEmptyValues, boolean pattern) {
if (value == null) {
return Collections.emptyList();
} else if (delimiter != null && (pattern || value.contains(delimiter))) {
// if its the default delimiter and the value has parenthesis
if (DEFAULT_DELIMITER.equals(delimiter)) {
if (value.indexOf('(') != -1 && value.indexOf(')') != -1) {
// we use the default delimiter which is a comma, then cater for bean expressions with OGNL
// which may have balanced parentheses pairs as well.
// if the value contains parentheses we need to balance those, to avoid iterating
// in the middle of parentheses pair, so use this regular expression (a bit hard to read)
// the regexp will split by comma, but honor parentheses pair that may include commas
// as well, eg if value = "bean=foo?method=killer(a,b),bean=bar?method=great(a,b)"
// then the regexp will split that into two:
// -> bean=foo?method=killer(a,b)
// -> bean=bar?method=great(a,b)
// http://stackoverflow.com/questions/1516090/splitting-a-title-into-separate-parts
return () -> new Scanner(value, PARENTHESIS_PATTERN);
} else {
// optimized split string on default delimiter
int count = StringHelper.countChar(value, DEFAULT_DELIMITER_CHAR) + 1;
return () -> StringHelper.splitOnCharacterAsIterator(value, DEFAULT_DELIMITER_CHAR, count);
}
} else if (pattern) {
return () -> new StringIteratorForPattern(value, delimiter);
}
return () -> new StringIterator(value, delimiter);
} else if (allowEmptyValues || org.apache.camel.util.ObjectHelper.isNotEmpty(value)) {
return Collections.singletonList(value);
} else {
return Collections.emptyList();
}
}
/**
* Creates an iterator over the value if the value is a {@link Stream}, collection, an Object[], a String with
* values separated by comma, or a primitive type array; otherwise to simplify the caller's code, we just create a
* singleton collection iterator over a single value
*
* Will default use comma for String separating String values. This method does not allow empty values
*
* @param value the value
* @return the iterator
*/
public static Iterator> createIterator(Object value) {
return createIterator(value, DEFAULT_DELIMITER);
}
/**
* Creates an iterator over the value if the value is a {@link Stream}, collection, an Object[], a String with
* values separated by the given delimiter, or a primitive type array; otherwise to simplify the caller's code, we
* just create a singleton collection iterator over a single value
*
* This method does not allow empty values
*
* @param value the value
* @param delimiter delimiter for separating String values
* @return the iterator
*/
public static Iterator> createIterator(Object value, String delimiter) {
return createIterator(value, delimiter, false);
}
/**
* Creates an iterator over the value if the value is a {@link Stream}, collection, an Object[], a String with
* values separated by the given delimiter, or a primitive type array; otherwise to simplify the caller's code, we
* just create a singleton collection iterator over a single value
*
*
* In case of primitive type arrays the returned {@code Iterator} iterates over the corresponding Java primitive
* wrapper objects of the given elements inside the {@code value} array. That's we get an autoboxing of the
* primitive types here for free as it's also the case in Java language itself.
*
* @param value the value
* @param delimiter delimiter for separating String values
* @param allowEmptyValues whether to allow empty values
* @return the iterator
*/
public static Iterator> createIterator(Object value, String delimiter, boolean allowEmptyValues) {
if (value instanceof Stream stream) {
return stream.iterator();
}
return createIterable(value, delimiter, allowEmptyValues, false).iterator();
}
/**
* Creates an iterator over the value if the value is a {@link Stream}, collection, an Object[], a String with
* values separated by the given delimiter, or a primitive type array; otherwise to simplify the caller's code, we
* just create a singleton collection iterator over a single value
*
*
* In case of primitive type arrays the returned {@code Iterator} iterates over the corresponding Java primitive
* wrapper objects of the given elements inside the {@code value} array. That's we get an autoboxing of the
* primitive types here for free as it's also the case in Java language itself.
*
* @param value the value
* @param delimiter delimiter for separating String values
* @param allowEmptyValues whether to allow empty values
* @param pattern whether the delimiter is a pattern
* @return the iterator
*/
public static Iterator> createIterator(
Object value, String delimiter,
boolean allowEmptyValues, boolean pattern) {
if (value instanceof Stream stream) {
return stream.iterator();
}
return createIterable(value, delimiter, allowEmptyValues, pattern).iterator();
}
/**
* Creates an iterable over the value if the value is a collection, an Object[], a String with values separated by
* the given delimiter, or a primitive type array; otherwise to simplify the caller's code, we just create a
* singleton collection iterator over a single value
*
*
* In case of primitive type arrays the returned {@code Iterable} iterates over the corresponding Java primitive
* wrapper objects of the given elements inside the {@code value} array. That's we get an autoboxing of the
* primitive types here for free as it's also the case in Java language itself.
*
* @param value the value
* @param delimiter delimiter for separating String values
* @param allowEmptyValues whether to allow empty values
* @return the iterable
* @see Iterable
*/
public static Iterable> createIterable(
Object value, String delimiter,
final boolean allowEmptyValues) {
return createIterable(value, delimiter, allowEmptyValues, false);
}
/**
* Creates an iterable over the value if the value is a collection, an Object[], a String with values separated by
* the given delimiter, or a primitive type array; otherwise to simplify the caller's code, we just create a
* singleton collection iterator over a single value
*
* In case of primitive type arrays the returned {@code Iterable} iterates over the corresponding Java primitive
* wrapper objects of the given elements inside the {@code value} array. That's we get an autoboxing of the
* primitive types here for free as it's also the case in Java language itself.
*
* @param value the value
* @param delimiter delimiter for separating String values
* @param allowEmptyValues whether to allow empty values
* @param pattern whether the delimiter is a pattern
* @return the iterable
* @see Iterable
*/
public static Iterable> createIterable(
Object value, String delimiter,
final boolean allowEmptyValues, final boolean pattern) {
// if its a message than we want to iterate its body
if (value instanceof Message message) {
value = message.getBody();
}
if (value == null) {
return Collections.emptyList();
}
if (fastStringCheck(value)) {
return createStringIterator((String) value, delimiter, allowEmptyValues, pattern);
}
if (fastIsMap(value)) {
Map, ?> map = (Map, ?>) value;
return map.entrySet();
}
if (value.getClass().isArray()) {
return createArrayIterator(value);
}
return trySlowIterables(value);
}
@SuppressWarnings("unchecked")
private static Iterable> trySlowIterables(Object value) {
if (value instanceof Iterator) {
final Iterator
© 2015 - 2025 Weber Informatics LLC | Privacy Policy