From ccaab5d0b312b28ab15833ab8f11dd809ec93aab Mon Sep 17 00:00:00 2001
From: Samuel Tardieu Operations on arrays, primitive arrays (like {@code int[]}) and
- * primitive wrapper arrays (like {@code Integer[]}). This class tries to handle {@code null} input gracefully.
- * An exception will not be thrown for a {@code null}
- * array input. However, an Object array that contains a {@code null}
- * element may throw an exception. Each method documents its behaviour. #ThreadSafe# ArrayUtils instances should NOT be constructed in standard programming.
- * Instead, the class should be used as This constructor is public to permit tools that require a JavaBean instance
- * to operate. Outputs an array as a String, treating {@code null} as an empty array. Multi-dimensional arrays are handled correctly, including
- * multi-dimensional primitive arrays. The format is that of Java source code, for example Outputs an array as a String handling {@code null}s. Multi-dimensional arrays are handled correctly, including
- * multi-dimensional primitive arrays. The format is that of Java source code, for example Get a hash code for an array handling multi-dimensional arrays correctly. Multi-dimensional primitive arrays are also handled correctly by this method. Compares two arrays, using equals(), handling multi-dimensional arrays
- * correctly. Multi-dimensional primitive arrays are also handled correctly by this method. Converts the given array into a {@link java.util.Map}. Each element of the array
- * must be either a {@link java.util.Map.Entry} or an Array, containing at least two
- * elements, where the first element is used as key and the second as
- * value. This method can be used to initialize: This method returns {@code null} for a {@code null} input array.ArrayUtils.clone(new int[] {2}). is OK
-
-
- // Basic methods handling multi-dimensional arrays
- //-----------------------------------------------------------------------
- /**
- * {a,b}.{a,b}.
- * // Create a Map mapping colors.
- * Map colorMap = MapUtils.toMap(new String[][] {{
- * {"RED", "#FF0000"},
- * {"GREEN", "#00FF00"},
- * {"BLUE", "#0000FF"}});
- *
- *
- *
Operates on classes without using reflection.
+ * + *This class handles invalid {@code null} inputs as best it can. + * Each method documents its behaviour in more detail.
+ * + *The notion of a {@code canonical name} includes the human + * readable name for the type, for example {@code int[]}. The + * non-canonical method variants work with the JVM names, such as + * {@code [I}.
+ * + * @since 2.0 + * @version $Id: ClassUtils.java 1145035 2011-07-11 06:09:39Z bayard $ + */ +public class ClassUtils { + + /** + *The package separator character: '.' == {@value}.
The package separator String: {@code "."}.
+ */ + public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR); + + /** + *The inner class separator character: '$' == {@value}.
The inner class separator String: {@code "$"}.
+ */ + public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR); + + /** + * Maps primitive {@code Class}es to their corresponding wrapper {@code Class}. + */ + private static final MapClassUtils instances should NOT be constructed in standard programming. + * Instead, the class should be used as + * {@code ClassUtils.getShortClassName(cls)}.
+ * + *This constructor is public to permit tools that require a JavaBean + * instance to operate.
+ */ + public ClassUtils() { + super(); + } + + // Short class name + // ---------------------------------------------------------------------- + /** + *Gets the class name minus the package name for an {@code Object}.
+ * + * @param object the class to get the short name for, may be null + * @param valueIfNull the value to return if null + * @return the class name of the object without the package name, or the null value + */ + public static String getShortClassName(Object object, String valueIfNull) { + if (object == null) { + return valueIfNull; + } + return getShortClassName(object.getClass()); + } + + /** + *Gets the class name minus the package name from a {@code Class}.
+ * + *Consider using the Java 5 API {@link Class#getSimpleName()} instead. + * The one known difference is that this code will return {@code "Map.Entry"} while + * the {@code java.lang.Class} variant will simply return {@code "Entry"}.
+ * + * @param cls the class to get the short name for. + * @return the class name without the package name or an empty string + */ + public static String getShortClassName(Class> cls) { + if (cls == null) { + return StringUtils.EMPTY; + } + return getShortClassName(cls.getName()); + } + + /** + *Gets the class name minus the package name from a String.
+ * + *The string passed in is assumed to be a class name - it is not checked.
+ + *Note that this method differs from Class.getSimpleName() in that this will + * return {@code "Map.Entry"} whilst the {@code java.lang.Class} variant will simply + * return {@code "Entry"}.
+ * + * @param className the className to get the short name for + * @return the class name of the class without the package name or an empty string + */ + public static String getShortClassName(String className) { + if (className == null) { + return StringUtils.EMPTY; + } + if (className.length() == 0) { + return StringUtils.EMPTY; + } + + StringBuilder arrayPrefix = new StringBuilder(); + + // Handle array encoding + if (className.startsWith("[")) { + while (className.charAt(0) == '[') { + className = className.substring(1); + arrayPrefix.append("[]"); + } + // Strip Object type encoding + if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { + className = className.substring(1, className.length() - 1); + } + } + + if (reverseAbbreviationMap.containsKey(className)) { + className = reverseAbbreviationMap.get(className); + } + + int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); + int innerIdx = className.indexOf( + INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1); + String out = className.substring(lastDotIdx + 1); + if (innerIdx != -1) { + out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR); + } + return out + arrayPrefix; + } + + /** + *Null-safe version of aClass.getSimpleName()
Null-safe version of aClass.getSimpleName()
object is null
+ * @return the simple class name.
+ * @since 3.0
+ * @see Class#getSimpleName()
+ */
+ public static String getSimpleName(Object object, String valueIfNull) {
+ if (object == null) {
+ return valueIfNull;
+ }
+ return getSimpleName(object.getClass());
+ }
+
+ // Package name
+ // ----------------------------------------------------------------------
+ /**
+ * Gets the package name of an {@code Object}.
+ * + * @param object the class to get the package name for, may be null + * @param valueIfNull the value to return if null + * @return the package name of the object, or the null value + */ + public static String getPackageName(Object object, String valueIfNull) { + if (object == null) { + return valueIfNull; + } + return getPackageName(object.getClass()); + } + + /** + *Gets the package name of a {@code Class}.
+ * + * @param cls the class to get the package name for, may be {@code null}. + * @return the package name or an empty string + */ + public static String getPackageName(Class> cls) { + if (cls == null) { + return StringUtils.EMPTY; + } + return getPackageName(cls.getName()); + } + + /** + *Gets the package name from a {@code String}.
+ * + *The string passed in is assumed to be a class name - it is not checked.
+ *If the class is unpackaged, return an empty string.
+ * + * @param className the className to get the package name for, may be {@code null} + * @return the package name or an empty string + */ + public static String getPackageName(String className) { + if (className == null || className.length() == 0) { + return StringUtils.EMPTY; + } + + // Strip array encoding + while (className.charAt(0) == '[') { + className = className.substring(1); + } + // Strip Object type encoding + if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { + className = className.substring(1); + } + + int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); + if (i == -1) { + return StringUtils.EMPTY; + } + return className.substring(0, i); + } + + // Superclasses/Superinterfaces + // ---------------------------------------------------------------------- + /** + *Gets a {@code List} of superclasses for the given class.
+ * + * @param cls the class to look up, may be {@code null} + * @return the {@code List} of superclasses in order going up from this one + * {@code null} if null input + */ + public static ListGets a {@code List} of all interfaces implemented by the given + * class and its superclasses.
+ * + *The order is determined by looking through each interface in turn as + * declared in the source file and following its hierarchy up. Then each + * superclass is considered in the same way. Later duplicates are ignored, + * so the order is maintained.
+ * + * @param cls the class to look up, may be {@code null} + * @return the {@code List} of interfaces in order, + * {@code null} if null input + */ + public static ListGiven a {@code List} of class names, this method converts them into classes.
+ * + *A new {@code List} is returned. If the class name cannot be found, {@code null} + * is stored in the {@code List}. If the class name in the {@code List} is + * {@code null}, {@code null} is stored in the output {@code List}.
+ * + * @param classNames the classNames to change + * @return a {@code List} of Class objects corresponding to the class names, + * {@code null} if null input + * @throws ClassCastException if classNames contains a non String entry + */ + public static ListGiven a {@code List} of {@code Class} objects, this method converts + * them into class names.
+ * + *A new {@code List} is returned. {@code null} objects will be copied into + * the returned list as {@code null}.
+ * + * @param classes the classes to change + * @return a {@code List} of class names corresponding to the Class objects, + * {@code null} if null input + * @throws ClassCastException if {@code classes} contains a non-{@code Class} entry + */ + public static ListChecks if an array of Classes can be assigned to another array of Classes.
+ * + *This method calls {@link #isAssignable(Class, Class) isAssignable} for each + * Class pair in the input arrays. It can be used to check if a set of arguments + * (the first parameter) are suitably compatible with a set of method parameter types + * (the second parameter).
+ * + *Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this + * method takes into account widenings of primitive classes and + * {@code null}s.
+ * + *Primitive widenings allow an int to be assigned to a {@code long}, + * {@code float} or {@code double}. This method returns the correct + * result for these cases.
+ * + *{@code Null} may be assigned to any reference type. This method will + * return {@code true} if {@code null} is passed in and the toClass is + * non-primitive.
+ * + *Specifically, this method tests whether the type represented by the + * specified {@code Class} parameter can be converted to the type + * represented by this {@code Class} object via an identity conversion + * widening primitive or widening reference conversion. See + * The Java Language Specification, + * sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ * + *Since Lang 3.0, this method will default behavior for + * calculating assignability between primitive and wrapper types corresponding + * to the running Java version; i.e. autoboxing will be the default + * behavior in VMs running Java versions >= 1.5.
+ * + * @param classArray the array of Classes to check, may be {@code null} + * @param toClassArray the array of Classes to try to assign into, may be {@code null} + * @return {@code true} if assignment possible + */ + public static boolean isAssignable(Class>[] classArray, Class>... toClassArray) { + return isAssignable(classArray, toClassArray, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5)); + } + + /** + *Checks if an array of Classes can be assigned to another array of Classes.
+ * + *This method calls {@link #isAssignable(Class, Class) isAssignable} for each + * Class pair in the input arrays. It can be used to check if a set of arguments + * (the first parameter) are suitably compatible with a set of method parameter types + * (the second parameter).
+ * + *Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this + * method takes into account widenings of primitive classes and + * {@code null}s.
+ * + *Primitive widenings allow an int to be assigned to a {@code long}, + * {@code float} or {@code double}. This method returns the correct + * result for these cases.
+ * + *{@code Null} may be assigned to any reference type. This method will + * return {@code true} if {@code null} is passed in and the toClass is + * non-primitive.
+ * + *Specifically, this method tests whether the type represented by the + * specified {@code Class} parameter can be converted to the type + * represented by this {@code Class} object via an identity conversion + * widening primitive or widening reference conversion. See + * The Java Language Specification, + * sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ * + * @param classArray the array of Classes to check, may be {@code null} + * @param toClassArray the array of Classes to try to assign into, may be {@code null} + * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers + * @return {@code true} if assignment possible + */ + public static boolean isAssignable(Class>[] classArray, Class>[] toClassArray, boolean autoboxing) { + if (ArrayUtils.isSameLength(classArray, toClassArray) == false) { + return false; + } + if (classArray == null) { + classArray = ArrayUtils.EMPTY_CLASS_ARRAY; + } + if (toClassArray == null) { + toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY; + } + for (int i = 0; i < classArray.length; i++) { + if (isAssignable(classArray[i], toClassArray[i], autoboxing) == false) { + return false; + } + } + return true; + } + + /** + *Checks if one {@code Class} can be assigned to a variable of + * another {@code Class}.
+ * + *Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, + * this method takes into account widenings of primitive classes and + * {@code null}s.
+ * + *Primitive widenings allow an int to be assigned to a long, float or + * double. This method returns the correct result for these cases.
+ * + *{@code Null} may be assigned to any reference type. This method + * will return {@code true} if {@code null} is passed in and the + * toClass is non-primitive.
+ * + *Specifically, this method tests whether the type represented by the + * specified {@code Class} parameter can be converted to the type + * represented by this {@code Class} object via an identity conversion + * widening primitive or widening reference conversion. See + * The Java Language Specification, + * sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ * + *Since Lang 3.0, this method will default behavior for + * calculating assignability between primitive and wrapper types corresponding + * to the running Java version; i.e. autoboxing will be the default + * behavior in VMs running Java versions >= 1.5.
+ * + * @param cls the Class to check, may be null + * @param toClass the Class to try to assign into, returns false if null + * @return {@code true} if assignment possible + */ + public static boolean isAssignable(Class> cls, Class> toClass) { + return isAssignable(cls, toClass, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5)); + } + + /** + *Checks if one {@code Class} can be assigned to a variable of + * another {@code Class}.
+ * + *Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, + * this method takes into account widenings of primitive classes and + * {@code null}s.
+ * + *Primitive widenings allow an int to be assigned to a long, float or + * double. This method returns the correct result for these cases.
+ * + *{@code Null} may be assigned to any reference type. This method + * will return {@code true} if {@code null} is passed in and the + * toClass is non-primitive.
+ * + *Specifically, this method tests whether the type represented by the + * specified {@code Class} parameter can be converted to the type + * represented by this {@code Class} object via an identity conversion + * widening primitive or widening reference conversion. See + * The Java Language Specification, + * sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ * + * @param cls the Class to check, may be null + * @param toClass the Class to try to assign into, returns false if null + * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers + * @return {@code true} if assignment possible + */ + public static boolean isAssignable(Class> cls, Class> toClass, boolean autoboxing) { + if (toClass == null) { + return false; + } + // have to check for null, as isAssignableFrom doesn't + if (cls == null) { + return !(toClass.isPrimitive()); + } + //autoboxing: + if (autoboxing) { + if (cls.isPrimitive() && !toClass.isPrimitive()) { + cls = primitiveToWrapper(cls); + if (cls == null) { + return false; + } + } + if (toClass.isPrimitive() && !cls.isPrimitive()) { + cls = wrapperToPrimitive(cls); + if (cls == null) { + return false; + } + } + } + if (cls.equals(toClass)) { + return true; + } + if (cls.isPrimitive()) { + if (toClass.isPrimitive() == false) { + return false; + } + if (Integer.TYPE.equals(cls)) { + return Long.TYPE.equals(toClass) + || Float.TYPE.equals(toClass) + || Double.TYPE.equals(toClass); + } + if (Long.TYPE.equals(cls)) { + return Float.TYPE.equals(toClass) + || Double.TYPE.equals(toClass); + } + if (Boolean.TYPE.equals(cls)) { + return false; + } + if (Double.TYPE.equals(cls)) { + return false; + } + if (Float.TYPE.equals(cls)) { + return Double.TYPE.equals(toClass); + } + if (Character.TYPE.equals(cls)) { + return Integer.TYPE.equals(toClass) + || Long.TYPE.equals(toClass) + || Float.TYPE.equals(toClass) + || Double.TYPE.equals(toClass); + } + if (Short.TYPE.equals(cls)) { + return Integer.TYPE.equals(toClass) + || Long.TYPE.equals(toClass) + || Float.TYPE.equals(toClass) + || Double.TYPE.equals(toClass); + } + if (Byte.TYPE.equals(cls)) { + return Short.TYPE.equals(toClass) + || Integer.TYPE.equals(toClass) + || Long.TYPE.equals(toClass) + || Float.TYPE.equals(toClass) + || Double.TYPE.equals(toClass); + } + // should never get here + return false; + } + return toClass.isAssignableFrom(cls); + } + + /** + *Converts the specified primitive Class object to its corresponding + * wrapper Class object.
+ * + *NOTE: From v2.2, this method handles {@code Void.TYPE}, + * returning {@code Void.TYPE}.
+ * + * @param cls the class to convert, may be null + * @return the wrapper class for {@code cls} or {@code cls} if + * {@code cls} is not a primitive. {@code null} if null input. + * @since 2.1 + */ + public static Class> primitiveToWrapper(Class> cls) { + Class> convertedClass = cls; + if (cls != null && cls.isPrimitive()) { + convertedClass = primitiveWrapperMap.get(cls); + } + return convertedClass; + } + + /** + *Converts the specified array of primitive Class objects to an array of + * its corresponding wrapper Class objects.
+ * + * @param classes the class array to convert, may be null or empty + * @return an array which contains for each given class, the wrapper class or + * the original class if class is not a primitive. {@code null} if null input. + * Empty array if an empty array passed in. + * @since 2.1 + */ + public static Class>[] primitivesToWrappers(Class>... classes) { + if (classes == null) { + return null; + } + + if (classes.length == 0) { + return classes; + } + + Class>[] convertedClasses = new Class[classes.length]; + for (int i = 0; i < classes.length; i++) { + convertedClasses[i] = primitiveToWrapper(classes[i]); + } + return convertedClasses; + } + + /** + *Converts the specified wrapper class to its corresponding primitive + * class.
+ * + *This method is the counter part of {@code primitiveToWrapper()}. + * If the passed in class is a wrapper class for a primitive type, this + * primitive type will be returned (e.g. {@code Integer.TYPE} for + * {@code Integer.class}). For other classes, or if the parameter is + * null, the return value is null.
+ * + * @param cls the class to convert, may be null + * @return the corresponding primitive type if {@code cls} is a + * wrapper class, null otherwise + * @see #primitiveToWrapper(Class) + * @since 2.4 + */ + public static Class> wrapperToPrimitive(Class> cls) { + return wrapperPrimitiveMap.get(cls); + } + + /** + *Converts the specified array of wrapper Class objects to an array of + * its corresponding primitive Class objects.
+ * + *This method invokes {@code wrapperToPrimitive()} for each element + * of the passed in array.
+ * + * @param classes the class array to convert, may be null or empty + * @return an array which contains for each given class, the primitive class or + * null if the original class is not a wrapper class. {@code null} if null input. + * Empty array if an empty array passed in. + * @see #wrapperToPrimitive(Class) + * @since 2.4 + */ + public static Class>[] wrappersToPrimitives(Class>... classes) { + if (classes == null) { + return null; + } + + if (classes.length == 0) { + return classes; + } + + Class>[] convertedClasses = new Class[classes.length]; + for (int i = 0; i < classes.length; i++) { + convertedClasses[i] = wrapperToPrimitive(classes[i]); + } + return convertedClasses; + } + + // Inner class + // ---------------------------------------------------------------------- + /** + *Is the specified class an inner class or static nested class.
+ * + * @param cls the class to check, may be null + * @return {@code true} if the class is an inner or static nested class, + * false if not or {@code null} + */ + public static boolean isInnerClass(Class> cls) { + return cls != null && cls.getEnclosingClass() != null; + } + + // Class loading + // ---------------------------------------------------------------------- + /** + * Returns the class represented by {@code className} using the + * {@code classLoader}. This implementation supports the syntaxes + * "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}", + * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}". + * + * @param classLoader the class loader to use to load the class + * @param className the class name + * @param initialize whether the class must be initialized + * @return the class represented by {@code className} using the {@code classLoader} + * @throws ClassNotFoundException if the class is not found + */ + public static Class> getClass( + ClassLoader classLoader, String className, boolean initialize) throws ClassNotFoundException { + try { + Class> clazz; + if (abbreviationMap.containsKey(className)) { + String clsName = "[" + abbreviationMap.get(className); + clazz = Class.forName(clsName, initialize, classLoader).getComponentType(); + } else { + clazz = Class.forName(toCanonicalName(className), initialize, classLoader); + } + return clazz; + } catch (ClassNotFoundException ex) { + // allow path separators (.) as inner class name separators + int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); + + if (lastDotIndex != -1) { + try { + return getClass(classLoader, className.substring(0, lastDotIndex) + + INNER_CLASS_SEPARATOR_CHAR + className.substring(lastDotIndex + 1), + initialize); + } catch (ClassNotFoundException ex2) { // NOPMD + // ignore exception + } + } + + throw ex; + } + } + + /** + * Returns the (initialized) class represented by {@code className} + * using the {@code classLoader}. This implementation supports + * the syntaxes "{@code java.util.Map.Entry[]}", + * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}", + * and "{@code [Ljava.util.Map$Entry;}". + * + * @param classLoader the class loader to use to load the class + * @param className the class name + * @return the class represented by {@code className} using the {@code classLoader} + * @throws ClassNotFoundException if the class is not found + */ + public static Class> getClass(ClassLoader classLoader, String className) throws ClassNotFoundException { + return getClass(classLoader, className, true); + } + + /** + * Returns the (initialized) class represented by {@code className} + * using the current thread's context class loader. This implementation + * supports the syntaxes "{@code java.util.Map.Entry[]}", + * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}", + * and "{@code [Ljava.util.Map$Entry;}". + * + * @param className the class name + * @return the class represented by {@code className} using the current thread's context class loader + * @throws ClassNotFoundException if the class is not found + */ + public static Class> getClass(String className) throws ClassNotFoundException { + return getClass(className, true); + } + + /** + * Returns the class represented by {@code className} using the + * current thread's context class loader. This implementation supports the + * syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}", + * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}". + * + * @param className the class name + * @param initialize whether the class must be initialized + * @return the class represented by {@code className} using the current thread's context class loader + * @throws ClassNotFoundException if the class is not found + */ + public static Class> getClass(String className, boolean initialize) throws ClassNotFoundException { + ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); + ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL; + return getClass(loader, className, initialize ); + } + + // Public method + // ---------------------------------------------------------------------- + /** + *Returns the desired Method much like {@code Class.getMethod}, however
+ * it ensures that the returned Method is from a public class or interface and not
+ * from an anonymous inner class. This means that the Method is invokable and
+ * doesn't fall foul of Java bug
+ * 4071957).
+ *
+ *
+ * Set set = Collections.unmodifiableSet(...);
+ * Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty", new Class[0]);
+ * Object result = method.invoke(set, new Object[]);
Converts an array of {@code Object} in to an array of {@code Class} objects. + * If any of these objects is null, a null element will be inserted into the array.
+ * + *This method returns {@code null} for a {@code null} input array.
+ * + * @param array an {@code Object} array + * @return a {@code Class} array, {@code null} if null array input + * @since 2.4 + */ + public static Class>[] toClass(Object... array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return ArrayUtils.EMPTY_CLASS_ARRAY; + } + Class>[] classes = new Class[array.length]; + for (int i = 0; i < array.length; i++) { + classes[i] = array[i] == null ? null : array[i].getClass(); + } + return classes; + } + + // Short canonical name + // ---------------------------------------------------------------------- + /** + *Gets the canonical name minus the package name for an {@code Object}.
+ * + * @param object the class to get the short name for, may be null + * @param valueIfNull the value to return if null + * @return the canonical name of the object without the package name, or the null value + * @since 2.4 + */ + public static String getShortCanonicalName(Object object, String valueIfNull) { + if (object == null) { + return valueIfNull; + } + return getShortCanonicalName(object.getClass().getName()); + } + + /** + *Gets the canonical name minus the package name from a {@code Class}.
+ * + * @param cls the class to get the short name for. + * @return the canonical name without the package name or an empty string + * @since 2.4 + */ + public static String getShortCanonicalName(Class> cls) { + if (cls == null) { + return StringUtils.EMPTY; + } + return getShortCanonicalName(cls.getName()); + } + + /** + *Gets the canonical name minus the package name from a String.
+ * + *The string passed in is assumed to be a canonical name - it is not checked.
+ * + * @param canonicalName the class name to get the short name for + * @return the canonical name of the class without the package name or an empty string + * @since 2.4 + */ + public static String getShortCanonicalName(String canonicalName) { + return ClassUtils.getShortClassName(getCanonicalName(canonicalName)); + } + + // Package name + // ---------------------------------------------------------------------- + /** + *Gets the package name from the canonical name of an {@code Object}.
+ * + * @param object the class to get the package name for, may be null + * @param valueIfNull the value to return if null + * @return the package name of the object, or the null value + * @since 2.4 + */ + public static String getPackageCanonicalName(Object object, String valueIfNull) { + if (object == null) { + return valueIfNull; + } + return getPackageCanonicalName(object.getClass().getName()); + } + + /** + *Gets the package name from the canonical name of a {@code Class}.
+ * + * @param cls the class to get the package name for, may be {@code null}. + * @return the package name or an empty string + * @since 2.4 + */ + public static String getPackageCanonicalName(Class> cls) { + if (cls == null) { + return StringUtils.EMPTY; + } + return getPackageCanonicalName(cls.getName()); + } + + /** + *Gets the package name from the canonical name.
+ * + *The string passed in is assumed to be a canonical name - it is not checked.
+ *If the class is unpackaged, return an empty string.
+ * + * @param canonicalName the canonical name to get the package name for, may be {@code null} + * @return the package name or an empty string + * @since 2.4 + */ + public static String getPackageCanonicalName(String canonicalName) { + return ClassUtils.getPackageName(getCanonicalName(canonicalName)); + } + + /** + *Converts a given name of class into canonical format. + * If name of class is not a name of array class it returns + * unchanged name.
+ *Example: + *
An enum representing all the versions of the Java specification. - * This is intended to mirror available values from the - * java.specification.version System property.
- * - * @since 3.0 - * @version $Id: $ - */ -public enum JavaVersion { - - /** - * The Java version reported by Android. This is not an official Java version number. - */ - JAVA_0_9(1.5f, "0.9"), - - /** - * Java 1.1. - */ - JAVA_1_1(1.1f, "1.1"), - - /** - * Java 1.2. - */ - JAVA_1_2(1.2f, "1.2"), - - /** - * Java 1.3. - */ - JAVA_1_3(1.3f, "1.3"), - - /** - * Java 1.4. - */ - JAVA_1_4(1.4f, "1.4"), - - /** - * Java 1.5. - */ - JAVA_1_5(1.5f, "1.5"), - - /** - * Java 1.6. - */ - JAVA_1_6(1.6f, "1.6"), - - /** - * Java 1.7. - */ - JAVA_1_7(1.7f, "1.7"), - - /** - * Java 1.8. - */ - JAVA_1_8(1.8f, "1.8"); - - /** - * The float value. - */ - private float value; - /** - * The standard name. - */ - private String name; - - /** - * Constructor. - * - * @param value the float value - * @param name the standard name, not null - */ - JavaVersion(final float value, final String name) { - this.value = value; - this.name = name; - } - - //----------------------------------------------------------------------- - /** - *Whether this version of Java is at least the version of Java passed in.
- * - *For example:
- * {@code myVersion.atLeast(JavaVersion.JAVA_1_4)}
- * - * @param requiredVersion the version to check against, not null - * @return true if this version is equal to or greater than the specified version - */ - public boolean atLeast(JavaVersion requiredVersion) { - return this.value >= requiredVersion.value; - } - - /** - * Transforms the given string with a Java version number to the - * corresponding constant of this enumeration class. This method is used - * internally. - * - * @param nom the Java version as string - * @return the corresponding enumeration constant or null if the - * version is unknown - */ - // helper for static importing - static JavaVersion getJavaVersion(final String nom) { - return get(nom); - } - - /** - * Transforms the given string with a Java version number to the - * corresponding constant of this enumeration class. This method is used - * internally. - * - * @param nom the Java version as string - * @return the corresponding enumeration constant or null if the - * version is unknown - */ - static JavaVersion get(final String nom) { - if ("0.9".equals(nom)) { - return JAVA_0_9; - } else if ("1.1".equals(nom)) { - return JAVA_1_1; - } else if ("1.2".equals(nom)) { - return JAVA_1_2; - } else if ("1.3".equals(nom)) { - return JAVA_1_3; - } else if ("1.4".equals(nom)) { - return JAVA_1_4; - } else if ("1.5".equals(nom)) { - return JAVA_1_5; - } else if ("1.6".equals(nom)) { - return JAVA_1_6; - } else if ("1.7".equals(nom)) { - return JAVA_1_7; - } else if ("1.8".equals(nom)) { - return JAVA_1_8; - } else { - return null; - } - } - - //----------------------------------------------------------------------- - /** - *
The string value is overridden to return the standard name.
- * - *For example, "1.5".
An enum representing all the versions of the Java specification. + * This is intended to mirror available values from the + * java.specification.version System property.
+ * + * @since 3.0 + * @version $Id: $ + */ +public enum JavaVersion { + + /** + * The Java version reported by Android. This is not an official Java version number. + */ + JAVA_0_9(1.5f, "0.9"), + + /** + * Java 1.1. + */ + JAVA_1_1(1.1f, "1.1"), + + /** + * Java 1.2. + */ + JAVA_1_2(1.2f, "1.2"), + + /** + * Java 1.3. + */ + JAVA_1_3(1.3f, "1.3"), + + /** + * Java 1.4. + */ + JAVA_1_4(1.4f, "1.4"), + + /** + * Java 1.5. + */ + JAVA_1_5(1.5f, "1.5"), + + /** + * Java 1.6. + */ + JAVA_1_6(1.6f, "1.6"), + + /** + * Java 1.7. + */ + JAVA_1_7(1.7f, "1.7"), + + /** + * Java 1.8. + */ + JAVA_1_8(1.8f, "1.8"); + + /** + * The float value. + */ + private float value; + /** + * The standard name. + */ + private String name; + + /** + * Constructor. + * + * @param value the float value + * @param name the standard name, not null + */ + JavaVersion(final float value, final String name) { + this.value = value; + this.name = name; + } + + //----------------------------------------------------------------------- + /** + *Whether this version of Java is at least the version of Java passed in.
+ * + *For example:
+ * {@code myVersion.atLeast(JavaVersion.JAVA_1_4)}
+ * + * @param requiredVersion the version to check against, not null + * @return true if this version is equal to or greater than the specified version + */ + public boolean atLeast(JavaVersion requiredVersion) { + return this.value >= requiredVersion.value; + } + + /** + * Transforms the given string with a Java version number to the + * corresponding constant of this enumeration class. This method is used + * internally. + * + * @param nom the Java version as string + * @return the corresponding enumeration constant or null if the + * version is unknown + */ + // helper for static importing + static JavaVersion getJavaVersion(final String nom) { + return get(nom); + } + + /** + * Transforms the given string with a Java version number to the + * corresponding constant of this enumeration class. This method is used + * internally. + * + * @param nom the Java version as string + * @return the corresponding enumeration constant or null if the + * version is unknown + */ + static JavaVersion get(final String nom) { + if ("0.9".equals(nom)) { + return JAVA_0_9; + } else if ("1.1".equals(nom)) { + return JAVA_1_1; + } else if ("1.2".equals(nom)) { + return JAVA_1_2; + } else if ("1.3".equals(nom)) { + return JAVA_1_3; + } else if ("1.4".equals(nom)) { + return JAVA_1_4; + } else if ("1.5".equals(nom)) { + return JAVA_1_5; + } else if ("1.6".equals(nom)) { + return JAVA_1_6; + } else if ("1.7".equals(nom)) { + return JAVA_1_7; + } else if ("1.8".equals(nom)) { + return JAVA_1_8; + } else { + return null; + } + } + + //----------------------------------------------------------------------- + /** + *
The string value is overridden to return the standard name.
+ * + *For example, "1.5".
Operations on {@code Object}.
- * - *This class tries to handle {@code null} input gracefully. - * An exception will generally not be thrown for a {@code null} input. - * Each method documents its behaviour in more detail.
- * - *#ThreadSafe#
- * @since 1.0 - * @version $Id: ObjectUtils.java 1153350 2011-08-03 05:29:21Z bayard $ - */ -//@Immutable -public class ObjectUtils { - - /** - *Singleton used as a {@code null} placeholder where - * {@code null} has another meaning.
- * - *For example, in a {@code HashMap} the - * {@link java.util.HashMap#get(java.lang.Object)} method returns - * {@code null} if the {@code Map} contains {@code null} or if there - * is no matching key. The {@code Null} placeholder can be used to - * distinguish between these two cases.
- * - *Another example is {@code Hashtable}, where {@code null} - * cannot be stored.
- * - *This instance is Serializable.
- */ - public static final Null NULL = new Null(); - - /** - *{@code ObjectUtils} instances should NOT be constructed in - * standard programming. Instead, the static methods on the class should - * be used, such as {@code ObjectUtils.defaultIfNull("a","b");}.
- * - *This constructor is public to permit tools that require a JavaBean - * instance to operate.
- */ - public ObjectUtils() { - super(); - } - - // Defaulting - //----------------------------------------------------------------------- - /** - *Returns a default value if the object passed is {@code null}.
- * - *
- * ObjectUtils.defaultIfNull(null, null) = null
- * ObjectUtils.defaultIfNull(null, "") = ""
- * ObjectUtils.defaultIfNull(null, "zz") = "zz"
- * ObjectUtils.defaultIfNull("abc", *) = "abc"
- * ObjectUtils.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE
- *
- *
- * @param Returns the first value in the array which is not {@code null}. - * If all the values are {@code null} or the array is {@code null} - * or empty then {@code null} is returned.
- * - *
- * ObjectUtils.firstNonNull(null, null) = null
- * ObjectUtils.firstNonNull(null, "") = ""
- * ObjectUtils.firstNonNull(null, null, "") = ""
- * ObjectUtils.firstNonNull(null, "zz") = "zz"
- * ObjectUtils.firstNonNull("abc", *) = "abc"
- * ObjectUtils.firstNonNull(null, "xyz", *) = "xyz"
- * ObjectUtils.firstNonNull(Boolean.TRUE, *) = Boolean.TRUE
- * ObjectUtils.firstNonNull() = null
- *
- *
- * @param Compares two objects for equality, where either one or both - * objects may be {@code null}.
- * - *
- * ObjectUtils.equals(null, null) = true
- * ObjectUtils.equals(null, "") = false
- * ObjectUtils.equals("", null) = false
- * ObjectUtils.equals("", "") = true
- * ObjectUtils.equals(Boolean.TRUE, null) = false
- * ObjectUtils.equals(Boolean.TRUE, "true") = false
- * ObjectUtils.equals(Boolean.TRUE, Boolean.TRUE) = true
- * ObjectUtils.equals(Boolean.TRUE, Boolean.FALSE) = false
- *
- *
- * @param object1 the first object, may be {@code null}
- * @param object2 the second object, may be {@code null}
- * @return {@code true} if the values of both objects are the same
- */
- public static boolean equals(Object object1, Object object2) {
- if (object1 == object2) {
- return true;
- }
- if ((object1 == null) || (object2 == null)) {
- return false;
- }
- return object1.equals(object2);
- }
-
- /**
- * Compares two objects for inequality, where either one or both - * objects may be {@code null}.
- * - *
- * ObjectUtils.notEqual(null, null) = false
- * ObjectUtils.notEqual(null, "") = true
- * ObjectUtils.notEqual("", null) = true
- * ObjectUtils.notEqual("", "") = false
- * ObjectUtils.notEqual(Boolean.TRUE, null) = true
- * ObjectUtils.notEqual(Boolean.TRUE, "true") = true
- * ObjectUtils.notEqual(Boolean.TRUE, Boolean.TRUE) = false
- * ObjectUtils.notEqual(Boolean.TRUE, Boolean.FALSE) = true
- *
- *
- * @param object1 the first object, may be {@code null}
- * @param object2 the second object, may be {@code null}
- * @return {@code false} if the values of both objects are the same
- */
- public static boolean notEqual(Object object1, Object object2) {
- return ObjectUtils.equals(object1, object2) == false;
- }
-
- /**
- * Gets the hash code of an object returning zero when the - * object is {@code null}.
- * - *- * ObjectUtils.hashCode(null) = 0 - * ObjectUtils.hashCode(obj) = obj.hashCode() - *- * - * @param obj the object to obtain the hash code of, may be {@code null} - * @return the hash code of the object, or zero if null - * @since 2.1 - */ - public static int hashCode(Object obj) { - // hashCode(Object) retained for performance, as hash code is often critical - return (obj == null) ? 0 : obj.hashCode(); - } - - /** - *
Gets the hash code for multiple objects.
- * - *This allows a hash code to be rapidly calculated for a number of objects. - * The hash code for a single object is the not same as {@link #hashCode(Object)}. - * The hash code for multiple objects is the same as that calculated by an - * {@code ArrayList} containing the specified objects.
- * - *- * ObjectUtils.hashCodeMulti() = 1 - * ObjectUtils.hashCodeMulti((Object[]) null) = 1 - * ObjectUtils.hashCodeMulti(a) = 31 + a.hashCode() - * ObjectUtils.hashCodeMulti(a,b) = (31 + a.hashCode()) * 31 + b.hashCode() - * ObjectUtils.hashCodeMulti(a,b,c) = ((31 + a.hashCode()) * 31 + b.hashCode()) * 31 + c.hashCode() - *- * - * @param objects the objects to obtain the hash code of, may be {@code null} - * @return the hash code of the objects, or zero if null - * @since 3.0 - */ - public static int hashCodeMulti(Object... objects) { - int hash = 1; - if (objects != null) { - for (Object object : objects) { - hash = hash * 31 + ObjectUtils.hashCode(object); - } - } - return hash; - } - - // Identity ToString - //----------------------------------------------------------------------- - /** - *
Gets the toString that would be produced by {@code Object} - * if a class did not override toString itself. {@code null} - * will return {@code null}.
- * - *
- * ObjectUtils.identityToString(null) = null
- * ObjectUtils.identityToString("") = "java.lang.String@1e23"
- * ObjectUtils.identityToString(Boolean.TRUE) = "java.lang.Boolean@7fa"
- *
- *
- * @param object the object to create a toString for, may be
- * {@code null}
- * @return the default toString text, or {@code null} if
- * {@code null} passed in
- */
- public static String identityToString(Object object) {
- if (object == null) {
- return null;
- }
- StringBuffer buffer = new StringBuffer();
- identityToString(buffer, object);
- return buffer.toString();
- }
-
- /**
- * Appends the toString that would be produced by {@code Object} - * if a class did not override toString itself. {@code null} - * will throw a NullPointerException for either of the two parameters.
- * - *
- * ObjectUtils.identityToString(buf, "") = buf.append("java.lang.String@1e23"
- * ObjectUtils.identityToString(buf, Boolean.TRUE) = buf.append("java.lang.Boolean@7fa"
- * ObjectUtils.identityToString(buf, Boolean.TRUE) = buf.append("java.lang.Boolean@7fa")
- *
- *
- * @param buffer the buffer to append to
- * @param object the object to create a toString for
- * @since 2.4
- */
- public static void identityToString(StringBuffer buffer, Object object) {
- if (object == null) {
- throw new NullPointerException("Cannot get the toString of a null identity");
- }
- buffer.append(object.getClass().getName())
- .append('@')
- .append(Integer.toHexString(System.identityHashCode(object)));
- }
-
- // ToString
- //-----------------------------------------------------------------------
- /**
- * Gets the {@code toString} of an {@code Object} returning - * an empty string ("") if {@code null} input.
- * - *
- * ObjectUtils.toString(null) = ""
- * ObjectUtils.toString("") = ""
- * ObjectUtils.toString("bat") = "bat"
- * ObjectUtils.toString(Boolean.TRUE) = "true"
- *
- *
- * @see StringUtils#defaultString(String)
- * @see String#valueOf(Object)
- * @param obj the Object to {@code toString}, may be null
- * @return the passed in Object's toString, or nullStr if {@code null} input
- * @since 2.0
- */
- public static String toString(Object obj) {
- return obj == null ? "" : obj.toString();
- }
-
- /**
- * Gets the {@code toString} of an {@code Object} returning - * a specified text if {@code null} input.
- * - *
- * ObjectUtils.toString(null, null) = null
- * ObjectUtils.toString(null, "null") = "null"
- * ObjectUtils.toString("", "null") = ""
- * ObjectUtils.toString("bat", "null") = "bat"
- * ObjectUtils.toString(Boolean.TRUE, "null") = "true"
- *
- *
- * @see StringUtils#defaultString(String,String)
- * @see String#valueOf(Object)
- * @param obj the Object to {@code toString}, may be null
- * @param nullStr the String to return if {@code null} input, may be null
- * @return the passed in Object's toString, or nullStr if {@code null} input
- * @since 2.0
- */
- public static String toString(Object obj, String nullStr) {
- return obj == null ? nullStr : obj.toString();
- }
-
- // Comparable
- //-----------------------------------------------------------------------
- /**
- * Null safe comparison of Comparables.
- * - * @paramNull safe comparison of Comparables.
- * - * @paramNull safe comparison of Comparables. - * {@code null} is assumed to be less than a non-{@code null} value.
- * - * @paramNull safe comparison of Comparables.
- * - * @paramClone an object.
- * - * @paramClone an object if possible.
- * - *This method is similar to {@link #clone(Object)}, but will return the provided - * instance as the return value instead of {@code null} if the instance - * is not cloneable. This is more convenient if the caller uses different - * implementations (e.g. of a service) and some of the implementations do not allow concurrent - * processing or have state. In such cases the implementation can simply provide a proper - * clone implementation and the caller's code does not have to change.
- * - * @paramClass used as a null placeholder where {@code null} - * has another meaning.
- * - *For example, in a {@code HashMap} the - * {@link java.util.HashMap#get(java.lang.Object)} method returns - * {@code null} if the {@code Map} contains {@code null} or if there is - * no matching key. The {@code Null} placeholder can be used to distinguish - * between these two cases.
- * - *Another example is {@code Hashtable}, where {@code null} - * cannot be stored.
- */ - public static class Null implements Serializable { - /** - * Required for serialization support. Declare serialization compatibility with Commons Lang 1.0 - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 7092611880189329093L; - - /** - * Restricted constructor - singleton. - */ - Null() { - super(); - } - - /** - *Ensure singleton.
- * - * @return the singleton value - */ - private Object readResolve() { - return ObjectUtils.NULL; - } - } - -} +/* + * 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.commons.lang3; + +import java.io.Serializable; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeSet; + +import org.apache.commons.lang3.exception.CloneFailedException; +import org.apache.commons.lang3.mutable.MutableInt; + +/** + *Operations on {@code Object}.
+ * + *This class tries to handle {@code null} input gracefully. + * An exception will generally not be thrown for a {@code null} input. + * Each method documents its behaviour in more detail.
+ * + *#ThreadSafe#
+ * @since 1.0 + * @version $Id: ObjectUtils.java 1153350 2011-08-03 05:29:21Z bayard $ + */ +//@Immutable +public class ObjectUtils { + + /** + *Singleton used as a {@code null} placeholder where + * {@code null} has another meaning.
+ * + *For example, in a {@code HashMap} the + * {@link java.util.HashMap#get(java.lang.Object)} method returns + * {@code null} if the {@code Map} contains {@code null} or if there + * is no matching key. The {@code Null} placeholder can be used to + * distinguish between these two cases.
+ * + *Another example is {@code Hashtable}, where {@code null} + * cannot be stored.
+ * + *This instance is Serializable.
+ */ + public static final Null NULL = new Null(); + + /** + *{@code ObjectUtils} instances should NOT be constructed in + * standard programming. Instead, the static methods on the class should + * be used, such as {@code ObjectUtils.defaultIfNull("a","b");}.
+ * + *This constructor is public to permit tools that require a JavaBean + * instance to operate.
+ */ + public ObjectUtils() { + super(); + } + + // Defaulting + //----------------------------------------------------------------------- + /** + *Returns a default value if the object passed is {@code null}.
+ * + *
+ * ObjectUtils.defaultIfNull(null, null) = null
+ * ObjectUtils.defaultIfNull(null, "") = ""
+ * ObjectUtils.defaultIfNull(null, "zz") = "zz"
+ * ObjectUtils.defaultIfNull("abc", *) = "abc"
+ * ObjectUtils.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE
+ *
+ *
+ * @param Returns the first value in the array which is not {@code null}. + * If all the values are {@code null} or the array is {@code null} + * or empty then {@code null} is returned.
+ * + *
+ * ObjectUtils.firstNonNull(null, null) = null
+ * ObjectUtils.firstNonNull(null, "") = ""
+ * ObjectUtils.firstNonNull(null, null, "") = ""
+ * ObjectUtils.firstNonNull(null, "zz") = "zz"
+ * ObjectUtils.firstNonNull("abc", *) = "abc"
+ * ObjectUtils.firstNonNull(null, "xyz", *) = "xyz"
+ * ObjectUtils.firstNonNull(Boolean.TRUE, *) = Boolean.TRUE
+ * ObjectUtils.firstNonNull() = null
+ *
+ *
+ * @param Compares two objects for equality, where either one or both + * objects may be {@code null}.
+ * + *
+ * ObjectUtils.equals(null, null) = true
+ * ObjectUtils.equals(null, "") = false
+ * ObjectUtils.equals("", null) = false
+ * ObjectUtils.equals("", "") = true
+ * ObjectUtils.equals(Boolean.TRUE, null) = false
+ * ObjectUtils.equals(Boolean.TRUE, "true") = false
+ * ObjectUtils.equals(Boolean.TRUE, Boolean.TRUE) = true
+ * ObjectUtils.equals(Boolean.TRUE, Boolean.FALSE) = false
+ *
+ *
+ * @param object1 the first object, may be {@code null}
+ * @param object2 the second object, may be {@code null}
+ * @return {@code true} if the values of both objects are the same
+ */
+ public static boolean equals(Object object1, Object object2) {
+ if (object1 == object2) {
+ return true;
+ }
+ if ((object1 == null) || (object2 == null)) {
+ return false;
+ }
+ return object1.equals(object2);
+ }
+
+ /**
+ * Compares two objects for inequality, where either one or both + * objects may be {@code null}.
+ * + *
+ * ObjectUtils.notEqual(null, null) = false
+ * ObjectUtils.notEqual(null, "") = true
+ * ObjectUtils.notEqual("", null) = true
+ * ObjectUtils.notEqual("", "") = false
+ * ObjectUtils.notEqual(Boolean.TRUE, null) = true
+ * ObjectUtils.notEqual(Boolean.TRUE, "true") = true
+ * ObjectUtils.notEqual(Boolean.TRUE, Boolean.TRUE) = false
+ * ObjectUtils.notEqual(Boolean.TRUE, Boolean.FALSE) = true
+ *
+ *
+ * @param object1 the first object, may be {@code null}
+ * @param object2 the second object, may be {@code null}
+ * @return {@code false} if the values of both objects are the same
+ */
+ public static boolean notEqual(Object object1, Object object2) {
+ return ObjectUtils.equals(object1, object2) == false;
+ }
+
+ /**
+ * Gets the hash code of an object returning zero when the + * object is {@code null}.
+ * + *+ * ObjectUtils.hashCode(null) = 0 + * ObjectUtils.hashCode(obj) = obj.hashCode() + *+ * + * @param obj the object to obtain the hash code of, may be {@code null} + * @return the hash code of the object, or zero if null + * @since 2.1 + */ + public static int hashCode(Object obj) { + // hashCode(Object) retained for performance, as hash code is often critical + return (obj == null) ? 0 : obj.hashCode(); + } + + /** + *
Gets the hash code for multiple objects.
+ * + *This allows a hash code to be rapidly calculated for a number of objects. + * The hash code for a single object is the not same as {@link #hashCode(Object)}. + * The hash code for multiple objects is the same as that calculated by an + * {@code ArrayList} containing the specified objects.
+ * + *+ * ObjectUtils.hashCodeMulti() = 1 + * ObjectUtils.hashCodeMulti((Object[]) null) = 1 + * ObjectUtils.hashCodeMulti(a) = 31 + a.hashCode() + * ObjectUtils.hashCodeMulti(a,b) = (31 + a.hashCode()) * 31 + b.hashCode() + * ObjectUtils.hashCodeMulti(a,b,c) = ((31 + a.hashCode()) * 31 + b.hashCode()) * 31 + c.hashCode() + *+ * + * @param objects the objects to obtain the hash code of, may be {@code null} + * @return the hash code of the objects, or zero if null + * @since 3.0 + */ + public static int hashCodeMulti(Object... objects) { + int hash = 1; + if (objects != null) { + for (Object object : objects) { + hash = hash * 31 + ObjectUtils.hashCode(object); + } + } + return hash; + } + + // Identity ToString + //----------------------------------------------------------------------- + /** + *
Gets the toString that would be produced by {@code Object} + * if a class did not override toString itself. {@code null} + * will return {@code null}.
+ * + *
+ * ObjectUtils.identityToString(null) = null
+ * ObjectUtils.identityToString("") = "java.lang.String@1e23"
+ * ObjectUtils.identityToString(Boolean.TRUE) = "java.lang.Boolean@7fa"
+ *
+ *
+ * @param object the object to create a toString for, may be
+ * {@code null}
+ * @return the default toString text, or {@code null} if
+ * {@code null} passed in
+ */
+ public static String identityToString(Object object) {
+ if (object == null) {
+ return null;
+ }
+ StringBuffer buffer = new StringBuffer();
+ identityToString(buffer, object);
+ return buffer.toString();
+ }
+
+ /**
+ * Appends the toString that would be produced by {@code Object} + * if a class did not override toString itself. {@code null} + * will throw a NullPointerException for either of the two parameters.
+ * + *
+ * ObjectUtils.identityToString(buf, "") = buf.append("java.lang.String@1e23"
+ * ObjectUtils.identityToString(buf, Boolean.TRUE) = buf.append("java.lang.Boolean@7fa"
+ * ObjectUtils.identityToString(buf, Boolean.TRUE) = buf.append("java.lang.Boolean@7fa")
+ *
+ *
+ * @param buffer the buffer to append to
+ * @param object the object to create a toString for
+ * @since 2.4
+ */
+ public static void identityToString(StringBuffer buffer, Object object) {
+ if (object == null) {
+ throw new NullPointerException("Cannot get the toString of a null identity");
+ }
+ buffer.append(object.getClass().getName())
+ .append('@')
+ .append(Integer.toHexString(System.identityHashCode(object)));
+ }
+
+ // ToString
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the {@code toString} of an {@code Object} returning + * an empty string ("") if {@code null} input.
+ * + *
+ * ObjectUtils.toString(null) = ""
+ * ObjectUtils.toString("") = ""
+ * ObjectUtils.toString("bat") = "bat"
+ * ObjectUtils.toString(Boolean.TRUE) = "true"
+ *
+ *
+ * @see StringUtils#defaultString(String)
+ * @see String#valueOf(Object)
+ * @param obj the Object to {@code toString}, may be null
+ * @return the passed in Object's toString, or nullStr if {@code null} input
+ * @since 2.0
+ */
+ public static String toString(Object obj) {
+ return obj == null ? "" : obj.toString();
+ }
+
+ /**
+ * Gets the {@code toString} of an {@code Object} returning + * a specified text if {@code null} input.
+ * + *
+ * ObjectUtils.toString(null, null) = null
+ * ObjectUtils.toString(null, "null") = "null"
+ * ObjectUtils.toString("", "null") = ""
+ * ObjectUtils.toString("bat", "null") = "bat"
+ * ObjectUtils.toString(Boolean.TRUE, "null") = "true"
+ *
+ *
+ * @see StringUtils#defaultString(String,String)
+ * @see String#valueOf(Object)
+ * @param obj the Object to {@code toString}, may be null
+ * @param nullStr the String to return if {@code null} input, may be null
+ * @return the passed in Object's toString, or nullStr if {@code null} input
+ * @since 2.0
+ */
+ public static String toString(Object obj, String nullStr) {
+ return obj == null ? nullStr : obj.toString();
+ }
+
+ // Comparable
+ //-----------------------------------------------------------------------
+ /**
+ * Null safe comparison of Comparables.
+ * + * @paramNull safe comparison of Comparables.
+ * + * @paramNull safe comparison of Comparables. + * {@code null} is assumed to be less than a non-{@code null} value.
+ * + * @paramNull safe comparison of Comparables.
+ * + * @paramClone an object.
+ * + * @paramClone an object if possible.
+ * + *This method is similar to {@link #clone(Object)}, but will return the provided + * instance as the return value instead of {@code null} if the instance + * is not cloneable. This is more convenient if the caller uses different + * implementations (e.g. of a service) and some of the implementations do not allow concurrent + * processing or have state. In such cases the implementation can simply provide a proper + * clone implementation and the caller's code does not have to change.
+ * + * @paramClass used as a null placeholder where {@code null} + * has another meaning.
+ * + *For example, in a {@code HashMap} the + * {@link java.util.HashMap#get(java.lang.Object)} method returns + * {@code null} if the {@code Map} contains {@code null} or if there is + * no matching key. The {@code Null} placeholder can be used to distinguish + * between these two cases.
+ * + *Another example is {@code Hashtable}, where {@code null} + * cannot be stored.
+ */ + public static class Null implements Serializable { + /** + * Required for serialization support. Declare serialization compatibility with Commons Lang 1.0 + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 7092611880189329093L; + + /** + * Restricted constructor - singleton. + */ + Null() { + super(); + } + + /** + *Ensure singleton.
+ * + * @return the singleton value + */ + private Object readResolve() { + return ObjectUtils.NULL; + } + } + +} diff --git a/src/org/apache/commons/lang3/StringUtils.java b/src/org/apache/commons/lang3/StringUtils.java index 9ea5de4..807f4d6 100644 --- a/src/org/apache/commons/lang3/StringUtils.java +++ b/src/org/apache/commons/lang3/StringUtils.java @@ -1,6525 +1,6525 @@ -/* - * 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.commons.lang3; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.regex.Pattern; - -/** - *Operations on {@link java.lang.String} that are - * {@code null} safe.
- * - *The {@code StringUtils} class defines certain words related to - * String handling.
- * - *{@code StringUtils} handles {@code null} input Strings quietly. - * That is to say that a {@code null} input will return {@code null}. - * Where a {@code boolean} or {@code int} is being returned - * details vary by method.
- * - *A side effect of the {@code null} handling is that a - * {@code NullPointerException} should be considered a bug in - * {@code StringUtils}.
- * - *Methods in this class give sample code to explain their operation. - * The symbol {@code *} is used to indicate any input including {@code null}.
- * - *#ThreadSafe#
- * @see java.lang.String - * @since 1.0 - * @version $Id$ - */ -//@Immutable -public class StringUtils { - // Performance testing notes (JDK 1.4, Jul03, scolebourne) - // Whitespace: - // Character.isWhitespace() is faster than WHITESPACE.indexOf() - // where WHITESPACE is a string of all whitespace characters - // - // Character access: - // String.charAt(n) versus toCharArray(), then array[n] - // String.charAt(n) is about 15% worse for a 10K string - // They are about equal for a length 50 string - // String.charAt(n) is about 4 times better for a length 3 string - // String.charAt(n) is best bet overall - // - // Append: - // String.concat about twice as fast as StringBuffer.append - // (not sure who tested this) - - /** - * The empty String {@code ""}. - * @since 2.0 - */ - public static final String EMPTY = ""; - - /** - * Represents a failed index search. - * @since 2.1 - */ - public static final int INDEX_NOT_FOUND = -1; - - /** - *The maximum size to which the padding constant(s) can expand.
- */ - private static final int PAD_LIMIT = 8192; - - /** - * A regex pattern for recognizing blocks of whitespace characters. - */ - private static final Pattern WHITESPACE_BLOCK = Pattern.compile("\\s+"); - - /** - *{@code StringUtils} instances should NOT be constructed in - * standard programming. Instead, the class should be used as - * {@code StringUtils.trim(" foo ");}.
- * - *This constructor is public to permit tools that require a JavaBean - * instance to operate.
- */ - public StringUtils() { - super(); - } - - // Empty checks - //----------------------------------------------------------------------- - /** - *Checks if a CharSequence is empty ("") or null.
- * - *
- * StringUtils.isEmpty(null) = true
- * StringUtils.isEmpty("") = true
- * StringUtils.isEmpty(" ") = false
- * StringUtils.isEmpty("bob") = false
- * StringUtils.isEmpty(" bob ") = false
- *
- *
- * NOTE: This method changed in Lang version 2.0. - * It no longer trims the CharSequence. - * That functionality is available in isBlank().
- * - * @param cs the CharSequence to check, may be null - * @return {@code true} if the CharSequence is empty or null - * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) - */ - public static boolean isEmpty(CharSequence cs) { - return cs == null || cs.length() == 0; - } - - /** - *Checks if a CharSequence is not empty ("") and not null.
- * - *
- * StringUtils.isNotEmpty(null) = false
- * StringUtils.isNotEmpty("") = false
- * StringUtils.isNotEmpty(" ") = true
- * StringUtils.isNotEmpty("bob") = true
- * StringUtils.isNotEmpty(" bob ") = true
- *
- *
- * @param cs the CharSequence to check, may be null
- * @return {@code true} if the CharSequence is not empty and not null
- * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
- */
- public static boolean isNotEmpty(CharSequence cs) {
- return !StringUtils.isEmpty(cs);
- }
-
- /**
- * Checks if a CharSequence is whitespace, empty ("") or null.
- * - *
- * StringUtils.isBlank(null) = true
- * StringUtils.isBlank("") = true
- * StringUtils.isBlank(" ") = true
- * StringUtils.isBlank("bob") = false
- * StringUtils.isBlank(" bob ") = false
- *
- *
- * @param cs the CharSequence to check, may be null
- * @return {@code true} if the CharSequence is null, empty or whitespace
- * @since 2.0
- * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
- */
- public static boolean isBlank(CharSequence cs) {
- int strLen;
- if (cs == null || (strLen = cs.length()) == 0) {
- return true;
- }
- for (int i = 0; i < strLen; i++) {
- if ((Character.isWhitespace(cs.charAt(i)) == false)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Checks if a CharSequence is not empty (""), not null and not whitespace only.
- * - *
- * StringUtils.isNotBlank(null) = false
- * StringUtils.isNotBlank("") = false
- * StringUtils.isNotBlank(" ") = false
- * StringUtils.isNotBlank("bob") = true
- * StringUtils.isNotBlank(" bob ") = true
- *
- *
- * @param cs the CharSequence to check, may be null
- * @return {@code true} if the CharSequence is
- * not empty and not null and not whitespace
- * @since 2.0
- * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
- */
- public static boolean isNotBlank(CharSequence cs) {
- return !StringUtils.isBlank(cs);
- }
-
- // Trim
- //-----------------------------------------------------------------------
- /**
- * Removes control characters (char <= 32) from both - * ends of this String, handling {@code null} by returning - * {@code null}.
- * - *The String is trimmed using {@link String#trim()}. - * Trim removes start and end characters <= 32. - * To strip whitespace use {@link #strip(String)}.
- * - *To trim your choice of characters, use the - * {@link #strip(String, String)} methods.
- * - *
- * StringUtils.trim(null) = null
- * StringUtils.trim("") = ""
- * StringUtils.trim(" ") = ""
- * StringUtils.trim("abc") = "abc"
- * StringUtils.trim(" abc ") = "abc"
- *
- *
- * @param str the String to be trimmed, may be null
- * @return the trimmed string, {@code null} if null String input
- */
- public static String trim(String str) {
- return str == null ? null : str.trim();
- }
-
- /**
- * Removes control characters (char <= 32) from both - * ends of this String returning {@code null} if the String is - * empty ("") after the trim or if it is {@code null}. - * - *
The String is trimmed using {@link String#trim()}. - * Trim removes start and end characters <= 32. - * To strip whitespace use {@link #stripToNull(String)}.
- * - *
- * StringUtils.trimToNull(null) = null
- * StringUtils.trimToNull("") = null
- * StringUtils.trimToNull(" ") = null
- * StringUtils.trimToNull("abc") = "abc"
- * StringUtils.trimToNull(" abc ") = "abc"
- *
- *
- * @param str the String to be trimmed, may be null
- * @return the trimmed String,
- * {@code null} if only chars <= 32, empty or null String input
- * @since 2.0
- */
- public static String trimToNull(String str) {
- String ts = trim(str);
- return isEmpty(ts) ? null : ts;
- }
-
- /**
- * Removes control characters (char <= 32) from both - * ends of this String returning an empty String ("") if the String - * is empty ("") after the trim or if it is {@code null}. - * - *
The String is trimmed using {@link String#trim()}. - * Trim removes start and end characters <= 32. - * To strip whitespace use {@link #stripToEmpty(String)}.
- * - *
- * StringUtils.trimToEmpty(null) = ""
- * StringUtils.trimToEmpty("") = ""
- * StringUtils.trimToEmpty(" ") = ""
- * StringUtils.trimToEmpty("abc") = "abc"
- * StringUtils.trimToEmpty(" abc ") = "abc"
- *
- *
- * @param str the String to be trimmed, may be null
- * @return the trimmed String, or an empty String if {@code null} input
- * @since 2.0
- */
- public static String trimToEmpty(String str) {
- return str == null ? EMPTY : str.trim();
- }
-
- // Stripping
- //-----------------------------------------------------------------------
- /**
- * Strips whitespace from the start and end of a String.
- * - *This is similar to {@link #trim(String)} but removes whitespace. - * Whitespace is defined by {@link Character#isWhitespace(char)}.
- * - *A {@code null} input String returns {@code null}.
- * - *
- * StringUtils.strip(null) = null
- * StringUtils.strip("") = ""
- * StringUtils.strip(" ") = ""
- * StringUtils.strip("abc") = "abc"
- * StringUtils.strip(" abc") = "abc"
- * StringUtils.strip("abc ") = "abc"
- * StringUtils.strip(" abc ") = "abc"
- * StringUtils.strip(" ab c ") = "ab c"
- *
- *
- * @param str the String to remove whitespace from, may be null
- * @return the stripped String, {@code null} if null String input
- */
- public static String strip(String str) {
- return strip(str, null);
- }
-
- /**
- * Strips whitespace from the start and end of a String returning - * {@code null} if the String is empty ("") after the strip.
- * - *This is similar to {@link #trimToNull(String)} but removes whitespace. - * Whitespace is defined by {@link Character#isWhitespace(char)}.
- * - *
- * StringUtils.stripToNull(null) = null
- * StringUtils.stripToNull("") = null
- * StringUtils.stripToNull(" ") = null
- * StringUtils.stripToNull("abc") = "abc"
- * StringUtils.stripToNull(" abc") = "abc"
- * StringUtils.stripToNull("abc ") = "abc"
- * StringUtils.stripToNull(" abc ") = "abc"
- * StringUtils.stripToNull(" ab c ") = "ab c"
- *
- *
- * @param str the String to be stripped, may be null
- * @return the stripped String,
- * {@code null} if whitespace, empty or null String input
- * @since 2.0
- */
- public static String stripToNull(String str) {
- if (str == null) {
- return null;
- }
- str = strip(str, null);
- return str.length() == 0 ? null : str;
- }
-
- /**
- * Strips whitespace from the start and end of a String returning - * an empty String if {@code null} input.
- * - *This is similar to {@link #trimToEmpty(String)} but removes whitespace. - * Whitespace is defined by {@link Character#isWhitespace(char)}.
- * - *
- * StringUtils.stripToEmpty(null) = ""
- * StringUtils.stripToEmpty("") = ""
- * StringUtils.stripToEmpty(" ") = ""
- * StringUtils.stripToEmpty("abc") = "abc"
- * StringUtils.stripToEmpty(" abc") = "abc"
- * StringUtils.stripToEmpty("abc ") = "abc"
- * StringUtils.stripToEmpty(" abc ") = "abc"
- * StringUtils.stripToEmpty(" ab c ") = "ab c"
- *
- *
- * @param str the String to be stripped, may be null
- * @return the trimmed String, or an empty String if {@code null} input
- * @since 2.0
- */
- public static String stripToEmpty(String str) {
- return str == null ? EMPTY : strip(str, null);
- }
-
- /**
- * Strips any of a set of characters from the start and end of a String. - * This is similar to {@link String#trim()} but allows the characters - * to be stripped to be controlled.
- * - *A {@code null} input String returns {@code null}. - * An empty string ("") input returns the empty string.
- * - *If the stripChars String is {@code null}, whitespace is - * stripped as defined by {@link Character#isWhitespace(char)}. - * Alternatively use {@link #strip(String)}.
- * - *
- * StringUtils.strip(null, *) = null
- * StringUtils.strip("", *) = ""
- * StringUtils.strip("abc", null) = "abc"
- * StringUtils.strip(" abc", null) = "abc"
- * StringUtils.strip("abc ", null) = "abc"
- * StringUtils.strip(" abc ", null) = "abc"
- * StringUtils.strip(" abcyx", "xyz") = " abc"
- *
- *
- * @param str the String to remove characters from, may be null
- * @param stripChars the characters to remove, null treated as whitespace
- * @return the stripped String, {@code null} if null String input
- */
- public static String strip(String str, String stripChars) {
- if (isEmpty(str)) {
- return str;
- }
- str = stripStart(str, stripChars);
- return stripEnd(str, stripChars);
- }
-
- /**
- * Strips any of a set of characters from the start of a String.
- * - *A {@code null} input String returns {@code null}. - * An empty string ("") input returns the empty string.
- * - *If the stripChars String is {@code null}, whitespace is - * stripped as defined by {@link Character#isWhitespace(char)}.
- * - *
- * StringUtils.stripStart(null, *) = null
- * StringUtils.stripStart("", *) = ""
- * StringUtils.stripStart("abc", "") = "abc"
- * StringUtils.stripStart("abc", null) = "abc"
- * StringUtils.stripStart(" abc", null) = "abc"
- * StringUtils.stripStart("abc ", null) = "abc "
- * StringUtils.stripStart(" abc ", null) = "abc "
- * StringUtils.stripStart("yxabc ", "xyz") = "abc "
- *
- *
- * @param str the String to remove characters from, may be null
- * @param stripChars the characters to remove, null treated as whitespace
- * @return the stripped String, {@code null} if null String input
- */
- public static String stripStart(String str, String stripChars) {
- int strLen;
- if (str == null || (strLen = str.length()) == 0) {
- return str;
- }
- int start = 0;
- if (stripChars == null) {
- while ((start != strLen) && Character.isWhitespace(str.charAt(start))) {
- start++;
- }
- } else if (stripChars.length() == 0) {
- return str;
- } else {
- while ((start != strLen) && (stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND)) {
- start++;
- }
- }
- return str.substring(start);
- }
-
- /**
- * Strips any of a set of characters from the end of a String.
- * - *A {@code null} input String returns {@code null}. - * An empty string ("") input returns the empty string.
- * - *If the stripChars String is {@code null}, whitespace is - * stripped as defined by {@link Character#isWhitespace(char)}.
- * - *
- * StringUtils.stripEnd(null, *) = null
- * StringUtils.stripEnd("", *) = ""
- * StringUtils.stripEnd("abc", "") = "abc"
- * StringUtils.stripEnd("abc", null) = "abc"
- * StringUtils.stripEnd(" abc", null) = " abc"
- * StringUtils.stripEnd("abc ", null) = "abc"
- * StringUtils.stripEnd(" abc ", null) = " abc"
- * StringUtils.stripEnd(" abcyx", "xyz") = " abc"
- * StringUtils.stripEnd("120.00", ".0") = "12"
- *
- *
- * @param str the String to remove characters from, may be null
- * @param stripChars the set of characters to remove, null treated as whitespace
- * @return the stripped String, {@code null} if null String input
- */
- public static String stripEnd(String str, String stripChars) {
- int end;
- if (str == null || (end = str.length()) == 0) {
- return str;
- }
-
- if (stripChars == null) {
- while ((end != 0) && Character.isWhitespace(str.charAt(end - 1))) {
- end--;
- }
- } else if (stripChars.length() == 0) {
- return str;
- } else {
- while ((end != 0) && (stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND)) {
- end--;
- }
- }
- return str.substring(0, end);
- }
-
- // StripAll
- //-----------------------------------------------------------------------
- /**
- * Strips whitespace from the start and end of every String in an array. - * Whitespace is defined by {@link Character#isWhitespace(char)}.
- * - *A new array is returned each time, except for length zero. - * A {@code null} array will return {@code null}. - * An empty array will return itself. - * A {@code null} array entry will be ignored.
- * - *- * StringUtils.stripAll(null) = null - * StringUtils.stripAll([]) = [] - * StringUtils.stripAll(["abc", " abc"]) = ["abc", "abc"] - * StringUtils.stripAll(["abc ", null]) = ["abc", null] - *- * - * @param strs the array to remove whitespace from, may be null - * @return the stripped Strings, {@code null} if null array input - */ - public static String[] stripAll(String... strs) { - return stripAll(strs, null); - } - - /** - *
Strips any of a set of characters from the start and end of every - * String in an array.
- * Whitespace is defined by {@link Character#isWhitespace(char)}. - * - *A new array is returned each time, except for length zero. - * A {@code null} array will return {@code null}. - * An empty array will return itself. - * A {@code null} array entry will be ignored. - * A {@code null} stripChars will strip whitespace as defined by - * {@link Character#isWhitespace(char)}.
- * - *- * StringUtils.stripAll(null, *) = null - * StringUtils.stripAll([], *) = [] - * StringUtils.stripAll(["abc", " abc"], null) = ["abc", "abc"] - * StringUtils.stripAll(["abc ", null], null) = ["abc", null] - * StringUtils.stripAll(["abc ", null], "yz") = ["abc ", null] - * StringUtils.stripAll(["yabcz", null], "yz") = ["abc", null] - *- * - * @param strs the array to remove characters from, may be null - * @param stripChars the characters to remove, null treated as whitespace - * @return the stripped Strings, {@code null} if null array input - */ - public static String[] stripAll(String[] strs, String stripChars) { - int strsLen; - if (strs == null || (strsLen = strs.length) == 0) { - return strs; - } - String[] newArr = new String[strsLen]; - for (int i = 0; i < strsLen; i++) { - newArr[i] = strip(strs[i], stripChars); - } - return newArr; - } - - /** - *
Removes diacritics (~= accents) from a string. The case will not be altered.
- *For instance, 'à' will be replaced by 'a'.
- *Note that ligatures will be left as is.
- * - *This method will use the first available implementation of: - * Java 6's {@link java.text.Normalizer}, Java 1.3–1.5's {@code sun.text.Normalizer}
- * - *
- * StringUtils.stripAccents(null) = null
- * StringUtils.stripAccents("") = ""
- * StringUtils.stripAccents("control") = "control"
- * StringUtils.stripAccents("éclair") = "eclair"
- *
- *
- * @param input String to be stripped
- * @return input text with diacritics removed
- *
- * @since 3.0
- */
- // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix: https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
- public static String stripAccents(String input) {
- if(input == null) {
- return null;
- }
- try {
- String result = null;
- if (java6Available) {
- result = removeAccentsJava6(input);
- } else if (sunAvailable) {
- result = removeAccentsSUN(input);
- } else {
- throw new UnsupportedOperationException(
- "The stripAccents(CharSequence) method requires at least Java 1.6 or a Sun JVM");
- }
- // Note that none of the above methods correctly remove ligatures...
- return result;
- } catch(IllegalArgumentException iae) {
- throw new RuntimeException("IllegalArgumentException occurred", iae);
- } catch(IllegalAccessException iae) {
- throw new RuntimeException("IllegalAccessException occurred", iae);
- } catch(InvocationTargetException ite) {
- throw new RuntimeException("InvocationTargetException occurred", ite);
- } catch(SecurityException se) {
- throw new RuntimeException("SecurityException occurred", se);
- }
- }
-
- /**
- * Use {@code java.text.Normalizer#normalize(CharSequence, Normalizer.Form)}
- * (but be careful, this class exists in Java 1.3, with an entirely different meaning!)
- *
- * @param text the text to be processed
- * @return the processed string
- * @throws IllegalAccessException may be thrown by a reflection call
- * @throws InvocationTargetException if a reflection call throws an exception
- * @throws IllegalStateException if the {@code Normalizer} class is not available
- */
- private static String removeAccentsJava6(CharSequence text)
- throws IllegalAccessException, InvocationTargetException {
- /*
- String decomposed = java.text.Normalizer.normalize(CharSequence, Normalizer.Form.NFD);
- return java6Pattern.matcher(decomposed).replaceAll("");//$NON-NLS-1$
- */
- if (!java6Available || java6NormalizerFormNFD == null) {
- throw new IllegalStateException("java.text.Normalizer is not available");
- }
- String result;
- result = (String) java6NormalizeMethod.invoke(null, new Object[] {text, java6NormalizerFormNFD});
- result = java6Pattern.matcher(result).replaceAll("");//$NON-NLS-1$
- return result;
- }
-
- /**
- * Use {@code sun.text.Normalizer#decompose(String, boolean, int)}
- *
- * @param text the text to be processed
- * @return the processed string
- * @throws IllegalAccessException may be thrown by a reflection call
- * @throws InvocationTargetException if a reflection call throws an exception
- * @throws IllegalStateException if the {@code Normalizer} class is not available
- */
- private static String removeAccentsSUN(CharSequence text)
- throws IllegalAccessException, InvocationTargetException {
- /*
- String decomposed = sun.text.Normalizer.decompose(text, false, 0);
- return sunPattern.matcher(decomposed).replaceAll("");//$NON-NLS-1$
- */
- if (! sunAvailable) {
- throw new IllegalStateException("sun.text.Normalizer is not available");
- }
- String result;
- result = (String) sunDecomposeMethod.invoke(null, new Object[] {text, Boolean.FALSE, Integer.valueOf(0)});
- result = sunPattern.matcher(result).replaceAll("");//$NON-NLS-1$
- return result;
- }
-
- // SUN internal, Java 1.3 -> Java 5
- private static boolean sunAvailable = false;
- private static Method sunDecomposeMethod = null;
- private static final Pattern sunPattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");//$NON-NLS-1$
- // Java 6+
- private static boolean java6Available = false;
- private static Method java6NormalizeMethod = null;
- private static Object java6NormalizerFormNFD = null;
- private static final Pattern java6Pattern = sunPattern;
-
- static {
- try {
- // java.text.Normalizer.normalize(CharSequence, Normalizer.Form.NFD);
- // Be careful not to get Java 1.3 java.text.Normalizer!
- Class> normalizerFormClass = Thread.currentThread().getContextClassLoader()
- .loadClass("java.text.Normalizer$Form");//$NON-NLS-1$
- java6NormalizerFormNFD = normalizerFormClass.getField("NFD").get(null);//$NON-NLS-1$
- Class> normalizerClass = Thread.currentThread().getContextClassLoader()
- .loadClass("java.text.Normalizer");//$NON-NLS-1$
- java6NormalizeMethod = normalizerClass.getMethod("normalize",
- new Class[] {CharSequence.class, normalizerFormClass});//$NON-NLS-1$
- java6Available = true;
- } catch (ClassNotFoundException e) {
- java6Available = false;
- } catch (NoSuchFieldException e) {
- java6Available = false;
- } catch (IllegalAccessException e) {
- java6Available = false;
- } catch (NoSuchMethodException e) {
- java6Available = false;
- }
-
- try {
- // sun.text.Normalizer.decompose(text, false, 0);
- Class> normalizerClass = Thread.currentThread().getContextClassLoader()
- .loadClass("sun.text.Normalizer");//$NON-NLS-1$
- sunDecomposeMethod = normalizerClass.getMethod("decompose",
- new Class[] {String.class, Boolean.TYPE, Integer.TYPE});//$NON-NLS-1$
- sunAvailable = true;
- } catch (ClassNotFoundException e) {
- sunAvailable = false;
- } catch (NoSuchMethodException e) {
- sunAvailable = false;
- } catch (java.security.AccessControlException e) {
- // LANG-744 - thrown in Google App Engine
- sunAvailable = false;
- }
- }
-
- // Equals
- //-----------------------------------------------------------------------
- /**
- * Compares two CharSequences, returning {@code true} if they are equal.
- * - *{@code null}s are handled without exceptions. Two {@code null} - * references are considered to be equal. The comparison is case sensitive.
- * - *
- * StringUtils.equals(null, null) = true
- * StringUtils.equals(null, "abc") = false
- * StringUtils.equals("abc", null) = false
- * StringUtils.equals("abc", "abc") = true
- * StringUtils.equals("abc", "ABC") = false
- *
- *
- * @see java.lang.String#equals(Object)
- * @param cs1 the first CharSequence, may be null
- * @param cs2 the second CharSequence, may be null
- * @return {@code true} if the CharSequences are equal, case sensitive, or
- * both {@code null}
- * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
- */
- public static boolean equals(CharSequence cs1, CharSequence cs2) {
- return cs1 == null ? cs2 == null : cs1.equals(cs2);
- }
-
- /**
- * Compares two CharSequences, returning {@code true} if they are equal ignoring - * the case.
- * - *{@code null}s are handled without exceptions. Two {@code null} - * references are considered equal. Comparison is case insensitive.
- * - *
- * StringUtils.equalsIgnoreCase(null, null) = true
- * StringUtils.equalsIgnoreCase(null, "abc") = false
- * StringUtils.equalsIgnoreCase("abc", null) = false
- * StringUtils.equalsIgnoreCase("abc", "abc") = true
- * StringUtils.equalsIgnoreCase("abc", "ABC") = true
- *
- *
- * @param str1 the first CharSequence, may be null
- * @param str2 the second CharSequence, may be null
- * @return {@code true} if the CharSequence are equal, case insensitive, or
- * both {@code null}
- * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
- */
- public static boolean equalsIgnoreCase(CharSequence str1, CharSequence str2) {
- if (str1 == null || str2 == null) {
- return str1 == str2;
- } else {
- return CharSequenceUtils.regionMatches(str1, true, 0, str2, 0, Math.max(str1.length(), str2.length()));
- }
- }
-
- // IndexOf
- //-----------------------------------------------------------------------
- /**
- * Finds the first index within a CharSequence, handling {@code null}. - * This method uses {@link String#indexOf(int, int)} if possible.
- * - *A {@code null} or empty ("") CharSequence will return {@code INDEX_NOT_FOUND (-1)}.
- * - *
- * StringUtils.indexOf(null, *) = -1
- * StringUtils.indexOf("", *) = -1
- * StringUtils.indexOf("aabaabaa", 'a') = 0
- * StringUtils.indexOf("aabaabaa", 'b') = 2
- *
- *
- * @param seq the CharSequence to check, may be null
- * @param searchChar the character to find
- * @return the first index of the search character,
- * -1 if no match or {@code null} string input
- * @since 2.0
- * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
- */
- public static int indexOf(CharSequence seq, int searchChar) {
- if (isEmpty(seq)) {
- return INDEX_NOT_FOUND;
- }
- return CharSequenceUtils.indexOf(seq, searchChar, 0);
- }
-
- /**
- * Finds the first index within a CharSequence from a start position, - * handling {@code null}. - * This method uses {@link String#indexOf(int, int)} if possible.
- * - *A {@code null} or empty ("") CharSequence will return {@code (INDEX_NOT_FOUND) -1}. - * A negative start position is treated as zero. - * A start position greater than the string length returns {@code -1}.
- * - *
- * StringUtils.indexOf(null, *, *) = -1
- * StringUtils.indexOf("", *, *) = -1
- * StringUtils.indexOf("aabaabaa", 'b', 0) = 2
- * StringUtils.indexOf("aabaabaa", 'b', 3) = 5
- * StringUtils.indexOf("aabaabaa", 'b', 9) = -1
- * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
- *
- *
- * @param seq the CharSequence to check, may be null
- * @param searchChar the character to find
- * @param startPos the start position, negative treated as zero
- * @return the first index of the search character,
- * -1 if no match or {@code null} string input
- * @since 2.0
- * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
- */
- public static int indexOf(CharSequence seq, int searchChar, int startPos) {
- if (isEmpty(seq)) {
- return INDEX_NOT_FOUND;
- }
- return CharSequenceUtils.indexOf(seq, searchChar, startPos);
- }
-
- /**
- * Finds the first index within a CharSequence, handling {@code null}. - * This method uses {@link String#indexOf(String, int)} if possible.
- * - *A {@code null} CharSequence will return {@code -1}.
- * - *
- * StringUtils.indexOf(null, *) = -1
- * StringUtils.indexOf(*, null) = -1
- * StringUtils.indexOf("", "") = 0
- * StringUtils.indexOf("", *) = -1 (except when * = "")
- * StringUtils.indexOf("aabaabaa", "a") = 0
- * StringUtils.indexOf("aabaabaa", "b") = 2
- * StringUtils.indexOf("aabaabaa", "ab") = 1
- * StringUtils.indexOf("aabaabaa", "") = 0
- *
- *
- * @param seq the CharSequence to check, may be null
- * @param searchSeq the CharSequence to find, may be null
- * @return the first index of the search CharSequence,
- * -1 if no match or {@code null} string input
- * @since 2.0
- * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
- */
- public static int indexOf(CharSequence seq, CharSequence searchSeq) {
- if (seq == null || searchSeq == null) {
- return INDEX_NOT_FOUND;
- }
- return CharSequenceUtils.indexOf(seq, searchSeq, 0);
- }
-
- /**
- * Finds the first index within a CharSequence, handling {@code null}. - * This method uses {@link String#indexOf(String, int)} if possible.
- * - *A {@code null} CharSequence will return {@code -1}. - * A negative start position is treated as zero. - * An empty ("") search CharSequence always matches. - * A start position greater than the string length only matches - * an empty search CharSequence.
- * - *
- * StringUtils.indexOf(null, *, *) = -1
- * StringUtils.indexOf(*, null, *) = -1
- * StringUtils.indexOf("", "", 0) = 0
- * StringUtils.indexOf("", *, 0) = -1 (except when * = "")
- * StringUtils.indexOf("aabaabaa", "a", 0) = 0
- * StringUtils.indexOf("aabaabaa", "b", 0) = 2
- * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
- * StringUtils.indexOf("aabaabaa", "b", 3) = 5
- * StringUtils.indexOf("aabaabaa", "b", 9) = -1
- * StringUtils.indexOf("aabaabaa", "b", -1) = 2
- * StringUtils.indexOf("aabaabaa", "", 2) = 2
- * StringUtils.indexOf("abc", "", 9) = 3
- *
- *
- * @param seq the CharSequence to check, may be null
- * @param searchSeq the CharSequence to find, may be null
- * @param startPos the start position, negative treated as zero
- * @return the first index of the search CharSequence,
- * -1 if no match or {@code null} string input
- * @since 2.0
- * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
- */
- public static int indexOf(CharSequence seq, CharSequence searchSeq, int startPos) {
- if (seq == null || searchSeq == null) {
- return INDEX_NOT_FOUND;
- }
- return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
- }
-
- /**
- * Finds the n-th index within a CharSequence, handling {@code null}. - * This method uses {@link String#indexOf(String)} if possible.
- * - *A {@code null} CharSequence will return {@code -1}.
- * - *
- * StringUtils.ordinalIndexOf(null, *, *) = -1
- * StringUtils.ordinalIndexOf(*, null, *) = -1
- * StringUtils.ordinalIndexOf("", "", *) = 0
- * StringUtils.ordinalIndexOf("aabaabaa", "a", 1) = 0
- * StringUtils.ordinalIndexOf("aabaabaa", "a", 2) = 1
- * StringUtils.ordinalIndexOf("aabaabaa", "b", 1) = 2
- * StringUtils.ordinalIndexOf("aabaabaa", "b", 2) = 5
- * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
- * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
- * StringUtils.ordinalIndexOf("aabaabaa", "", 1) = 0
- * StringUtils.ordinalIndexOf("aabaabaa", "", 2) = 0
- *
- *
- * Note that 'head(CharSequence str, int n)' may be implemented as:
- * - *- * str.substring(0, lastOrdinalIndexOf(str, "\n", n)) - *- * - * @param str the CharSequence to check, may be null - * @param searchStr the CharSequence to find, may be null - * @param ordinal the n-th {@code searchStr} to find - * @return the n-th index of the search CharSequence, - * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input - * @since 2.1 - * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int) - */ - public static int ordinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal) { - return ordinalIndexOf(str, searchStr, ordinal, false); - } - - /** - *
Finds the n-th index within a String, handling {@code null}. - * This method uses {@link String#indexOf(String)} if possible.
- * - *A {@code null} CharSequence will return {@code -1}.
- * - * @param str the CharSequence to check, may be null - * @param searchStr the CharSequence to find, may be null - * @param ordinal the n-th {@code searchStr} to find - * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf() - * @return the n-th index of the search CharSequence, - * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input - */ - // Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int) - private static int ordinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal, boolean lastIndex) { - if (str == null || searchStr == null || ordinal <= 0) { - return INDEX_NOT_FOUND; - } - if (searchStr.length() == 0) { - return lastIndex ? str.length() : 0; - } - int found = 0; - int index = lastIndex ? str.length() : INDEX_NOT_FOUND; - do { - if (lastIndex) { - index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); - } else { - index = CharSequenceUtils.indexOf(str, searchStr, index + 1); - } - if (index < 0) { - return index; - } - found++; - } while (found < ordinal); - return index; - } - - /** - *Case in-sensitive find of the first index within a CharSequence.
- * - *A {@code null} CharSequence will return {@code -1}. - * A negative start position is treated as zero. - * An empty ("") search CharSequence always matches. - * A start position greater than the string length only matches - * an empty search CharSequence.
- * - *
- * StringUtils.indexOfIgnoreCase(null, *) = -1
- * StringUtils.indexOfIgnoreCase(*, null) = -1
- * StringUtils.indexOfIgnoreCase("", "") = 0
- * StringUtils.indexOfIgnoreCase("aabaabaa", "a") = 0
- * StringUtils.indexOfIgnoreCase("aabaabaa", "b") = 2
- * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
- *
- *
- * @param str the CharSequence to check, may be null
- * @param searchStr the CharSequence to find, may be null
- * @return the first index of the search CharSequence,
- * -1 if no match or {@code null} string input
- * @since 2.5
- * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
- */
- public static int indexOfIgnoreCase(CharSequence str, CharSequence searchStr) {
- return indexOfIgnoreCase(str, searchStr, 0);
- }
-
- /**
- * Case in-sensitive find of the first index within a CharSequence - * from the specified position.
- * - *A {@code null} CharSequence will return {@code -1}. - * A negative start position is treated as zero. - * An empty ("") search CharSequence always matches. - * A start position greater than the string length only matches - * an empty search CharSequence.
- * - *
- * StringUtils.indexOfIgnoreCase(null, *, *) = -1
- * StringUtils.indexOfIgnoreCase(*, null, *) = -1
- * StringUtils.indexOfIgnoreCase("", "", 0) = 0
- * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0) = 0
- * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0) = 2
- * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
- * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3) = 5
- * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9) = -1
- * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
- * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2) = 2
- * StringUtils.indexOfIgnoreCase("abc", "", 9) = 3
- *
- *
- * @param str the CharSequence to check, may be null
- * @param searchStr the CharSequence to find, may be null
- * @param startPos the start position, negative treated as zero
- * @return the first index of the search CharSequence,
- * -1 if no match or {@code null} string input
- * @since 2.5
- * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
- */
- public static int indexOfIgnoreCase(CharSequence str, CharSequence searchStr, int startPos) {
- if (str == null || searchStr == null) {
- return INDEX_NOT_FOUND;
- }
- if (startPos < 0) {
- startPos = 0;
- }
- int endLimit = (str.length() - searchStr.length()) + 1;
- if (startPos > endLimit) {
- return INDEX_NOT_FOUND;
- }
- if (searchStr.length() == 0) {
- return startPos;
- }
- for (int i = startPos; i < endLimit; i++) {
- if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- // LastIndexOf
- //-----------------------------------------------------------------------
- /**
- * Finds the last index within a CharSequence, handling {@code null}. - * This method uses {@link String#lastIndexOf(int)} if possible.
- * - *A {@code null} or empty ("") CharSequence will return {@code -1}.
- * - *
- * StringUtils.lastIndexOf(null, *) = -1
- * StringUtils.lastIndexOf("", *) = -1
- * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
- * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
- *
- *
- * @param seq the CharSequence to check, may be null
- * @param searchChar the character to find
- * @return the last index of the search character,
- * -1 if no match or {@code null} string input
- * @since 2.0
- * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
- */
- public static int lastIndexOf(CharSequence seq, int searchChar) {
- if (isEmpty(seq)) {
- return INDEX_NOT_FOUND;
- }
- return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
- }
-
- /**
- * Finds the last index within a CharSequence from a start position, - * handling {@code null}. - * This method uses {@link String#lastIndexOf(int, int)} if possible.
- * - *A {@code null} or empty ("") CharSequence will return {@code -1}. - * A negative start position returns {@code -1}. - * A start position greater than the string length searches the whole string.
- * - *
- * StringUtils.lastIndexOf(null, *, *) = -1
- * StringUtils.lastIndexOf("", *, *) = -1
- * StringUtils.lastIndexOf("aabaabaa", 'b', 8) = 5
- * StringUtils.lastIndexOf("aabaabaa", 'b', 4) = 2
- * StringUtils.lastIndexOf("aabaabaa", 'b', 0) = -1
- * StringUtils.lastIndexOf("aabaabaa", 'b', 9) = 5
- * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
- * StringUtils.lastIndexOf("aabaabaa", 'a', 0) = 0
- *
- *
- * @param seq the CharSequence to check, may be null
- * @param searchChar the character to find
- * @param startPos the start position
- * @return the last index of the search character,
- * -1 if no match or {@code null} string input
- * @since 2.0
- * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
- */
- public static int lastIndexOf(CharSequence seq, int searchChar, int startPos) {
- if (isEmpty(seq)) {
- return INDEX_NOT_FOUND;
- }
- return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
- }
-
- /**
- * Finds the last index within a CharSequence, handling {@code null}. - * This method uses {@link String#lastIndexOf(String)} if possible.
- * - *A {@code null} CharSequence will return {@code -1}.
- * - *
- * StringUtils.lastIndexOf(null, *) = -1
- * StringUtils.lastIndexOf(*, null) = -1
- * StringUtils.lastIndexOf("", "") = 0
- * StringUtils.lastIndexOf("aabaabaa", "a") = 7
- * StringUtils.lastIndexOf("aabaabaa", "b") = 5
- * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
- * StringUtils.lastIndexOf("aabaabaa", "") = 8
- *
- *
- * @param seq the CharSequence to check, may be null
- * @param searchSeq the CharSequence to find, may be null
- * @return the last index of the search String,
- * -1 if no match or {@code null} string input
- * @since 2.0
- * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
- */
- public static int lastIndexOf(CharSequence seq, CharSequence searchSeq) {
- if (seq == null || searchSeq == null) {
- return INDEX_NOT_FOUND;
- }
- return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
- }
-
- /**
- * Finds the n-th last index within a String, handling {@code null}. - * This method uses {@link String#lastIndexOf(String)}.
- * - *A {@code null} String will return {@code -1}.
- * - *
- * StringUtils.lastOrdinalIndexOf(null, *, *) = -1
- * StringUtils.lastOrdinalIndexOf(*, null, *) = -1
- * StringUtils.lastOrdinalIndexOf("", "", *) = 0
- * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1) = 7
- * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2) = 6
- * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1) = 5
- * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2) = 2
- * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
- * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
- * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1) = 8
- * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2) = 8
- *
- *
- * Note that 'tail(CharSequence str, int n)' may be implemented as:
- * - *- * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1) - *- * - * @param str the CharSequence to check, may be null - * @param searchStr the CharSequence to find, may be null - * @param ordinal the n-th last {@code searchStr} to find - * @return the n-th last index of the search CharSequence, - * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input - * @since 2.5 - * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int) - */ - public static int lastOrdinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal) { - return ordinalIndexOf(str, searchStr, ordinal, true); - } - - /** - *
Finds the first index within a CharSequence, handling {@code null}. - * This method uses {@link String#lastIndexOf(String, int)} if possible.
- * - *A {@code null} CharSequence will return {@code -1}. - * A negative start position returns {@code -1}. - * An empty ("") search CharSequence always matches unless the start position is negative. - * A start position greater than the string length searches the whole string.
- * - *
- * StringUtils.lastIndexOf(null, *, *) = -1
- * StringUtils.lastIndexOf(*, null, *) = -1
- * StringUtils.lastIndexOf("aabaabaa", "a", 8) = 7
- * StringUtils.lastIndexOf("aabaabaa", "b", 8) = 5
- * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
- * StringUtils.lastIndexOf("aabaabaa", "b", 9) = 5
- * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
- * StringUtils.lastIndexOf("aabaabaa", "a", 0) = 0
- * StringUtils.lastIndexOf("aabaabaa", "b", 0) = -1
- *
- *
- * @param seq the CharSequence to check, may be null
- * @param searchSeq the CharSequence to find, may be null
- * @param startPos the start position, negative treated as zero
- * @return the first index of the search CharSequence,
- * -1 if no match or {@code null} string input
- * @since 2.0
- * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
- */
- public static int lastIndexOf(CharSequence seq, CharSequence searchSeq, int startPos) {
- if (seq == null || searchSeq == null) {
- return INDEX_NOT_FOUND;
- }
- return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
- }
-
- /**
- * Case in-sensitive find of the last index within a CharSequence.
- * - *A {@code null} CharSequence will return {@code -1}. - * A negative start position returns {@code -1}. - * An empty ("") search CharSequence always matches unless the start position is negative. - * A start position greater than the string length searches the whole string.
- * - *
- * StringUtils.lastIndexOfIgnoreCase(null, *) = -1
- * StringUtils.lastIndexOfIgnoreCase(*, null) = -1
- * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A") = 7
- * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B") = 5
- * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
- *
- *
- * @param str the CharSequence to check, may be null
- * @param searchStr the CharSequence to find, may be null
- * @return the first index of the search CharSequence,
- * -1 if no match or {@code null} string input
- * @since 2.5
- * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
- */
- public static int lastIndexOfIgnoreCase(CharSequence str, CharSequence searchStr) {
- if (str == null || searchStr == null) {
- return INDEX_NOT_FOUND;
- }
- return lastIndexOfIgnoreCase(str, searchStr, str.length());
- }
-
- /**
- * Case in-sensitive find of the last index within a CharSequence - * from the specified position.
- * - *A {@code null} CharSequence will return {@code -1}. - * A negative start position returns {@code -1}. - * An empty ("") search CharSequence always matches unless the start position is negative. - * A start position greater than the string length searches the whole string.
- * - *
- * StringUtils.lastIndexOfIgnoreCase(null, *, *) = -1
- * StringUtils.lastIndexOfIgnoreCase(*, null, *) = -1
- * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8) = 7
- * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8) = 5
- * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
- * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9) = 5
- * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
- * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0) = 0
- * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0) = -1
- *
- *
- * @param str the CharSequence to check, may be null
- * @param searchStr the CharSequence to find, may be null
- * @param startPos the start position
- * @return the first index of the search CharSequence,
- * -1 if no match or {@code null} input
- * @since 2.5
- * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
- */
- public static int lastIndexOfIgnoreCase(CharSequence str, CharSequence searchStr, int startPos) {
- if (str == null || searchStr == null) {
- return INDEX_NOT_FOUND;
- }
- if (startPos > (str.length() - searchStr.length())) {
- startPos = str.length() - searchStr.length();
- }
- if (startPos < 0) {
- return INDEX_NOT_FOUND;
- }
- if (searchStr.length() == 0) {
- return startPos;
- }
-
- for (int i = startPos; i >= 0; i--) {
- if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- // Contains
- //-----------------------------------------------------------------------
- /**
- * Checks if CharSequence contains a search character, handling {@code null}. - * This method uses {@link String#indexOf(int)} if possible.
- * - *A {@code null} or empty ("") CharSequence will return {@code false}.
- * - *
- * StringUtils.contains(null, *) = false
- * StringUtils.contains("", *) = false
- * StringUtils.contains("abc", 'a') = true
- * StringUtils.contains("abc", 'z') = false
- *
- *
- * @param seq the CharSequence to check, may be null
- * @param searchChar the character to find
- * @return true if the CharSequence contains the search character,
- * false if not or {@code null} string input
- * @since 2.0
- * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
- */
- public static boolean contains(CharSequence seq, int searchChar) {
- if (isEmpty(seq)) {
- return false;
- }
- return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
- }
-
- /**
- * Checks if CharSequence contains a search CharSequence, handling {@code null}. - * This method uses {@link String#indexOf(String)} if possible.
- * - *A {@code null} CharSequence will return {@code false}.
- * - *
- * StringUtils.contains(null, *) = false
- * StringUtils.contains(*, null) = false
- * StringUtils.contains("", "") = true
- * StringUtils.contains("abc", "") = true
- * StringUtils.contains("abc", "a") = true
- * StringUtils.contains("abc", "z") = false
- *
- *
- * @param seq the CharSequence to check, may be null
- * @param searchSeq the CharSequence to find, may be null
- * @return true if the CharSequence contains the search CharSequence,
- * false if not or {@code null} string input
- * @since 2.0
- * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
- */
- public static boolean contains(CharSequence seq, CharSequence searchSeq) {
- if (seq == null || searchSeq == null) {
- return false;
- }
- return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
- }
-
- /**
- * Checks if CharSequence contains a search CharSequence irrespective of case, - * handling {@code null}. Case-insensitivity is defined as by - * {@link String#equalsIgnoreCase(String)}. - * - *
A {@code null} CharSequence will return {@code false}.
- * - *
- * StringUtils.contains(null, *) = false
- * StringUtils.contains(*, null) = false
- * StringUtils.contains("", "") = true
- * StringUtils.contains("abc", "") = true
- * StringUtils.contains("abc", "a") = true
- * StringUtils.contains("abc", "z") = false
- * StringUtils.contains("abc", "A") = true
- * StringUtils.contains("abc", "Z") = false
- *
- *
- * @param str the CharSequence to check, may be null
- * @param searchStr the CharSequence to find, may be null
- * @return true if the CharSequence contains the search CharSequence irrespective of
- * case or false if not or {@code null} string input
- * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
- */
- public static boolean containsIgnoreCase(CharSequence str, CharSequence searchStr) {
- if (str == null || searchStr == null) {
- return false;
- }
- int len = searchStr.length();
- int max = str.length() - len;
- for (int i = 0; i <= max; i++) {
- if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Check whether the given CharSequence contains any whitespace characters.
- * @param seq the CharSequence to check (may be {@code null})
- * @return {@code true} if the CharSequence is not empty and
- * contains at least 1 whitespace character
- * @see java.lang.Character#isWhitespace
- * @since 3.0
- */
- // From org.springframework.util.StringUtils, under Apache License 2.0
- public static boolean containsWhitespace(CharSequence seq) {
- if (isEmpty(seq)) {
- return false;
- }
- int strLen = seq.length();
- for (int i = 0; i < strLen; i++) {
- if (Character.isWhitespace(seq.charAt(i))) {
- return true;
- }
- }
- return false;
- }
-
- // IndexOfAny chars
- //-----------------------------------------------------------------------
- /**
- * Search a CharSequence to find the first index of any - * character in the given set of characters.
- * - *A {@code null} String will return {@code -1}. - * A {@code null} or zero length search array will return {@code -1}.
- * - *
- * StringUtils.indexOfAny(null, *) = -1
- * StringUtils.indexOfAny("", *) = -1
- * StringUtils.indexOfAny(*, null) = -1
- * StringUtils.indexOfAny(*, []) = -1
- * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0
- * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3
- * StringUtils.indexOfAny("aba", ['z']) = -1
- *
- *
- * @param cs the CharSequence to check, may be null
- * @param searchChars the chars to search for, may be null
- * @return the index of any of the chars, -1 if no match or null input
- * @since 2.0
- * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
- */
- public static int indexOfAny(CharSequence cs, char... searchChars) {
- if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
- return INDEX_NOT_FOUND;
- }
- int csLen = cs.length();
- int csLast = csLen - 1;
- int searchLen = searchChars.length;
- int searchLast = searchLen - 1;
- for (int i = 0; i < csLen; i++) {
- char ch = cs.charAt(i);
- for (int j = 0; j < searchLen; j++) {
- if (searchChars[j] == ch) {
- if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
- // ch is a supplementary character
- if (searchChars[j + 1] == cs.charAt(i + 1)) {
- return i;
- }
- } else {
- return i;
- }
- }
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- * Search a CharSequence to find the first index of any - * character in the given set of characters.
- * - *A {@code null} String will return {@code -1}. - * A {@code null} search string will return {@code -1}.
- * - *
- * StringUtils.indexOfAny(null, *) = -1
- * StringUtils.indexOfAny("", *) = -1
- * StringUtils.indexOfAny(*, null) = -1
- * StringUtils.indexOfAny(*, "") = -1
- * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
- * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
- * StringUtils.indexOfAny("aba","z") = -1
- *
- *
- * @param cs the CharSequence to check, may be null
- * @param searchChars the chars to search for, may be null
- * @return the index of any of the chars, -1 if no match or null input
- * @since 2.0
- * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
- */
- public static int indexOfAny(CharSequence cs, String searchChars) {
- if (isEmpty(cs) || isEmpty(searchChars)) {
- return INDEX_NOT_FOUND;
- }
- return indexOfAny(cs, searchChars.toCharArray());
- }
-
- // ContainsAny
- //-----------------------------------------------------------------------
- /**
- * Checks if the CharSequence contains any character in the given - * set of characters.
- * - *A {@code null} CharSequence will return {@code false}. - * A {@code null} or zero length search array will return {@code false}.
- * - *
- * StringUtils.containsAny(null, *) = false
- * StringUtils.containsAny("", *) = false
- * StringUtils.containsAny(*, null) = false
- * StringUtils.containsAny(*, []) = false
- * StringUtils.containsAny("zzabyycdxx",['z','a']) = true
- * StringUtils.containsAny("zzabyycdxx",['b','y']) = true
- * StringUtils.containsAny("aba", ['z']) = false
- *
- *
- * @param cs the CharSequence to check, may be null
- * @param searchChars the chars to search for, may be null
- * @return the {@code true} if any of the chars are found,
- * {@code false} if no match or null input
- * @since 2.4
- * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
- */
- public static boolean containsAny(CharSequence cs, char... searchChars) {
- if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
- return false;
- }
- int csLength = cs.length();
- int searchLength = searchChars.length;
- int csLast = csLength - 1;
- int searchLast = searchLength - 1;
- for (int i = 0; i < csLength; i++) {
- char ch = cs.charAt(i);
- for (int j = 0; j < searchLength; j++) {
- if (searchChars[j] == ch) {
- if (Character.isHighSurrogate(ch)) {
- if (j == searchLast) {
- // missing low surrogate, fine, like String.indexOf(String)
- return true;
- }
- if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
- return true;
- }
- } else {
- // ch is in the Basic Multilingual Plane
- return true;
- }
- }
- }
- }
- return false;
- }
-
- /**
- * - * Checks if the CharSequence contains any character in the given set of characters. - *
- * - *- * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return - * {@code false}. - *
- * - *
- * StringUtils.containsAny(null, *) = false
- * StringUtils.containsAny("", *) = false
- * StringUtils.containsAny(*, null) = false
- * StringUtils.containsAny(*, "") = false
- * StringUtils.containsAny("zzabyycdxx", "za") = true
- * StringUtils.containsAny("zzabyycdxx", "by") = true
- * StringUtils.containsAny("aba","z") = false
- *
- *
- * @param cs
- * the CharSequence to check, may be null
- * @param searchChars
- * the chars to search for, may be null
- * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
- * @since 2.4
- * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
- */
- public static boolean containsAny(CharSequence cs, CharSequence searchChars) {
- if (searchChars == null) {
- return false;
- }
- return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
- }
-
- // IndexOfAnyBut chars
- //-----------------------------------------------------------------------
- /**
- * Searches a CharSequence to find the first index of any - * character not in the given set of characters.
- * - *A {@code null} CharSequence will return {@code -1}. - * A {@code null} or zero length search array will return {@code -1}.
- * - *
- * StringUtils.indexOfAnyBut(null, *) = -1
- * StringUtils.indexOfAnyBut("", *) = -1
- * StringUtils.indexOfAnyBut(*, null) = -1
- * StringUtils.indexOfAnyBut(*, []) = -1
- * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
- * StringUtils.indexOfAnyBut("aba", new char[] {'z'} ) = 0
- * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} ) = -1
-
- *
- *
- * @param cs the CharSequence to check, may be null
- * @param searchChars the chars to search for, may be null
- * @return the index of any of the chars, -1 if no match or null input
- * @since 2.0
- * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
- */
- public static int indexOfAnyBut(CharSequence cs, char... searchChars) {
- if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
- return INDEX_NOT_FOUND;
- }
- int csLen = cs.length();
- int csLast = csLen - 1;
- int searchLen = searchChars.length;
- int searchLast = searchLen - 1;
- outer:
- for (int i = 0; i < csLen; i++) {
- char ch = cs.charAt(i);
- for (int j = 0; j < searchLen; j++) {
- if (searchChars[j] == ch) {
- if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
- if (searchChars[j + 1] == cs.charAt(i + 1)) {
- continue outer;
- }
- } else {
- continue outer;
- }
- }
- }
- return i;
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- * Search a CharSequence to find the first index of any - * character not in the given set of characters.
- * - *A {@code null} CharSequence will return {@code -1}. - * A {@code null} or empty search string will return {@code -1}.
- * - *
- * StringUtils.indexOfAnyBut(null, *) = -1
- * StringUtils.indexOfAnyBut("", *) = -1
- * StringUtils.indexOfAnyBut(*, null) = -1
- * StringUtils.indexOfAnyBut(*, "") = -1
- * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
- * StringUtils.indexOfAnyBut("zzabyycdxx", "") = -1
- * StringUtils.indexOfAnyBut("aba","ab") = -1
- *
- *
- * @param seq the CharSequence to check, may be null
- * @param searchChars the chars to search for, may be null
- * @return the index of any of the chars, -1 if no match or null input
- * @since 2.0
- * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
- */
- public static int indexOfAnyBut(CharSequence seq, CharSequence searchChars) {
- if (isEmpty(seq) || isEmpty(searchChars)) {
- return INDEX_NOT_FOUND;
- }
- int strLen = seq.length();
- for (int i = 0; i < strLen; i++) {
- char ch = seq.charAt(i);
- boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
- if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
- char ch2 = seq.charAt(i + 1);
- if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
- return i;
- }
- } else {
- if (!chFound) {
- return i;
- }
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- // ContainsOnly
- //-----------------------------------------------------------------------
- /**
- * Checks if the CharSequence contains only certain characters.
- * - *A {@code null} CharSequence will return {@code false}. - * A {@code null} valid character array will return {@code false}. - * An empty CharSequence (length()=0) always returns {@code true}.
- * - *
- * StringUtils.containsOnly(null, *) = false
- * StringUtils.containsOnly(*, null) = false
- * StringUtils.containsOnly("", *) = true
- * StringUtils.containsOnly("ab", '') = false
- * StringUtils.containsOnly("abab", 'abc') = true
- * StringUtils.containsOnly("ab1", 'abc') = false
- * StringUtils.containsOnly("abz", 'abc') = false
- *
- *
- * @param cs the String to check, may be null
- * @param valid an array of valid chars, may be null
- * @return true if it only contains valid chars and is non-null
- * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
- */
- public static boolean containsOnly(CharSequence cs, char... valid) {
- // All these pre-checks are to maintain API with an older version
- if (valid == null || cs == null) {
- return false;
- }
- if (cs.length() == 0) {
- return true;
- }
- if (valid.length == 0) {
- return false;
- }
- return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
- }
-
- /**
- * Checks if the CharSequence contains only certain characters.
- * - *A {@code null} CharSequence will return {@code false}. - * A {@code null} valid character String will return {@code false}. - * An empty String (length()=0) always returns {@code true}.
- * - *
- * StringUtils.containsOnly(null, *) = false
- * StringUtils.containsOnly(*, null) = false
- * StringUtils.containsOnly("", *) = true
- * StringUtils.containsOnly("ab", "") = false
- * StringUtils.containsOnly("abab", "abc") = true
- * StringUtils.containsOnly("ab1", "abc") = false
- * StringUtils.containsOnly("abz", "abc") = false
- *
- *
- * @param cs the CharSequence to check, may be null
- * @param validChars a String of valid chars, may be null
- * @return true if it only contains valid chars and is non-null
- * @since 2.0
- * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
- */
- public static boolean containsOnly(CharSequence cs, String validChars) {
- if (cs == null || validChars == null) {
- return false;
- }
- return containsOnly(cs, validChars.toCharArray());
- }
-
- // ContainsNone
- //-----------------------------------------------------------------------
- /**
- * Checks that the CharSequence does not contain certain characters.
- * - *A {@code null} CharSequence will return {@code true}. - * A {@code null} invalid character array will return {@code true}. - * An empty CharSequence (length()=0) always returns true.
- * - *
- * StringUtils.containsNone(null, *) = true
- * StringUtils.containsNone(*, null) = true
- * StringUtils.containsNone("", *) = true
- * StringUtils.containsNone("ab", '') = true
- * StringUtils.containsNone("abab", 'xyz') = true
- * StringUtils.containsNone("ab1", 'xyz') = true
- * StringUtils.containsNone("abz", 'xyz') = false
- *
- *
- * @param cs the CharSequence to check, may be null
- * @param searchChars an array of invalid chars, may be null
- * @return true if it contains none of the invalid chars, or is null
- * @since 2.0
- * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
- */
- public static boolean containsNone(CharSequence cs, char... searchChars) {
- if (cs == null || searchChars == null) {
- return true;
- }
- int csLen = cs.length();
- int csLast = csLen - 1;
- int searchLen = searchChars.length;
- int searchLast = searchLen - 1;
- for (int i = 0; i < csLen; i++) {
- char ch = cs.charAt(i);
- for (int j = 0; j < searchLen; j++) {
- if (searchChars[j] == ch) {
- if (Character.isHighSurrogate(ch)) {
- if (j == searchLast) {
- // missing low surrogate, fine, like String.indexOf(String)
- return false;
- }
- if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
- return false;
- }
- } else {
- // ch is in the Basic Multilingual Plane
- return false;
- }
- }
- }
- }
- return true;
- }
-
- /**
- * Checks that the CharSequence does not contain certain characters.
- * - *A {@code null} CharSequence will return {@code true}. - * A {@code null} invalid character array will return {@code true}. - * An empty String ("") always returns true.
- * - *
- * StringUtils.containsNone(null, *) = true
- * StringUtils.containsNone(*, null) = true
- * StringUtils.containsNone("", *) = true
- * StringUtils.containsNone("ab", "") = true
- * StringUtils.containsNone("abab", "xyz") = true
- * StringUtils.containsNone("ab1", "xyz") = true
- * StringUtils.containsNone("abz", "xyz") = false
- *
- *
- * @param cs the CharSequence to check, may be null
- * @param invalidChars a String of invalid chars, may be null
- * @return true if it contains none of the invalid chars, or is null
- * @since 2.0
- * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
- */
- public static boolean containsNone(CharSequence cs, String invalidChars) {
- if (cs == null || invalidChars == null) {
- return true;
- }
- return containsNone(cs, invalidChars.toCharArray());
- }
-
- // IndexOfAny strings
- //-----------------------------------------------------------------------
- /**
- * Find the first index of any of a set of potential substrings.
- * - *A {@code null} CharSequence will return {@code -1}. - * A {@code null} or zero length search array will return {@code -1}. - * A {@code null} search array entry will be ignored, but a search - * array containing "" will return {@code 0} if {@code str} is not - * null. This method uses {@link String#indexOf(String)} if possible.
- * - *
- * StringUtils.indexOfAny(null, *) = -1
- * StringUtils.indexOfAny(*, null) = -1
- * StringUtils.indexOfAny(*, []) = -1
- * StringUtils.indexOfAny("zzabyycdxx", ["ab","cd"]) = 2
- * StringUtils.indexOfAny("zzabyycdxx", ["cd","ab"]) = 2
- * StringUtils.indexOfAny("zzabyycdxx", ["mn","op"]) = -1
- * StringUtils.indexOfAny("zzabyycdxx", ["zab","aby"]) = 1
- * StringUtils.indexOfAny("zzabyycdxx", [""]) = 0
- * StringUtils.indexOfAny("", [""]) = 0
- * StringUtils.indexOfAny("", ["a"]) = -1
- *
- *
- * @param str the CharSequence to check, may be null
- * @param searchStrs the CharSequences to search for, may be null
- * @return the first index of any of the searchStrs in str, -1 if no match
- * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
- */
- public static int indexOfAny(CharSequence str, CharSequence... searchStrs) {
- if (str == null || searchStrs == null) {
- return INDEX_NOT_FOUND;
- }
- int sz = searchStrs.length;
-
- // String's can't have a MAX_VALUEth index.
- int ret = Integer.MAX_VALUE;
-
- int tmp = 0;
- for (int i = 0; i < sz; i++) {
- CharSequence search = searchStrs[i];
- if (search == null) {
- continue;
- }
- tmp = CharSequenceUtils.indexOf(str, search, 0);
- if (tmp == INDEX_NOT_FOUND) {
- continue;
- }
-
- if (tmp < ret) {
- ret = tmp;
- }
- }
-
- return (ret == Integer.MAX_VALUE) ? INDEX_NOT_FOUND : ret;
- }
-
- /**
- * Find the latest index of any of a set of potential substrings.
- * - *A {@code null} CharSequence will return {@code -1}. - * A {@code null} search array will return {@code -1}. - * A {@code null} or zero length search array entry will be ignored, - * but a search array containing "" will return the length of {@code str} - * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible
- * - *
- * StringUtils.lastIndexOfAny(null, *) = -1
- * StringUtils.lastIndexOfAny(*, null) = -1
- * StringUtils.lastIndexOfAny(*, []) = -1
- * StringUtils.lastIndexOfAny(*, [null]) = -1
- * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab","cd"]) = 6
- * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd","ab"]) = 6
- * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
- * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
- * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn",""]) = 10
- *
- *
- * @param str the CharSequence to check, may be null
- * @param searchStrs the CharSequences to search for, may be null
- * @return the last index of any of the CharSequences, -1 if no match
- * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
- */
- public static int lastIndexOfAny(CharSequence str, CharSequence... searchStrs) {
- if (str == null || searchStrs == null) {
- return INDEX_NOT_FOUND;
- }
- int sz = searchStrs.length;
- int ret = INDEX_NOT_FOUND;
- int tmp = 0;
- for (int i = 0; i < sz; i++) {
- CharSequence search = searchStrs[i];
- if (search == null) {
- continue;
- }
- tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
- if (tmp > ret) {
- ret = tmp;
- }
- }
- return ret;
- }
-
- // Substring
- //-----------------------------------------------------------------------
- /**
- * Gets a substring from the specified String avoiding exceptions.
- * - *A negative start position can be used to start {@code n} - * characters from the end of the String.
- * - *A {@code null} String will return {@code null}. - * An empty ("") String will return "".
- * - *
- * StringUtils.substring(null, *) = null
- * StringUtils.substring("", *) = ""
- * StringUtils.substring("abc", 0) = "abc"
- * StringUtils.substring("abc", 2) = "c"
- * StringUtils.substring("abc", 4) = ""
- * StringUtils.substring("abc", -2) = "bc"
- * StringUtils.substring("abc", -4) = "abc"
- *
- *
- * @param str the String to get the substring from, may be null
- * @param start the position to start from, negative means
- * count back from the end of the String by this many characters
- * @return substring from start position, {@code null} if null String input
- */
- public static String substring(String str, int start) {
- if (str == null) {
- return null;
- }
-
- // handle negatives, which means last n characters
- if (start < 0) {
- start = str.length() + start; // remember start is negative
- }
-
- if (start < 0) {
- start = 0;
- }
- if (start > str.length()) {
- return EMPTY;
- }
-
- return str.substring(start);
- }
-
- /**
- * Gets a substring from the specified String avoiding exceptions.
- * - *A negative start position can be used to start/end {@code n} - * characters from the end of the String.
- * - *The returned substring starts with the character in the {@code start} - * position and ends before the {@code end} position. All position counting is - * zero-based -- i.e., to start at the beginning of the string use - * {@code start = 0}. Negative start and end positions can be used to - * specify offsets relative to the end of the String.
- * - *If {@code start} is not strictly to the left of {@code end}, "" - * is returned.
- * - *
- * StringUtils.substring(null, *, *) = null
- * StringUtils.substring("", * , *) = "";
- * StringUtils.substring("abc", 0, 2) = "ab"
- * StringUtils.substring("abc", 2, 0) = ""
- * StringUtils.substring("abc", 2, 4) = "c"
- * StringUtils.substring("abc", 4, 6) = ""
- * StringUtils.substring("abc", 2, 2) = ""
- * StringUtils.substring("abc", -2, -1) = "b"
- * StringUtils.substring("abc", -4, 2) = "ab"
- *
- *
- * @param str the String to get the substring from, may be null
- * @param start the position to start from, negative means
- * count back from the end of the String by this many characters
- * @param end the position to end at (exclusive), negative means
- * count back from the end of the String by this many characters
- * @return substring from start position to end position,
- * {@code null} if null String input
- */
- public static String substring(String str, int start, int end) {
- if (str == null) {
- return null;
- }
-
- // handle negatives
- if (end < 0) {
- end = str.length() + end; // remember end is negative
- }
- if (start < 0) {
- start = str.length() + start; // remember start is negative
- }
-
- // check length next
- if (end > str.length()) {
- end = str.length();
- }
-
- // if start is greater than end, return ""
- if (start > end) {
- return EMPTY;
- }
-
- if (start < 0) {
- start = 0;
- }
- if (end < 0) {
- end = 0;
- }
-
- return str.substring(start, end);
- }
-
- // Left/Right/Mid
- //-----------------------------------------------------------------------
- /**
- * Gets the leftmost {@code len} characters of a String.
- * - *If {@code len} characters are not available, or the - * String is {@code null}, the String will be returned without - * an exception. An empty String is returned if len is negative.
- * - *
- * StringUtils.left(null, *) = null
- * StringUtils.left(*, -ve) = ""
- * StringUtils.left("", *) = ""
- * StringUtils.left("abc", 0) = ""
- * StringUtils.left("abc", 2) = "ab"
- * StringUtils.left("abc", 4) = "abc"
- *
- *
- * @param str the String to get the leftmost characters from, may be null
- * @param len the length of the required String
- * @return the leftmost characters, {@code null} if null String input
- */
- public static String left(String str, int len) {
- if (str == null) {
- return null;
- }
- if (len < 0) {
- return EMPTY;
- }
- if (str.length() <= len) {
- return str;
- }
- return str.substring(0, len);
- }
-
- /**
- * Gets the rightmost {@code len} characters of a String.
- * - *If {@code len} characters are not available, or the String - * is {@code null}, the String will be returned without an - * an exception. An empty String is returned if len is negative.
- * - *
- * StringUtils.right(null, *) = null
- * StringUtils.right(*, -ve) = ""
- * StringUtils.right("", *) = ""
- * StringUtils.right("abc", 0) = ""
- * StringUtils.right("abc", 2) = "bc"
- * StringUtils.right("abc", 4) = "abc"
- *
- *
- * @param str the String to get the rightmost characters from, may be null
- * @param len the length of the required String
- * @return the rightmost characters, {@code null} if null String input
- */
- public static String right(String str, int len) {
- if (str == null) {
- return null;
- }
- if (len < 0) {
- return EMPTY;
- }
- if (str.length() <= len) {
- return str;
- }
- return str.substring(str.length() - len);
- }
-
- /**
- * Gets {@code len} characters from the middle of a String.
- * - *If {@code len} characters are not available, the remainder - * of the String will be returned without an exception. If the - * String is {@code null}, {@code null} will be returned. - * An empty String is returned if len is negative or exceeds the - * length of {@code str}.
- * - *
- * StringUtils.mid(null, *, *) = null
- * StringUtils.mid(*, *, -ve) = ""
- * StringUtils.mid("", 0, *) = ""
- * StringUtils.mid("abc", 0, 2) = "ab"
- * StringUtils.mid("abc", 0, 4) = "abc"
- * StringUtils.mid("abc", 2, 4) = "c"
- * StringUtils.mid("abc", 4, 2) = ""
- * StringUtils.mid("abc", -2, 2) = "ab"
- *
- *
- * @param str the String to get the characters from, may be null
- * @param pos the position to start from, negative treated as zero
- * @param len the length of the required String
- * @return the middle characters, {@code null} if null String input
- */
- public static String mid(String str, int pos, int len) {
- if (str == null) {
- return null;
- }
- if (len < 0 || pos > str.length()) {
- return EMPTY;
- }
- if (pos < 0) {
- pos = 0;
- }
- if (str.length() <= (pos + len)) {
- return str.substring(pos);
- }
- return str.substring(pos, pos + len);
- }
-
- // SubStringAfter/SubStringBefore
- //-----------------------------------------------------------------------
- /**
- * Gets the substring before the first occurrence of a separator. - * The separator is not returned.
- * - *A {@code null} string input will return {@code null}. - * An empty ("") string input will return the empty string. - * A {@code null} separator will return the input string.
- * - *If nothing is found, the string input is returned.
- * - *
- * StringUtils.substringBefore(null, *) = null
- * StringUtils.substringBefore("", *) = ""
- * StringUtils.substringBefore("abc", "a") = ""
- * StringUtils.substringBefore("abcba", "b") = "a"
- * StringUtils.substringBefore("abc", "c") = "ab"
- * StringUtils.substringBefore("abc", "d") = "abc"
- * StringUtils.substringBefore("abc", "") = ""
- * StringUtils.substringBefore("abc", null) = "abc"
- *
- *
- * @param str the String to get a substring from, may be null
- * @param separator the String to search for, may be null
- * @return the substring before the first occurrence of the separator,
- * {@code null} if null String input
- * @since 2.0
- */
- public static String substringBefore(String str, String separator) {
- if (isEmpty(str) || separator == null) {
- return str;
- }
- if (separator.length() == 0) {
- return EMPTY;
- }
- int pos = str.indexOf(separator);
- if (pos == INDEX_NOT_FOUND) {
- return str;
- }
- return str.substring(0, pos);
- }
-
- /**
- * Gets the substring after the first occurrence of a separator. - * The separator is not returned.
- * - *A {@code null} string input will return {@code null}. - * An empty ("") string input will return the empty string. - * A {@code null} separator will return the empty string if the - * input string is not {@code null}.
- * - *If nothing is found, the empty string is returned.
- * - *
- * StringUtils.substringAfter(null, *) = null
- * StringUtils.substringAfter("", *) = ""
- * StringUtils.substringAfter(*, null) = ""
- * StringUtils.substringAfter("abc", "a") = "bc"
- * StringUtils.substringAfter("abcba", "b") = "cba"
- * StringUtils.substringAfter("abc", "c") = ""
- * StringUtils.substringAfter("abc", "d") = ""
- * StringUtils.substringAfter("abc", "") = "abc"
- *
- *
- * @param str the String to get a substring from, may be null
- * @param separator the String to search for, may be null
- * @return the substring after the first occurrence of the separator,
- * {@code null} if null String input
- * @since 2.0
- */
- public static String substringAfter(String str, String separator) {
- if (isEmpty(str)) {
- return str;
- }
- if (separator == null) {
- return EMPTY;
- }
- int pos = str.indexOf(separator);
- if (pos == INDEX_NOT_FOUND) {
- return EMPTY;
- }
- return str.substring(pos + separator.length());
- }
-
- /**
- * Gets the substring before the last occurrence of a separator. - * The separator is not returned.
- * - *A {@code null} string input will return {@code null}. - * An empty ("") string input will return the empty string. - * An empty or {@code null} separator will return the input string.
- * - *If nothing is found, the string input is returned.
- * - *
- * StringUtils.substringBeforeLast(null, *) = null
- * StringUtils.substringBeforeLast("", *) = ""
- * StringUtils.substringBeforeLast("abcba", "b") = "abc"
- * StringUtils.substringBeforeLast("abc", "c") = "ab"
- * StringUtils.substringBeforeLast("a", "a") = ""
- * StringUtils.substringBeforeLast("a", "z") = "a"
- * StringUtils.substringBeforeLast("a", null) = "a"
- * StringUtils.substringBeforeLast("a", "") = "a"
- *
- *
- * @param str the String to get a substring from, may be null
- * @param separator the String to search for, may be null
- * @return the substring before the last occurrence of the separator,
- * {@code null} if null String input
- * @since 2.0
- */
- public static String substringBeforeLast(String str, String separator) {
- if (isEmpty(str) || isEmpty(separator)) {
- return str;
- }
- int pos = str.lastIndexOf(separator);
- if (pos == INDEX_NOT_FOUND) {
- return str;
- }
- return str.substring(0, pos);
- }
-
- /**
- * Gets the substring after the last occurrence of a separator. - * The separator is not returned.
- * - *A {@code null} string input will return {@code null}. - * An empty ("") string input will return the empty string. - * An empty or {@code null} separator will return the empty string if - * the input string is not {@code null}.
- * - *If nothing is found, the empty string is returned.
- * - *
- * StringUtils.substringAfterLast(null, *) = null
- * StringUtils.substringAfterLast("", *) = ""
- * StringUtils.substringAfterLast(*, "") = ""
- * StringUtils.substringAfterLast(*, null) = ""
- * StringUtils.substringAfterLast("abc", "a") = "bc"
- * StringUtils.substringAfterLast("abcba", "b") = "a"
- * StringUtils.substringAfterLast("abc", "c") = ""
- * StringUtils.substringAfterLast("a", "a") = ""
- * StringUtils.substringAfterLast("a", "z") = ""
- *
- *
- * @param str the String to get a substring from, may be null
- * @param separator the String to search for, may be null
- * @return the substring after the last occurrence of the separator,
- * {@code null} if null String input
- * @since 2.0
- */
- public static String substringAfterLast(String str, String separator) {
- if (isEmpty(str)) {
- return str;
- }
- if (isEmpty(separator)) {
- return EMPTY;
- }
- int pos = str.lastIndexOf(separator);
- if (pos == INDEX_NOT_FOUND || pos == (str.length() - separator.length())) {
- return EMPTY;
- }
- return str.substring(pos + separator.length());
- }
-
- // Substring between
- //-----------------------------------------------------------------------
- /**
- * Gets the String that is nested in between two instances of the - * same String.
- * - *A {@code null} input String returns {@code null}. - * A {@code null} tag returns {@code null}.
- * - *
- * StringUtils.substringBetween(null, *) = null
- * StringUtils.substringBetween("", "") = ""
- * StringUtils.substringBetween("", "tag") = null
- * StringUtils.substringBetween("tagabctag", null) = null
- * StringUtils.substringBetween("tagabctag", "") = ""
- * StringUtils.substringBetween("tagabctag", "tag") = "abc"
- *
- *
- * @param str the String containing the substring, may be null
- * @param tag the String before and after the substring, may be null
- * @return the substring, {@code null} if no match
- * @since 2.0
- */
- public static String substringBetween(String str, String tag) {
- return substringBetween(str, tag, tag);
- }
-
- /**
- * Gets the String that is nested in between two Strings. - * Only the first match is returned.
- * - *A {@code null} input String returns {@code null}. - * A {@code null} open/close returns {@code null} (no match). - * An empty ("") open and close returns an empty string.
- * - *
- * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
- * StringUtils.substringBetween(null, *, *) = null
- * StringUtils.substringBetween(*, null, *) = null
- * StringUtils.substringBetween(*, *, null) = null
- * StringUtils.substringBetween("", "", "") = ""
- * StringUtils.substringBetween("", "", "]") = null
- * StringUtils.substringBetween("", "[", "]") = null
- * StringUtils.substringBetween("yabcz", "", "") = ""
- * StringUtils.substringBetween("yabcz", "y", "z") = "abc"
- * StringUtils.substringBetween("yabczyabcz", "y", "z") = "abc"
- *
- *
- * @param str the String containing the substring, may be null
- * @param open the String before the substring, may be null
- * @param close the String after the substring, may be null
- * @return the substring, {@code null} if no match
- * @since 2.0
- */
- public static String substringBetween(String str, String open, String close) {
- if (str == null || open == null || close == null) {
- return null;
- }
- int start = str.indexOf(open);
- if (start != INDEX_NOT_FOUND) {
- int end = str.indexOf(close, start + open.length());
- if (end != INDEX_NOT_FOUND) {
- return str.substring(start + open.length(), end);
- }
- }
- return null;
- }
-
- /**
- * Searches a String for substrings delimited by a start and end tag, - * returning all matching substrings in an array.
- * - *A {@code null} input String returns {@code null}. - * A {@code null} open/close returns {@code null} (no match). - * An empty ("") open/close returns {@code null} (no match).
- * - *
- * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
- * StringUtils.substringsBetween(null, *, *) = null
- * StringUtils.substringsBetween(*, null, *) = null
- * StringUtils.substringsBetween(*, *, null) = null
- * StringUtils.substringsBetween("", "[", "]") = []
- *
- *
- * @param str the String containing the substrings, null returns null, empty returns empty
- * @param open the String identifying the start of the substring, empty returns null
- * @param close the String identifying the end of the substring, empty returns null
- * @return a String Array of substrings, or {@code null} if no match
- * @since 2.3
- */
- public static String[] substringsBetween(String str, String open, String close) {
- if (str == null || isEmpty(open) || isEmpty(close)) {
- return null;
- }
- int strLen = str.length();
- if (strLen == 0) {
- return ArrayUtils.EMPTY_STRING_ARRAY;
- }
- int closeLen = close.length();
- int openLen = open.length();
- ListSplits the provided text into an array, using whitespace as the - * separator. - * Whitespace is defined by {@link Character#isWhitespace(char)}.
- * - *The separator is not included in the returned String array. - * Adjacent separators are treated as one separator. - * For more control over the split use the StrTokenizer class.
- * - *A {@code null} input String returns {@code null}.
- * - *
- * StringUtils.split(null) = null
- * StringUtils.split("") = []
- * StringUtils.split("abc def") = ["abc", "def"]
- * StringUtils.split("abc def") = ["abc", "def"]
- * StringUtils.split(" abc ") = ["abc"]
- *
- *
- * @param str the String to parse, may be null
- * @return an array of parsed Strings, {@code null} if null String input
- */
- public static String[] split(String str) {
- return split(str, null, -1);
- }
-
- /**
- * Splits the provided text into an array, separator specified. - * This is an alternative to using StringTokenizer.
- * - *The separator is not included in the returned String array. - * Adjacent separators are treated as one separator. - * For more control over the split use the StrTokenizer class.
- * - *A {@code null} input String returns {@code null}.
- * - *
- * StringUtils.split(null, *) = null
- * StringUtils.split("", *) = []
- * StringUtils.split("a.b.c", '.') = ["a", "b", "c"]
- * StringUtils.split("a..b.c", '.') = ["a", "b", "c"]
- * StringUtils.split("a:b:c", '.') = ["a:b:c"]
- * StringUtils.split("a b c", ' ') = ["a", "b", "c"]
- *
- *
- * @param str the String to parse, may be null
- * @param separatorChar the character used as the delimiter
- * @return an array of parsed Strings, {@code null} if null String input
- * @since 2.0
- */
- public static String[] split(String str, char separatorChar) {
- return splitWorker(str, separatorChar, false);
- }
-
- /**
- * Splits the provided text into an array, separators specified. - * This is an alternative to using StringTokenizer.
- * - *The separator is not included in the returned String array. - * Adjacent separators are treated as one separator. - * For more control over the split use the StrTokenizer class.
- * - *A {@code null} input String returns {@code null}. - * A {@code null} separatorChars splits on whitespace.
- * - *
- * StringUtils.split(null, *) = null
- * StringUtils.split("", *) = []
- * StringUtils.split("abc def", null) = ["abc", "def"]
- * StringUtils.split("abc def", " ") = ["abc", "def"]
- * StringUtils.split("abc def", " ") = ["abc", "def"]
- * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
- *
- *
- * @param str the String to parse, may be null
- * @param separatorChars the characters used as the delimiters,
- * {@code null} splits on whitespace
- * @return an array of parsed Strings, {@code null} if null String input
- */
- public static String[] split(String str, String separatorChars) {
- return splitWorker(str, separatorChars, -1, false);
- }
-
- /**
- * Splits the provided text into an array with a maximum length, - * separators specified.
- * - *The separator is not included in the returned String array. - * Adjacent separators are treated as one separator.
- * - *A {@code null} input String returns {@code null}. - * A {@code null} separatorChars splits on whitespace.
- * - *If more than {@code max} delimited substrings are found, the last - * returned string includes all characters after the first {@code max - 1} - * returned strings (including separator characters).
- * - *
- * StringUtils.split(null, *, *) = null
- * StringUtils.split("", *, *) = []
- * StringUtils.split("ab de fg", null, 0) = ["ab", "cd", "ef"]
- * StringUtils.split("ab de fg", null, 0) = ["ab", "cd", "ef"]
- * StringUtils.split("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"]
- * StringUtils.split("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
- *
- *
- * @param str the String to parse, may be null
- * @param separatorChars the characters used as the delimiters,
- * {@code null} splits on whitespace
- * @param max the maximum number of elements to include in the
- * array. A zero or negative value implies no limit
- * @return an array of parsed Strings, {@code null} if null String input
- */
- public static String[] split(String str, String separatorChars, int max) {
- return splitWorker(str, separatorChars, max, false);
- }
-
- /**
- * Splits the provided text into an array, separator string specified.
- * - *The separator(s) will not be included in the returned String array. - * Adjacent separators are treated as one separator.
- * - *A {@code null} input String returns {@code null}. - * A {@code null} separator splits on whitespace.
- * - *
- * StringUtils.splitByWholeSeparator(null, *) = null
- * StringUtils.splitByWholeSeparator("", *) = []
- * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"]
- * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"]
- * StringUtils.splitByWholeSeparator("ab:cd:ef", ":") = ["ab", "cd", "ef"]
- * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
- *
- *
- * @param str the String to parse, may be null
- * @param separator String containing the String to be used as a delimiter,
- * {@code null} splits on whitespace
- * @return an array of parsed Strings, {@code null} if null String was input
- */
- public static String[] splitByWholeSeparator(String str, String separator) {
- return splitByWholeSeparatorWorker( str, separator, -1, false ) ;
- }
-
- /**
- * Splits the provided text into an array, separator string specified. - * Returns a maximum of {@code max} substrings.
- * - *The separator(s) will not be included in the returned String array. - * Adjacent separators are treated as one separator.
- * - *A {@code null} input String returns {@code null}. - * A {@code null} separator splits on whitespace.
- * - *
- * StringUtils.splitByWholeSeparator(null, *, *) = null
- * StringUtils.splitByWholeSeparator("", *, *) = []
- * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"]
- * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"]
- * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
- * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
- * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
- *
- *
- * @param str the String to parse, may be null
- * @param separator String containing the String to be used as a delimiter,
- * {@code null} splits on whitespace
- * @param max the maximum number of elements to include in the returned
- * array. A zero or negative value implies no limit.
- * @return an array of parsed Strings, {@code null} if null String was input
- */
- public static String[] splitByWholeSeparator( String str, String separator, int max ) {
- return splitByWholeSeparatorWorker(str, separator, max, false);
- }
-
- /**
- * Splits the provided text into an array, separator string specified.
- * - *The separator is not included in the returned String array. - * Adjacent separators are treated as separators for empty tokens. - * For more control over the split use the StrTokenizer class.
- * - *A {@code null} input String returns {@code null}. - * A {@code null} separator splits on whitespace.
- * - *
- * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *) = null
- * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *) = []
- * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "de", "fg"]
- * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "", "", "de", "fg"]
- * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"]
- * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
- *
- *
- * @param str the String to parse, may be null
- * @param separator String containing the String to be used as a delimiter,
- * {@code null} splits on whitespace
- * @return an array of parsed Strings, {@code null} if null String was input
- * @since 2.4
- */
- public static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator) {
- return splitByWholeSeparatorWorker(str, separator, -1, true);
- }
-
- /**
- * Splits the provided text into an array, separator string specified. - * Returns a maximum of {@code max} substrings.
- * - *The separator is not included in the returned String array. - * Adjacent separators are treated as separators for empty tokens. - * For more control over the split use the StrTokenizer class.
- * - *A {@code null} input String returns {@code null}. - * A {@code null} separator splits on whitespace.
- * - *
- * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *) = null
- * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *) = []
- * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "de", "fg"]
- * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "", "", "de", "fg"]
- * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
- * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
- * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
- *
- *
- * @param str the String to parse, may be null
- * @param separator String containing the String to be used as a delimiter,
- * {@code null} splits on whitespace
- * @param max the maximum number of elements to include in the returned
- * array. A zero or negative value implies no limit.
- * @return an array of parsed Strings, {@code null} if null String was input
- * @since 2.4
- */
- public static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator, int max) {
- return splitByWholeSeparatorWorker(str, separator, max, true);
- }
-
- /**
- * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
- *
- * @param str the String to parse, may be {@code null}
- * @param separator String containing the String to be used as a delimiter,
- * {@code null} splits on whitespace
- * @param max the maximum number of elements to include in the returned
- * array. A zero or negative value implies no limit.
- * @param preserveAllTokens if {@code true}, adjacent separators are
- * treated as empty token separators; if {@code false}, adjacent
- * separators are treated as one separator.
- * @return an array of parsed Strings, {@code null} if null String input
- * @since 2.4
- */
- private static String[] splitByWholeSeparatorWorker(
- String str, String separator, int max, boolean preserveAllTokens) {
- if (str == null) {
- return null;
- }
-
- int len = str.length();
-
- if (len == 0) {
- return ArrayUtils.EMPTY_STRING_ARRAY;
- }
-
- if ((separator == null) || (EMPTY.equals(separator))) {
- // Split on whitespace.
- return splitWorker(str, null, max, preserveAllTokens);
- }
-
- int separatorLength = separator.length();
-
- ArrayListSplits the provided text into an array, using whitespace as the - * separator, preserving all tokens, including empty tokens created by - * adjacent separators. This is an alternative to using StringTokenizer. - * Whitespace is defined by {@link Character#isWhitespace(char)}.
- * - *The separator is not included in the returned String array. - * Adjacent separators are treated as separators for empty tokens. - * For more control over the split use the StrTokenizer class.
- * - *A {@code null} input String returns {@code null}.
- * - *
- * StringUtils.splitPreserveAllTokens(null) = null
- * StringUtils.splitPreserveAllTokens("") = []
- * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "def"]
- * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "", "def"]
- * StringUtils.splitPreserveAllTokens(" abc ") = ["", "abc", ""]
- *
- *
- * @param str the String to parse, may be {@code null}
- * @return an array of parsed Strings, {@code null} if null String input
- * @since 2.1
- */
- public static String[] splitPreserveAllTokens(String str) {
- return splitWorker(str, null, -1, true);
- }
-
- /**
- * Splits the provided text into an array, separator specified, - * preserving all tokens, including empty tokens created by adjacent - * separators. This is an alternative to using StringTokenizer.
- * - *The separator is not included in the returned String array. - * Adjacent separators are treated as separators for empty tokens. - * For more control over the split use the StrTokenizer class.
- * - *A {@code null} input String returns {@code null}.
- * - *
- * StringUtils.splitPreserveAllTokens(null, *) = null
- * StringUtils.splitPreserveAllTokens("", *) = []
- * StringUtils.splitPreserveAllTokens("a.b.c", '.') = ["a", "b", "c"]
- * StringUtils.splitPreserveAllTokens("a..b.c", '.') = ["a", "", "b", "c"]
- * StringUtils.splitPreserveAllTokens("a:b:c", '.') = ["a:b:c"]
- * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
- * StringUtils.splitPreserveAllTokens("a b c", ' ') = ["a", "b", "c"]
- * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", ""]
- * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", "", ""]
- * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", a", "b", "c"]
- * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", "", a", "b", "c"]
- * StringUtils.splitPreserveAllTokens(" a b c ", ' ') = ["", a", "b", "c", ""]
- *
- *
- * @param str the String to parse, may be {@code null}
- * @param separatorChar the character used as the delimiter,
- * {@code null} splits on whitespace
- * @return an array of parsed Strings, {@code null} if null String input
- * @since 2.1
- */
- public static String[] splitPreserveAllTokens(String str, char separatorChar) {
- return splitWorker(str, separatorChar, true);
- }
-
- /**
- * Performs the logic for the {@code split} and
- * {@code splitPreserveAllTokens} methods that do not return a
- * maximum array length.
- *
- * @param str the String to parse, may be {@code null}
- * @param separatorChar the separate character
- * @param preserveAllTokens if {@code true}, adjacent separators are
- * treated as empty token separators; if {@code false}, adjacent
- * separators are treated as one separator.
- * @return an array of parsed Strings, {@code null} if null String input
- */
- private static String[] splitWorker(String str, char separatorChar, boolean preserveAllTokens) {
- // Performance tuned for 2.0 (JDK1.4)
-
- if (str == null) {
- return null;
- }
- int len = str.length();
- if (len == 0) {
- return ArrayUtils.EMPTY_STRING_ARRAY;
- }
- ListSplits the provided text into an array, separators specified, - * preserving all tokens, including empty tokens created by adjacent - * separators. This is an alternative to using StringTokenizer.
- * - *The separator is not included in the returned String array. - * Adjacent separators are treated as separators for empty tokens. - * For more control over the split use the StrTokenizer class.
- * - *A {@code null} input String returns {@code null}. - * A {@code null} separatorChars splits on whitespace.
- * - *
- * StringUtils.splitPreserveAllTokens(null, *) = null
- * StringUtils.splitPreserveAllTokens("", *) = []
- * StringUtils.splitPreserveAllTokens("abc def", null) = ["abc", "def"]
- * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "def"]
- * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "", def"]
- * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"]
- * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":") = ["ab", "cd", "ef", ""]
- * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
- * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":") = ["ab", "", cd", "ef"]
- * StringUtils.splitPreserveAllTokens(":cd:ef", ":") = ["", cd", "ef"]
- * StringUtils.splitPreserveAllTokens("::cd:ef", ":") = ["", "", cd", "ef"]
- * StringUtils.splitPreserveAllTokens(":cd:ef:", ":") = ["", cd", "ef", ""]
- *
- *
- * @param str the String to parse, may be {@code null}
- * @param separatorChars the characters used as the delimiters,
- * {@code null} splits on whitespace
- * @return an array of parsed Strings, {@code null} if null String input
- * @since 2.1
- */
- public static String[] splitPreserveAllTokens(String str, String separatorChars) {
- return splitWorker(str, separatorChars, -1, true);
- }
-
- /**
- * Splits the provided text into an array with a maximum length, - * separators specified, preserving all tokens, including empty tokens - * created by adjacent separators.
- * - *The separator is not included in the returned String array. - * Adjacent separators are treated as separators for empty tokens. - * Adjacent separators are treated as one separator.
- * - *A {@code null} input String returns {@code null}. - * A {@code null} separatorChars splits on whitespace.
- * - *If more than {@code max} delimited substrings are found, the last - * returned string includes all characters after the first {@code max - 1} - * returned strings (including separator characters).
- * - *
- * StringUtils.splitPreserveAllTokens(null, *, *) = null
- * StringUtils.splitPreserveAllTokens("", *, *) = []
- * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"]
- * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"]
- * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"]
- * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
- * StringUtils.splitPreserveAllTokens("ab de fg", null, 2) = ["ab", " de fg"]
- * StringUtils.splitPreserveAllTokens("ab de fg", null, 3) = ["ab", "", " de fg"]
- * StringUtils.splitPreserveAllTokens("ab de fg", null, 4) = ["ab", "", "", "de fg"]
- *
- *
- * @param str the String to parse, may be {@code null}
- * @param separatorChars the characters used as the delimiters,
- * {@code null} splits on whitespace
- * @param max the maximum number of elements to include in the
- * array. A zero or negative value implies no limit
- * @return an array of parsed Strings, {@code null} if null String input
- * @since 2.1
- */
- public static String[] splitPreserveAllTokens(String str, String separatorChars, int max) {
- return splitWorker(str, separatorChars, max, true);
- }
-
- /**
- * Performs the logic for the {@code split} and
- * {@code splitPreserveAllTokens} methods that return a maximum array
- * length.
- *
- * @param str the String to parse, may be {@code null}
- * @param separatorChars the separate character
- * @param max the maximum number of elements to include in the
- * array. A zero or negative value implies no limit.
- * @param preserveAllTokens if {@code true}, adjacent separators are
- * treated as empty token separators; if {@code false}, adjacent
- * separators are treated as one separator.
- * @return an array of parsed Strings, {@code null} if null String input
- */
- private static String[] splitWorker(String str, String separatorChars, int max, boolean preserveAllTokens) {
- // Performance tuned for 2.0 (JDK1.4)
- // Direct code is quicker than StringTokenizer.
- // Also, StringTokenizer uses isSpace() not isWhitespace()
-
- if (str == null) {
- return null;
- }
- int len = str.length();
- if (len == 0) {
- return ArrayUtils.EMPTY_STRING_ARRAY;
- }
- ListSplits a String by Character type as returned by - * {@code java.lang.Character.getType(char)}. Groups of contiguous - * characters of the same type are returned as complete tokens. - *
- * StringUtils.splitByCharacterType(null) = null
- * StringUtils.splitByCharacterType("") = []
- * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"]
- * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"]
- * StringUtils.splitByCharacterType("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"]
- * StringUtils.splitByCharacterType("number5") = ["number", "5"]
- * StringUtils.splitByCharacterType("fooBar") = ["foo", "B", "ar"]
- * StringUtils.splitByCharacterType("foo200Bar") = ["foo", "200", "B", "ar"]
- * StringUtils.splitByCharacterType("ASFRules") = ["ASFR", "ules"]
- *
- * @param str the String to split, may be {@code null}
- * @return an array of parsed Strings, {@code null} if null String input
- * @since 2.4
- */
- public static String[] splitByCharacterType(String str) {
- return splitByCharacterType(str, false);
- }
-
- /**
- * Splits a String by Character type as returned by - * {@code java.lang.Character.getType(char)}. Groups of contiguous - * characters of the same type are returned as complete tokens, with the - * following exception: the character of type - * {@code Character.UPPERCASE_LETTER}, if any, immediately - * preceding a token of type {@code Character.LOWERCASE_LETTER} - * will belong to the following token rather than to the preceding, if any, - * {@code Character.UPPERCASE_LETTER} token. - *
- * StringUtils.splitByCharacterTypeCamelCase(null) = null
- * StringUtils.splitByCharacterTypeCamelCase("") = []
- * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"]
- * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"]
- * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"]
- * StringUtils.splitByCharacterTypeCamelCase("number5") = ["number", "5"]
- * StringUtils.splitByCharacterTypeCamelCase("fooBar") = ["foo", "Bar"]
- * StringUtils.splitByCharacterTypeCamelCase("foo200Bar") = ["foo", "200", "Bar"]
- * StringUtils.splitByCharacterTypeCamelCase("ASFRules") = ["ASF", "Rules"]
- *
- * @param str the String to split, may be {@code null}
- * @return an array of parsed Strings, {@code null} if null String input
- * @since 2.4
- */
- public static String[] splitByCharacterTypeCamelCase(String str) {
- return splitByCharacterType(str, true);
- }
-
- /**
- * Splits a String by Character type as returned by
- * {@code java.lang.Character.getType(char)}. Groups of contiguous
- * characters of the same type are returned as complete tokens, with the
- * following exception: if {@code camelCase} is {@code true},
- * the character of type {@code Character.UPPERCASE_LETTER}, if any,
- * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
- * will belong to the following token rather than to the preceding, if any,
- * {@code Character.UPPERCASE_LETTER} token.
- * @param str the String to split, may be {@code null}
- * @param camelCase whether to use so-called "camel-case" for letter types
- * @return an array of parsed Strings, {@code null} if null String input
- * @since 2.4
- */
- private static String[] splitByCharacterType(String str, boolean camelCase) {
- if (str == null) {
- return null;
- }
- if (str.length() == 0) {
- return ArrayUtils.EMPTY_STRING_ARRAY;
- }
- char[] c = str.toCharArray();
- List Joins the elements of the provided array into a single String
- * containing the provided list of elements. No separator is added to the joined String.
- * Null objects or empty strings within the array are represented by
- * empty strings. Joins the elements of the provided array into a single String
- * containing the provided list of elements. No delimiter is added before or after the list.
- * Null objects or empty strings within the array are represented by
- * empty strings. Joins the elements of the provided array into a single String
- * containing the provided list of elements. No delimiter is added before or after the list.
- * Null objects or empty strings within the array are represented by
- * empty strings. Joins the elements of the provided array into a single String
- * containing the provided list of elements. No delimiter is added before or after the list.
- * A {@code null} separator is the same as an empty String ("").
- * Null objects or empty strings within the array are represented by
- * empty strings. Joins the elements of the provided array into a single String
- * containing the provided list of elements. No delimiter is added before or after the list.
- * A {@code null} separator is the same as an empty String ("").
- * Null objects or empty strings within the array are represented by
- * empty strings. Joins the elements of the provided {@code Iterator} into
- * a single String containing the provided elements. No delimiter is added before or after the list. Null objects or empty
- * strings within the iteration are represented by empty strings. See the examples here: {@link #join(Object[],char)}. Joins the elements of the provided {@code Iterator} into
- * a single String containing the provided elements. No delimiter is added before or after the list.
- * A {@code null} separator is the same as an empty String (""). See the examples here: {@link #join(Object[],String)}. Joins the elements of the provided {@code Iterable} into
- * a single String containing the provided elements. No delimiter is added before or after the list. Null objects or empty
- * strings within the iteration are represented by empty strings. See the examples here: {@link #join(Object[],char)}. Joins the elements of the provided {@code Iterable} into
- * a single String containing the provided elements. No delimiter is added before or after the list.
- * A {@code null} separator is the same as an empty String (""). See the examples here: {@link #join(Object[],String)}. Deletes all whitespaces from a String as defined by
- * {@link Character#isWhitespace(char)}. Removes a substring only if it is at the beginning of a source string,
- * otherwise returns the source string. A {@code null} source string will return {@code null}.
- * An empty ("") source string will return the empty string.
- * A {@code null} search string will return the source string. Case insensitive removal of a substring if it is at the beginning of a source string,
- * otherwise returns the source string. A {@code null} source string will return {@code null}.
- * An empty ("") source string will return the empty string.
- * A {@code null} search string will return the source string. Removes a substring only if it is at the end of a source string,
- * otherwise returns the source string. A {@code null} source string will return {@code null}.
- * An empty ("") source string will return the empty string.
- * A {@code null} search string will return the source string. Case insensitive removal of a substring if it is at the end of a source string,
- * otherwise returns the source string. A {@code null} source string will return {@code null}.
- * An empty ("") source string will return the empty string.
- * A {@code null} search string will return the source string. Removes all occurrences of a substring from within the source string. A {@code null} source string will return {@code null}.
- * An empty ("") source string will return the empty string.
- * A {@code null} remove string will return the source string.
- * An empty ("") remove string will return the source string. Removes all occurrences of a character from within the source string. A {@code null} source string will return {@code null}.
- * An empty ("") source string will return the empty string. Replaces a String with another String inside a larger String, once. A {@code null} reference passed to this method is a no-op. Replaces all occurrences of a String within another String. A {@code null} reference passed to this method is a no-op. Replaces a String with another String inside a larger String,
- * for the first {@code max} values of the search String. A {@code null} reference passed to this method is a no-op.
- * Replaces all occurrences of Strings within another String.
- *
- * A {@code null} reference passed to this method is a no-op, or if
- * any "search string" or "string to replace" is null, that replace will be
- * ignored. This will not repeat. For repeating replaces, call the
- * overloaded method.
- *
- * Replaces all occurrences of Strings within another String.
- *
- * A {@code null} reference passed to this method is a no-op, or if
- * any "search string" or "string to replace" is null, that replace will be
- * ignored.
- *
- * Replaces all occurrences of Strings within another String.
- *
- * A {@code null} reference passed to this method is a no-op, or if
- * any "search string" or "string to replace" is null, that replace will be
- * ignored.
- * Replaces all occurrences of a character in a String with another.
- * This is a null-safe version of {@link String#replace(char, char)}. A {@code null} string input returns {@code null}.
- * An empty ("") string input returns an empty string. Replaces multiple characters in a String in one go.
- * This method can also be used to delete characters. For example: A {@code null} string input returns {@code null}.
- * An empty ("") string input returns an empty string.
- * A null or empty set of search characters returns the input string. The length of the search characters should normally equal the length
- * of the replace characters.
- * If the search characters is longer, then the extra search characters
- * are deleted.
- * If the search characters is shorter, then the extra replace characters
- * are ignored. Overlays part of a String with another String. A {@code null} string input returns {@code null}.
- * A negative index is treated as zero.
- * An index greater than the string length is treated as the string length.
- * The start index is always the smaller of the two indices. Removes one newline from end of a String if it's there,
- * otherwise leave it alone. A newline is "{@code \n}",
- * "{@code \r}", or "{@code \r\n}". NOTE: This method changed in 2.0.
- * It now more closely matches Perl chomp. Remove the last character from a String. If the String ends in {@code \r\n}, then remove both
- * of them. Repeat a String {@code repeat} times to form a
- * new String. Repeat a String {@code repeat} times to form a
- * new String, with a String separator injected each time. Returns padding using the specified delimiter repeated
- * to a given length. Note: this method doesn't not support padding with
- * Unicode Supplementary Characters
- * as they require a pair of {@code char}s to be represented.
- * If you are needing to support full I18N of your applications
- * consider using {@link #repeat(String, int)} instead.
- * Right pad a String with spaces (' '). The String is padded to the size of {@code size}. Right pad a String with a specified character. The String is padded to the size of {@code size}. Right pad a String with a specified String. The String is padded to the size of {@code size}. Left pad a String with spaces (' '). The String is padded to the size of {@code size}. Left pad a String with a specified character. Pad to a size of {@code size}. Left pad a String with a specified String. Pad to a size of {@code size}. Centers a String in a larger String of size {@code size}
- * using the space character (' ').
- *
- * If the size is less than the String length, the String is returned.
- * A {@code null} String returns {@code null}.
- * A negative size is treated as zero. Equivalent to {@code center(str, size, " ")}. Centers a String in a larger String of size {@code size}.
- * Uses a supplied character as the value to pad the String with. If the size is less than the String length, the String is returned.
- * A {@code null} String returns {@code null}.
- * A negative size is treated as zero. Centers a String in a larger String of size {@code size}.
- * Uses a supplied String as the value to pad the String with. If the size is less than the String length, the String is returned.
- * A {@code null} String returns {@code null}.
- * A negative size is treated as zero. Converts a String to upper case as per {@link String#toUpperCase()}. A {@code null} input String returns {@code null}. Note: As described in the documentation for {@link String#toUpperCase()},
- * the result of this method is affected by the current locale.
- * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
- * should be used with a specific locale (e.g. {@link Locale#ENGLISH}). Converts a String to upper case as per {@link String#toUpperCase(Locale)}. A {@code null} input String returns {@code null}. Converts a String to lower case as per {@link String#toLowerCase()}. A {@code null} input String returns {@code null}. Note: As described in the documentation for {@link String#toLowerCase()},
- * the result of this method is affected by the current locale.
- * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
- * should be used with a specific locale (e.g. {@link Locale#ENGLISH}). Converts a String to lower case as per {@link String#toLowerCase(Locale)}. A {@code null} input String returns {@code null}. Capitalizes a String changing the first letter to title case as
- * per {@link Character#toTitleCase(char)}. No other letters are changed. For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}.
- * A {@code null} input String returns {@code null}. Uncapitalizes a String changing the first letter to title case as
- * per {@link Character#toLowerCase(char)}. No other letters are changed. For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}.
- * A {@code null} input String returns {@code null}. Swaps the case of a String changing upper and title case to
- * lower case, and lower case to upper case. For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}.
- * A {@code null} input String returns {@code null}. NOTE: This method changed in Lang version 2.0.
- * It no longer performs a word based algorithm.
- * If you only use ASCII, you will notice no change.
- * That functionality is available in org.apache.commons.lang3.text.WordUtils. Counts how many times the substring appears in the larger string. A {@code null} or empty ("") String input returns {@code 0}. Checks if the CharSequence contains only Unicode letters. {@code null} will return {@code false}.
- * An empty CharSequence (length()=0) will return {@code false}. Checks if the CharSequence contains only Unicode letters and
- * space (' '). {@code null} will return {@code false}
- * An empty CharSequence (length()=0) will return {@code true}. Checks if the CharSequence contains only Unicode letters or digits. {@code null} will return {@code false}.
- * An empty CharSequence (length()=0) will return {@code false}. Checks if the CharSequence contains only Unicode letters, digits
- * or space ({@code ' '}). {@code null} will return {@code false}.
- * An empty CharSequence (length()=0) will return {@code true}. Checks if the CharSequence contains only ASCII printable characters. {@code null} will return {@code false}.
- * An empty CharSequence (length()=0) will return {@code true}. Checks if the CharSequence contains only Unicode digits.
- * A decimal point is not a Unicode digit and returns false. {@code null} will return {@code false}.
- * An empty CharSequence (length()=0) will return {@code false}. Checks if the CharSequence contains only Unicode digits or space
- * ({@code ' '}).
- * A decimal point is not a Unicode digit and returns false. {@code null} will return {@code false}.
- * An empty CharSequence (length()=0) will return {@code true}. Checks if the CharSequence contains only whitespace. {@code null} will return {@code false}.
- * An empty CharSequence (length()=0) will return {@code true}. Checks if the CharSequence contains only lowercase characters. {@code null} will return {@code false}.
- * An empty CharSequence (length()=0) will return {@code false}. Checks if the CharSequence contains only uppercase characters. {@code null} will return {@code false}.
- * An empty String (length()=0) will return {@code false}. Returns either the passed in String,
- * or if the String is {@code null}, an empty String (""). Returns either the passed in String, or if the String is
- * {@code null}, the value of {@code defaultStr}. Returns either the passed in CharSequence, or if the CharSequence is
- * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}. Returns either the passed in CharSequence, or if the CharSequence is
- * empty or {@code null}, the value of {@code defaultStr}. Reverses a String as per {@link StringBuilder#reverse()}. A {@code null} String returns {@code null}. Reverses a String that is delimited by a specific character. The Strings between the delimiters are not reversed.
- * Thus java.lang.String becomes String.lang.java (if the delimiter
- * is {@code '.'}). Abbreviates a String using ellipses. This will turn
- * "Now is the time for all good men" into "Now is the time for..." Specifically:
- *
- * StringUtils.join(null) = null
- * StringUtils.join([]) = ""
- * StringUtils.join([null]) = ""
- * StringUtils.join(["a", "b", "c"]) = "abc"
- * StringUtils.join([null, "", "a"]) = "a"
- *
- *
- * @param
- * StringUtils.join(null, *) = null
- * StringUtils.join([], *) = ""
- * StringUtils.join([null], *) = ""
- * StringUtils.join(["a", "b", "c"], ';') = "a;b;c"
- * StringUtils.join(["a", "b", "c"], null) = "abc"
- * StringUtils.join([null, "", "a"], ';') = ";;a"
- *
- *
- * @param array the array of values to join together, may be null
- * @param separator the separator character to use
- * @return the joined String, {@code null} if null array input
- * @since 2.0
- */
- public static String join(Object[] array, char separator) {
- if (array == null) {
- return null;
- }
-
- return join(array, separator, 0, array.length);
- }
-
- /**
- *
- * StringUtils.join(null, *) = null
- * StringUtils.join([], *) = ""
- * StringUtils.join([null], *) = ""
- * StringUtils.join(["a", "b", "c"], ';') = "a;b;c"
- * StringUtils.join(["a", "b", "c"], null) = "abc"
- * StringUtils.join([null, "", "a"], ';') = ";;a"
- *
- *
- * @param array the array of values to join together, may be null
- * @param separator the separator character to use
- * @param startIndex the first index to start joining from. It is
- * an error to pass in an end index past the end of the array
- * @param endIndex the index to stop joining from (exclusive). It is
- * an error to pass in an end index past the end of the array
- * @return the joined String, {@code null} if null array input
- * @since 2.0
- */
- public static String join(Object[] array, char separator, int startIndex, int endIndex) {
- if (array == null) {
- return null;
- }
- int noOfItems = (endIndex - startIndex);
- if (noOfItems <= 0) {
- return EMPTY;
- }
-
- StringBuilder buf = new StringBuilder(noOfItems * 16);
-
- for (int i = startIndex; i < endIndex; i++) {
- if (i > startIndex) {
- buf.append(separator);
- }
- if (array[i] != null) {
- buf.append(array[i]);
- }
- }
- return buf.toString();
- }
-
- /**
- *
- * StringUtils.join(null, *) = null
- * StringUtils.join([], *) = ""
- * StringUtils.join([null], *) = ""
- * StringUtils.join(["a", "b", "c"], "--") = "a--b--c"
- * StringUtils.join(["a", "b", "c"], null) = "abc"
- * StringUtils.join(["a", "b", "c"], "") = "abc"
- * StringUtils.join([null, "", "a"], ',') = ",,a"
- *
- *
- * @param array the array of values to join together, may be null
- * @param separator the separator character to use, null treated as ""
- * @return the joined String, {@code null} if null array input
- */
- public static String join(Object[] array, String separator) {
- if (array == null) {
- return null;
- }
- return join(array, separator, 0, array.length);
- }
-
- /**
- *
- * StringUtils.join(null, *) = null
- * StringUtils.join([], *) = ""
- * StringUtils.join([null], *) = ""
- * StringUtils.join(["a", "b", "c"], "--") = "a--b--c"
- * StringUtils.join(["a", "b", "c"], null) = "abc"
- * StringUtils.join(["a", "b", "c"], "") = "abc"
- * StringUtils.join([null, "", "a"], ',') = ",,a"
- *
- *
- * @param array the array of values to join together, may be null
- * @param separator the separator character to use, null treated as ""
- * @param startIndex the first index to start joining from. It is
- * an error to pass in an end index past the end of the array
- * @param endIndex the index to stop joining from (exclusive). It is
- * an error to pass in an end index past the end of the array
- * @return the joined String, {@code null} if null array input
- */
- public static String join(Object[] array, String separator, int startIndex, int endIndex) {
- if (array == null) {
- return null;
- }
- if (separator == null) {
- separator = EMPTY;
- }
-
- // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator))
- // (Assuming that all Strings are roughly equally long)
- int noOfItems = (endIndex - startIndex);
- if (noOfItems <= 0) {
- return EMPTY;
- }
-
- StringBuilder buf = new StringBuilder(noOfItems * 16);
-
- for (int i = startIndex; i < endIndex; i++) {
- if (i > startIndex) {
- buf.append(separator);
- }
- if (array[i] != null) {
- buf.append(array[i]);
- }
- }
- return buf.toString();
- }
-
- /**
- *
- * StringUtils.deleteWhitespace(null) = null
- * StringUtils.deleteWhitespace("") = ""
- * StringUtils.deleteWhitespace("abc") = "abc"
- * StringUtils.deleteWhitespace(" ab c ") = "abc"
- *
- *
- * @param str the String to delete whitespace from, may be null
- * @return the String without whitespaces, {@code null} if null String input
- */
- public static String deleteWhitespace(String str) {
- if (isEmpty(str)) {
- return str;
- }
- int sz = str.length();
- char[] chs = new char[sz];
- int count = 0;
- for (int i = 0; i < sz; i++) {
- if (!Character.isWhitespace(str.charAt(i))) {
- chs[count++] = str.charAt(i);
- }
- }
- if (count == sz) {
- return str;
- }
- return new String(chs, 0, count);
- }
-
- // Remove
- //-----------------------------------------------------------------------
- /**
- *
- * StringUtils.removeStart(null, *) = null
- * StringUtils.removeStart("", *) = ""
- * StringUtils.removeStart(*, null) = *
- * StringUtils.removeStart("www.domain.com", "www.") = "domain.com"
- * StringUtils.removeStart("domain.com", "www.") = "domain.com"
- * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
- * StringUtils.removeStart("abc", "") = "abc"
- *
- *
- * @param str the source String to search, may be null
- * @param remove the String to search for and remove, may be null
- * @return the substring with the string removed if found,
- * {@code null} if null String input
- * @since 2.1
- */
- public static String removeStart(String str, String remove) {
- if (isEmpty(str) || isEmpty(remove)) {
- return str;
- }
- if (str.startsWith(remove)){
- return str.substring(remove.length());
- }
- return str;
- }
-
- /**
- *
- * StringUtils.removeStartIgnoreCase(null, *) = null
- * StringUtils.removeStartIgnoreCase("", *) = ""
- * StringUtils.removeStartIgnoreCase(*, null) = *
- * StringUtils.removeStartIgnoreCase("www.domain.com", "www.") = "domain.com"
- * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.") = "domain.com"
- * StringUtils.removeStartIgnoreCase("domain.com", "www.") = "domain.com"
- * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
- * StringUtils.removeStartIgnoreCase("abc", "") = "abc"
- *
- *
- * @param str the source String to search, may be null
- * @param remove the String to search for (case insensitive) and remove, may be null
- * @return the substring with the string removed if found,
- * {@code null} if null String input
- * @since 2.4
- */
- public static String removeStartIgnoreCase(String str, String remove) {
- if (isEmpty(str) || isEmpty(remove)) {
- return str;
- }
- if (startsWithIgnoreCase(str, remove)) {
- return str.substring(remove.length());
- }
- return str;
- }
-
- /**
- *
- * StringUtils.removeEnd(null, *) = null
- * StringUtils.removeEnd("", *) = ""
- * StringUtils.removeEnd(*, null) = *
- * StringUtils.removeEnd("www.domain.com", ".com.") = "www.domain.com"
- * StringUtils.removeEnd("www.domain.com", ".com") = "www.domain"
- * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
- * StringUtils.removeEnd("abc", "") = "abc"
- *
- *
- * @param str the source String to search, may be null
- * @param remove the String to search for and remove, may be null
- * @return the substring with the string removed if found,
- * {@code null} if null String input
- * @since 2.1
- */
- public static String removeEnd(String str, String remove) {
- if (isEmpty(str) || isEmpty(remove)) {
- return str;
- }
- if (str.endsWith(remove)) {
- return str.substring(0, str.length() - remove.length());
- }
- return str;
- }
-
- /**
- *
- * StringUtils.removeEndIgnoreCase(null, *) = null
- * StringUtils.removeEndIgnoreCase("", *) = ""
- * StringUtils.removeEndIgnoreCase(*, null) = *
- * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.") = "www.domain.com"
- * StringUtils.removeEndIgnoreCase("www.domain.com", ".com") = "www.domain"
- * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
- * StringUtils.removeEndIgnoreCase("abc", "") = "abc"
- * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
- * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
- *
- *
- * @param str the source String to search, may be null
- * @param remove the String to search for (case insensitive) and remove, may be null
- * @return the substring with the string removed if found,
- * {@code null} if null String input
- * @since 2.4
- */
- public static String removeEndIgnoreCase(String str, String remove) {
- if (isEmpty(str) || isEmpty(remove)) {
- return str;
- }
- if (endsWithIgnoreCase(str, remove)) {
- return str.substring(0, str.length() - remove.length());
- }
- return str;
- }
-
- /**
- *
- * StringUtils.remove(null, *) = null
- * StringUtils.remove("", *) = ""
- * StringUtils.remove(*, null) = *
- * StringUtils.remove(*, "") = *
- * StringUtils.remove("queued", "ue") = "qd"
- * StringUtils.remove("queued", "zz") = "queued"
- *
- *
- * @param str the source String to search, may be null
- * @param remove the String to search for and remove, may be null
- * @return the substring with the string removed if found,
- * {@code null} if null String input
- * @since 2.1
- */
- public static String remove(String str, String remove) {
- if (isEmpty(str) || isEmpty(remove)) {
- return str;
- }
- return replace(str, remove, EMPTY, -1);
- }
-
- /**
- *
- * StringUtils.remove(null, *) = null
- * StringUtils.remove("", *) = ""
- * StringUtils.remove("queued", 'u') = "qeed"
- * StringUtils.remove("queued", 'z') = "queued"
- *
- *
- * @param str the source String to search, may be null
- * @param remove the char to search for and remove, may be null
- * @return the substring with the char removed if found,
- * {@code null} if null String input
- * @since 2.1
- */
- public static String remove(String str, char remove) {
- if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
- return str;
- }
- char[] chars = str.toCharArray();
- int pos = 0;
- for (int i = 0; i < chars.length; i++) {
- if (chars[i] != remove) {
- chars[pos++] = chars[i];
- }
- }
- return new String(chars, 0, pos);
- }
-
- // Replacing
- //-----------------------------------------------------------------------
- /**
- *
- * StringUtils.replaceOnce(null, *, *) = null
- * StringUtils.replaceOnce("", *, *) = ""
- * StringUtils.replaceOnce("any", null, *) = "any"
- * StringUtils.replaceOnce("any", *, null) = "any"
- * StringUtils.replaceOnce("any", "", *) = "any"
- * StringUtils.replaceOnce("aba", "a", null) = "aba"
- * StringUtils.replaceOnce("aba", "a", "") = "ba"
- * StringUtils.replaceOnce("aba", "a", "z") = "zba"
- *
- *
- * @see #replace(String text, String searchString, String replacement, int max)
- * @param text text to search and replace in, may be null
- * @param searchString the String to search for, may be null
- * @param replacement the String to replace with, may be null
- * @return the text with any replacements processed,
- * {@code null} if null String input
- */
- public static String replaceOnce(String text, String searchString, String replacement) {
- return replace(text, searchString, replacement, 1);
- }
-
- /**
- *
- * StringUtils.replace(null, *, *) = null
- * StringUtils.replace("", *, *) = ""
- * StringUtils.replace("any", null, *) = "any"
- * StringUtils.replace("any", *, null) = "any"
- * StringUtils.replace("any", "", *) = "any"
- * StringUtils.replace("aba", "a", null) = "aba"
- * StringUtils.replace("aba", "a", "") = "b"
- * StringUtils.replace("aba", "a", "z") = "zbz"
- *
- *
- * @see #replace(String text, String searchString, String replacement, int max)
- * @param text text to search and replace in, may be null
- * @param searchString the String to search for, may be null
- * @param replacement the String to replace it with, may be null
- * @return the text with any replacements processed,
- * {@code null} if null String input
- */
- public static String replace(String text, String searchString, String replacement) {
- return replace(text, searchString, replacement, -1);
- }
-
- /**
- *
- * StringUtils.replace(null, *, *, *) = null
- * StringUtils.replace("", *, *, *) = ""
- * StringUtils.replace("any", null, *, *) = "any"
- * StringUtils.replace("any", *, null, *) = "any"
- * StringUtils.replace("any", "", *, *) = "any"
- * StringUtils.replace("any", *, *, 0) = "any"
- * StringUtils.replace("abaa", "a", null, -1) = "abaa"
- * StringUtils.replace("abaa", "a", "", -1) = "b"
- * StringUtils.replace("abaa", "a", "z", 0) = "abaa"
- * StringUtils.replace("abaa", "a", "z", 1) = "zbaa"
- * StringUtils.replace("abaa", "a", "z", 2) = "zbza"
- * StringUtils.replace("abaa", "a", "z", -1) = "zbzz"
- *
- *
- * @param text text to search and replace in, may be null
- * @param searchString the String to search for, may be null
- * @param replacement the String to replace it with, may be null
- * @param max maximum number of values to replace, or {@code -1} if no maximum
- * @return the text with any replacements processed,
- * {@code null} if null String input
- */
- public static String replace(String text, String searchString, String replacement, int max) {
- if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
- return text;
- }
- int start = 0;
- int end = text.indexOf(searchString, start);
- if (end == INDEX_NOT_FOUND) {
- return text;
- }
- int replLength = searchString.length();
- int increase = replacement.length() - replLength;
- increase = (increase < 0 ? 0 : increase);
- increase *= (max < 0 ? 16 : (max > 64 ? 64 : max));
- StringBuilder buf = new StringBuilder(text.length() + increase);
- while (end != INDEX_NOT_FOUND) {
- buf.append(text.substring(start, end)).append(replacement);
- start = end + replLength;
- if (--max == 0) {
- break;
- }
- end = text.indexOf(searchString, start);
- }
- buf.append(text.substring(start));
- return buf.toString();
- }
-
- /**
- *
- * StringUtils.replaceEach(null, *, *) = null
- * StringUtils.replaceEach("", *, *) = ""
- * StringUtils.replaceEach("aba", null, null) = "aba"
- * StringUtils.replaceEach("aba", new String[0], null) = "aba"
- * StringUtils.replaceEach("aba", null, new String[0]) = "aba"
- * StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba"
- * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b"
- * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba"
- * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
- * (example of how it does not repeat)
- * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte"
- *
- *
- * @param text
- * text to search and replace in, no-op if null
- * @param searchList
- * the Strings to search for, no-op if null
- * @param replacementList
- * the Strings to replace them with, no-op if null
- * @return the text with any replacements processed, {@code null} if
- * null String input
- * @throws IllegalArgumentException
- * if the lengths of the arrays are not the same (null is ok,
- * and/or size 0)
- * @since 2.4
- */
- public static String replaceEach(String text, String[] searchList, String[] replacementList) {
- return replaceEach(text, searchList, replacementList, false, 0);
- }
-
- /**
- *
- * StringUtils.replaceEach(null, *, *, *) = null
- * StringUtils.replaceEach("", *, *, *) = ""
- * StringUtils.replaceEach("aba", null, null, *) = "aba"
- * StringUtils.replaceEach("aba", new String[0], null, *) = "aba"
- * StringUtils.replaceEach("aba", null, new String[0], *) = "aba"
- * StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba"
- * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b"
- * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba"
- * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte"
- * (example of how it repeats)
- * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte"
- * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte"
- * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, true) = IllegalStateException
- * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, false) = "dcabe"
- *
- *
- * @param text
- * text to search and replace in, no-op if null
- * @param searchList
- * the Strings to search for, no-op if null
- * @param replacementList
- * the Strings to replace them with, no-op if null
- * @return the text with any replacements processed, {@code null} if
- * null String input
- * @throws IllegalStateException
- * if the search is repeating and there is an endless loop due
- * to outputs of one being inputs to another
- * @throws IllegalArgumentException
- * if the lengths of the arrays are not the same (null is ok,
- * and/or size 0)
- * @since 2.4
- */
- public static String replaceEachRepeatedly(String text, String[] searchList, String[] replacementList) {
- // timeToLive should be 0 if not used or nothing to replace, else it's
- // the length of the replace array
- int timeToLive = searchList == null ? 0 : searchList.length;
- return replaceEach(text, searchList, replacementList, true, timeToLive);
- }
-
- /**
- *
- * StringUtils.replaceEach(null, *, *, *) = null
- * StringUtils.replaceEach("", *, *, *) = ""
- * StringUtils.replaceEach("aba", null, null, *) = "aba"
- * StringUtils.replaceEach("aba", new String[0], null, *) = "aba"
- * StringUtils.replaceEach("aba", null, new String[0], *) = "aba"
- * StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba"
- * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b"
- * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba"
- * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte"
- * (example of how it repeats)
- * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte"
- * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte"
- * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *) = IllegalStateException
- *
- *
- * @param text
- * text to search and replace in, no-op if null
- * @param searchList
- * the Strings to search for, no-op if null
- * @param replacementList
- * the Strings to replace them with, no-op if null
- * @param repeat if true, then replace repeatedly
- * until there are no more possible replacements or timeToLive < 0
- * @param timeToLive
- * if less than 0 then there is a circular reference and endless
- * loop
- * @return the text with any replacements processed, {@code null} if
- * null String input
- * @throws IllegalStateException
- * if the search is repeating and there is an endless loop due
- * to outputs of one being inputs to another
- * @throws IllegalArgumentException
- * if the lengths of the arrays are not the same (null is ok,
- * and/or size 0)
- * @since 2.4
- */
- private static String replaceEach(
- String text, String[] searchList, String[] replacementList, boolean repeat, int timeToLive) {
-
- // mchyzer Performance note: This creates very few new objects (one major goal)
- // let me know if there are performance requests, we can create a harness to measure
-
- if (text == null || text.length() == 0 || searchList == null ||
- searchList.length == 0 || replacementList == null || replacementList.length == 0) {
- return text;
- }
-
- // if recursing, this shouldn't be less than 0
- if (timeToLive < 0) {
- throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
- "output of one loop is the input of another");
- }
-
- int searchLength = searchList.length;
- int replacementLength = replacementList.length;
-
- // make sure lengths are ok, these need to be equal
- if (searchLength != replacementLength) {
- throw new IllegalArgumentException("Search and Replace array lengths don't match: "
- + searchLength
- + " vs "
- + replacementLength);
- }
-
- // keep track of which still have matches
- boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
-
- // index on index that the match was found
- int textIndex = -1;
- int replaceIndex = -1;
- int tempIndex = -1;
-
- // index of replace array that will replace the search string found
- // NOTE: logic duplicated below START
- for (int i = 0; i < searchLength; i++) {
- if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
- searchList[i].length() == 0 || replacementList[i] == null) {
- continue;
- }
- tempIndex = text.indexOf(searchList[i]);
-
- // see if we need to keep searching for this
- if (tempIndex == -1) {
- noMoreMatchesForReplIndex[i] = true;
- } else {
- if (textIndex == -1 || tempIndex < textIndex) {
- textIndex = tempIndex;
- replaceIndex = i;
- }
- }
- }
- // NOTE: logic mostly below END
-
- // no search strings found, we are done
- if (textIndex == -1) {
- return text;
- }
-
- int start = 0;
-
- // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
- int increase = 0;
-
- // count the replacement text elements that are larger than their corresponding text being replaced
- for (int i = 0; i < searchList.length; i++) {
- if (searchList[i] == null || replacementList[i] == null) {
- continue;
- }
- int greater = replacementList[i].length() - searchList[i].length();
- if (greater > 0) {
- increase += 3 * greater; // assume 3 matches
- }
- }
- // have upper-bound at 20% increase, then let Java take over
- increase = Math.min(increase, text.length() / 5);
-
- StringBuilder buf = new StringBuilder(text.length() + increase);
-
- while (textIndex != -1) {
-
- for (int i = start; i < textIndex; i++) {
- buf.append(text.charAt(i));
- }
- buf.append(replacementList[replaceIndex]);
-
- start = textIndex + searchList[replaceIndex].length();
-
- textIndex = -1;
- replaceIndex = -1;
- tempIndex = -1;
- // find the next earliest match
- // NOTE: logic mostly duplicated above START
- for (int i = 0; i < searchLength; i++) {
- if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
- searchList[i].length() == 0 || replacementList[i] == null) {
- continue;
- }
- tempIndex = text.indexOf(searchList[i], start);
-
- // see if we need to keep searching for this
- if (tempIndex == -1) {
- noMoreMatchesForReplIndex[i] = true;
- } else {
- if (textIndex == -1 || tempIndex < textIndex) {
- textIndex = tempIndex;
- replaceIndex = i;
- }
- }
- }
- // NOTE: logic duplicated above END
-
- }
- int textLength = text.length();
- for (int i = start; i < textLength; i++) {
- buf.append(text.charAt(i));
- }
- String result = buf.toString();
- if (!repeat) {
- return result;
- }
-
- return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
- }
-
- // Replace, character based
- //-----------------------------------------------------------------------
- /**
- *
- * StringUtils.replaceChars(null, *, *) = null
- * StringUtils.replaceChars("", *, *) = ""
- * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
- * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
- *
- *
- * @param str String to replace characters in, may be null
- * @param searchChar the character to search for, may be null
- * @param replaceChar the character to replace, may be null
- * @return modified String, {@code null} if null string input
- * @since 2.0
- */
- public static String replaceChars(String str, char searchChar, char replaceChar) {
- if (str == null) {
- return null;
- }
- return str.replace(searchChar, replaceChar);
- }
-
- /**
- *
- * replaceChars("hello", "ho", "jy") = jelly.
- * StringUtils.replaceChars(null, *, *) = null
- * StringUtils.replaceChars("", *, *) = ""
- * StringUtils.replaceChars("abc", null, *) = "abc"
- * StringUtils.replaceChars("abc", "", *) = "abc"
- * StringUtils.replaceChars("abc", "b", null) = "ac"
- * StringUtils.replaceChars("abc", "b", "") = "ac"
- * StringUtils.replaceChars("abcba", "bc", "yz") = "ayzya"
- * StringUtils.replaceChars("abcba", "bc", "y") = "ayya"
- * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
- *
- *
- * @param str String to replace characters in, may be null
- * @param searchChars a set of characters to search for, may be null
- * @param replaceChars a set of characters to replace, may be null
- * @return modified String, {@code null} if null string input
- * @since 2.0
- */
- public static String replaceChars(String str, String searchChars, String replaceChars) {
- if (isEmpty(str) || isEmpty(searchChars)) {
- return str;
- }
- if (replaceChars == null) {
- replaceChars = EMPTY;
- }
- boolean modified = false;
- int replaceCharsLength = replaceChars.length();
- int strLength = str.length();
- StringBuilder buf = new StringBuilder(strLength);
- for (int i = 0; i < strLength; i++) {
- char ch = str.charAt(i);
- int index = searchChars.indexOf(ch);
- if (index >= 0) {
- modified = true;
- if (index < replaceCharsLength) {
- buf.append(replaceChars.charAt(index));
- }
- } else {
- buf.append(ch);
- }
- }
- if (modified) {
- return buf.toString();
- }
- return str;
- }
-
- // Overlay
- //-----------------------------------------------------------------------
- /**
- *
- * StringUtils.overlay(null, *, *, *) = null
- * StringUtils.overlay("", "abc", 0, 0) = "abc"
- * StringUtils.overlay("abcdef", null, 2, 4) = "abef"
- * StringUtils.overlay("abcdef", "", 2, 4) = "abef"
- * StringUtils.overlay("abcdef", "", 4, 2) = "abef"
- * StringUtils.overlay("abcdef", "zzzz", 2, 4) = "abzzzzef"
- * StringUtils.overlay("abcdef", "zzzz", 4, 2) = "abzzzzef"
- * StringUtils.overlay("abcdef", "zzzz", -1, 4) = "zzzzef"
- * StringUtils.overlay("abcdef", "zzzz", 2, 8) = "abzzzz"
- * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
- * StringUtils.overlay("abcdef", "zzzz", 8, 10) = "abcdefzzzz"
- *
- *
- * @param str the String to do overlaying in, may be null
- * @param overlay the String to overlay, may be null
- * @param start the position to start overlaying at
- * @param end the position to stop overlaying before
- * @return overlayed String, {@code null} if null String input
- * @since 2.0
- */
- public static String overlay(String str, String overlay, int start, int end) {
- if (str == null) {
- return null;
- }
- if (overlay == null) {
- overlay = EMPTY;
- }
- int len = str.length();
- if (start < 0) {
- start = 0;
- }
- if (start > len) {
- start = len;
- }
- if (end < 0) {
- end = 0;
- }
- if (end > len) {
- end = len;
- }
- if (start > end) {
- int temp = start;
- start = end;
- end = temp;
- }
- return new StringBuilder(len + start - end + overlay.length() + 1)
- .append(str.substring(0, start))
- .append(overlay)
- .append(str.substring(end))
- .toString();
- }
-
- // Chomping
- //-----------------------------------------------------------------------
- /**
- *
- * StringUtils.chomp(null) = null
- * StringUtils.chomp("") = ""
- * StringUtils.chomp("abc \r") = "abc "
- * StringUtils.chomp("abc\n") = "abc"
- * StringUtils.chomp("abc\r\n") = "abc"
- * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
- * StringUtils.chomp("abc\n\r") = "abc\n"
- * StringUtils.chomp("abc\n\rabc") = "abc\n\rabc"
- * StringUtils.chomp("\r") = ""
- * StringUtils.chomp("\n") = ""
- * StringUtils.chomp("\r\n") = ""
- *
- *
- * @param str the String to chomp a newline from, may be null
- * @return String without newline, {@code null} if null String input
- */
- public static String chomp(String str) {
- if (isEmpty(str)) {
- return str;
- }
-
- if (str.length() == 1) {
- char ch = str.charAt(0);
- if (ch == CharUtils.CR || ch == CharUtils.LF) {
- return EMPTY;
- }
- return str;
- }
-
- int lastIdx = str.length() - 1;
- char last = str.charAt(lastIdx);
-
- if (last == CharUtils.LF) {
- if (str.charAt(lastIdx - 1) == CharUtils.CR) {
- lastIdx--;
- }
- } else if (last != CharUtils.CR) {
- lastIdx++;
- }
- return str.substring(0, lastIdx);
- }
-
- // Chopping
- //-----------------------------------------------------------------------
- /**
- *
- * StringUtils.chop(null) = null
- * StringUtils.chop("") = ""
- * StringUtils.chop("abc \r") = "abc "
- * StringUtils.chop("abc\n") = "abc"
- * StringUtils.chop("abc\r\n") = "abc"
- * StringUtils.chop("abc") = "ab"
- * StringUtils.chop("abc\nabc") = "abc\nab"
- * StringUtils.chop("a") = ""
- * StringUtils.chop("\r") = ""
- * StringUtils.chop("\n") = ""
- * StringUtils.chop("\r\n") = ""
- *
- *
- * @param str the String to chop last character from, may be null
- * @return String without last character, {@code null} if null String input
- */
- public static String chop(String str) {
- if (str == null) {
- return null;
- }
- int strLen = str.length();
- if (strLen < 2) {
- return EMPTY;
- }
- int lastIdx = strLen - 1;
- String ret = str.substring(0, lastIdx);
- char last = str.charAt(lastIdx);
- if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
- return ret.substring(0, lastIdx - 1);
- }
- return ret;
- }
-
- // Conversion
- //-----------------------------------------------------------------------
-
- // Padding
- //-----------------------------------------------------------------------
- /**
- *
- * StringUtils.repeat(null, 2) = null
- * StringUtils.repeat("", 0) = ""
- * StringUtils.repeat("", 2) = ""
- * StringUtils.repeat("a", 3) = "aaa"
- * StringUtils.repeat("ab", 2) = "abab"
- * StringUtils.repeat("a", -2) = ""
- *
- *
- * @param str the String to repeat, may be null
- * @param repeat number of times to repeat str, negative treated as zero
- * @return a new String consisting of the original String repeated,
- * {@code null} if null String input
- */
- public static String repeat(String str, int repeat) {
- // Performance tuned for 2.0 (JDK1.4)
-
- if (str == null) {
- return null;
- }
- if (repeat <= 0) {
- return EMPTY;
- }
- int inputLength = str.length();
- if (repeat == 1 || inputLength == 0) {
- return str;
- }
- if (inputLength == 1 && repeat <= PAD_LIMIT) {
- return repeat(str.charAt(0), repeat);
- }
-
- int outputLength = inputLength * repeat;
- switch (inputLength) {
- case 1 :
- return repeat(str.charAt(0), repeat);
- case 2 :
- char ch0 = str.charAt(0);
- char ch1 = str.charAt(1);
- char[] output2 = new char[outputLength];
- for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
- output2[i] = ch0;
- output2[i + 1] = ch1;
- }
- return new String(output2);
- default :
- StringBuilder buf = new StringBuilder(outputLength);
- for (int i = 0; i < repeat; i++) {
- buf.append(str);
- }
- return buf.toString();
- }
- }
-
- /**
- *
- * StringUtils.repeat(null, null, 2) = null
- * StringUtils.repeat(null, "x", 2) = null
- * StringUtils.repeat("", null, 0) = ""
- * StringUtils.repeat("", "", 2) = ""
- * StringUtils.repeat("", "x", 3) = "xxx"
- * StringUtils.repeat("?", ", ", 3) = "?, ?, ?"
- *
- *
- * @param str the String to repeat, may be null
- * @param separator the String to inject, may be null
- * @param repeat number of times to repeat str, negative treated as zero
- * @return a new String consisting of the original String repeated,
- * {@code null} if null String input
- * @since 2.5
- */
- public static String repeat(String str, String separator, int repeat) {
- if(str == null || separator == null) {
- return repeat(str, repeat);
- } else {
- // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
- String result = repeat(str + separator, repeat);
- return removeEnd(result, separator);
- }
- }
-
- /**
- *
- * StringUtils.repeat(0, 'e') = ""
- * StringUtils.repeat(3, 'e') = "eee"
- * StringUtils.repeat(-2, 'e') = ""
- *
- *
- *
- * StringUtils.rightPad(null, *) = null
- * StringUtils.rightPad("", 3) = " "
- * StringUtils.rightPad("bat", 3) = "bat"
- * StringUtils.rightPad("bat", 5) = "bat "
- * StringUtils.rightPad("bat", 1) = "bat"
- * StringUtils.rightPad("bat", -1) = "bat"
- *
- *
- * @param str the String to pad out, may be null
- * @param size the size to pad to
- * @return right padded String or original String if no padding is necessary,
- * {@code null} if null String input
- */
- public static String rightPad(String str, int size) {
- return rightPad(str, size, ' ');
- }
-
- /**
- *
- * StringUtils.rightPad(null, *, *) = null
- * StringUtils.rightPad("", 3, 'z') = "zzz"
- * StringUtils.rightPad("bat", 3, 'z') = "bat"
- * StringUtils.rightPad("bat", 5, 'z') = "batzz"
- * StringUtils.rightPad("bat", 1, 'z') = "bat"
- * StringUtils.rightPad("bat", -1, 'z') = "bat"
- *
- *
- * @param str the String to pad out, may be null
- * @param size the size to pad to
- * @param padChar the character to pad with
- * @return right padded String or original String if no padding is necessary,
- * {@code null} if null String input
- * @since 2.0
- */
- public static String rightPad(String str, int size, char padChar) {
- if (str == null) {
- return null;
- }
- int pads = size - str.length();
- if (pads <= 0) {
- return str; // returns original String when possible
- }
- if (pads > PAD_LIMIT) {
- return rightPad(str, size, String.valueOf(padChar));
- }
- return str.concat(repeat(padChar, pads));
- }
-
- /**
- *
- * StringUtils.rightPad(null, *, *) = null
- * StringUtils.rightPad("", 3, "z") = "zzz"
- * StringUtils.rightPad("bat", 3, "yz") = "bat"
- * StringUtils.rightPad("bat", 5, "yz") = "batyz"
- * StringUtils.rightPad("bat", 8, "yz") = "batyzyzy"
- * StringUtils.rightPad("bat", 1, "yz") = "bat"
- * StringUtils.rightPad("bat", -1, "yz") = "bat"
- * StringUtils.rightPad("bat", 5, null) = "bat "
- * StringUtils.rightPad("bat", 5, "") = "bat "
- *
- *
- * @param str the String to pad out, may be null
- * @param size the size to pad to
- * @param padStr the String to pad with, null or empty treated as single space
- * @return right padded String or original String if no padding is necessary,
- * {@code null} if null String input
- */
- public static String rightPad(String str, int size, String padStr) {
- if (str == null) {
- return null;
- }
- if (isEmpty(padStr)) {
- padStr = " ";
- }
- int padLen = padStr.length();
- int strLen = str.length();
- int pads = size - strLen;
- if (pads <= 0) {
- return str; // returns original String when possible
- }
- if (padLen == 1 && pads <= PAD_LIMIT) {
- return rightPad(str, size, padStr.charAt(0));
- }
-
- if (pads == padLen) {
- return str.concat(padStr);
- } else if (pads < padLen) {
- return str.concat(padStr.substring(0, pads));
- } else {
- char[] padding = new char[pads];
- char[] padChars = padStr.toCharArray();
- for (int i = 0; i < pads; i++) {
- padding[i] = padChars[i % padLen];
- }
- return str.concat(new String(padding));
- }
- }
-
- /**
- *
- * StringUtils.leftPad(null, *) = null
- * StringUtils.leftPad("", 3) = " "
- * StringUtils.leftPad("bat", 3) = "bat"
- * StringUtils.leftPad("bat", 5) = " bat"
- * StringUtils.leftPad("bat", 1) = "bat"
- * StringUtils.leftPad("bat", -1) = "bat"
- *
- *
- * @param str the String to pad out, may be null
- * @param size the size to pad to
- * @return left padded String or original String if no padding is necessary,
- * {@code null} if null String input
- */
- public static String leftPad(String str, int size) {
- return leftPad(str, size, ' ');
- }
-
- /**
- *
- * StringUtils.leftPad(null, *, *) = null
- * StringUtils.leftPad("", 3, 'z') = "zzz"
- * StringUtils.leftPad("bat", 3, 'z') = "bat"
- * StringUtils.leftPad("bat", 5, 'z') = "zzbat"
- * StringUtils.leftPad("bat", 1, 'z') = "bat"
- * StringUtils.leftPad("bat", -1, 'z') = "bat"
- *
- *
- * @param str the String to pad out, may be null
- * @param size the size to pad to
- * @param padChar the character to pad with
- * @return left padded String or original String if no padding is necessary,
- * {@code null} if null String input
- * @since 2.0
- */
- public static String leftPad(String str, int size, char padChar) {
- if (str == null) {
- return null;
- }
- int pads = size - str.length();
- if (pads <= 0) {
- return str; // returns original String when possible
- }
- if (pads > PAD_LIMIT) {
- return leftPad(str, size, String.valueOf(padChar));
- }
- return repeat(padChar, pads).concat(str);
- }
-
- /**
- *
- * StringUtils.leftPad(null, *, *) = null
- * StringUtils.leftPad("", 3, "z") = "zzz"
- * StringUtils.leftPad("bat", 3, "yz") = "bat"
- * StringUtils.leftPad("bat", 5, "yz") = "yzbat"
- * StringUtils.leftPad("bat", 8, "yz") = "yzyzybat"
- * StringUtils.leftPad("bat", 1, "yz") = "bat"
- * StringUtils.leftPad("bat", -1, "yz") = "bat"
- * StringUtils.leftPad("bat", 5, null) = " bat"
- * StringUtils.leftPad("bat", 5, "") = " bat"
- *
- *
- * @param str the String to pad out, may be null
- * @param size the size to pad to
- * @param padStr the String to pad with, null or empty treated as single space
- * @return left padded String or original String if no padding is necessary,
- * {@code null} if null String input
- */
- public static String leftPad(String str, int size, String padStr) {
- if (str == null) {
- return null;
- }
- if (isEmpty(padStr)) {
- padStr = " ";
- }
- int padLen = padStr.length();
- int strLen = str.length();
- int pads = size - strLen;
- if (pads <= 0) {
- return str; // returns original String when possible
- }
- if (padLen == 1 && pads <= PAD_LIMIT) {
- return leftPad(str, size, padStr.charAt(0));
- }
-
- if (pads == padLen) {
- return padStr.concat(str);
- } else if (pads < padLen) {
- return padStr.substring(0, pads).concat(str);
- } else {
- char[] padding = new char[pads];
- char[] padChars = padStr.toCharArray();
- for (int i = 0; i < pads; i++) {
- padding[i] = padChars[i % padLen];
- }
- return new String(padding).concat(str);
- }
- }
-
- /**
- * Gets a CharSequence length or {@code 0} if the CharSequence is
- * {@code null}.
- *
- * @param cs
- * a CharSequence or {@code null}
- * @return CharSequence length or {@code 0} if the CharSequence is
- * {@code null}.
- * @since 2.4
- * @since 3.0 Changed signature from length(String) to length(CharSequence)
- */
- public static int length(CharSequence cs) {
- return cs == null ? 0 : cs.length();
- }
-
- // Centering
- //-----------------------------------------------------------------------
- /**
- *
- * StringUtils.center(null, *) = null
- * StringUtils.center("", 4) = " "
- * StringUtils.center("ab", -1) = "ab"
- * StringUtils.center("ab", 4) = " ab "
- * StringUtils.center("abcd", 2) = "abcd"
- * StringUtils.center("a", 4) = " a "
- *
- *
- * @param str the String to center, may be null
- * @param size the int size of new String, negative treated as zero
- * @return centered String, {@code null} if null String input
- */
- public static String center(String str, int size) {
- return center(str, size, ' ');
- }
-
- /**
- *
- * StringUtils.center(null, *, *) = null
- * StringUtils.center("", 4, ' ') = " "
- * StringUtils.center("ab", -1, ' ') = "ab"
- * StringUtils.center("ab", 4, ' ') = " ab"
- * StringUtils.center("abcd", 2, ' ') = "abcd"
- * StringUtils.center("a", 4, ' ') = " a "
- * StringUtils.center("a", 4, 'y') = "yayy"
- *
- *
- * @param str the String to center, may be null
- * @param size the int size of new String, negative treated as zero
- * @param padChar the character to pad the new String with
- * @return centered String, {@code null} if null String input
- * @since 2.0
- */
- public static String center(String str, int size, char padChar) {
- if (str == null || size <= 0) {
- return str;
- }
- int strLen = str.length();
- int pads = size - strLen;
- if (pads <= 0) {
- return str;
- }
- str = leftPad(str, strLen + pads / 2, padChar);
- str = rightPad(str, size, padChar);
- return str;
- }
-
- /**
- *
- * StringUtils.center(null, *, *) = null
- * StringUtils.center("", 4, " ") = " "
- * StringUtils.center("ab", -1, " ") = "ab"
- * StringUtils.center("ab", 4, " ") = " ab"
- * StringUtils.center("abcd", 2, " ") = "abcd"
- * StringUtils.center("a", 4, " ") = " a "
- * StringUtils.center("a", 4, "yz") = "yayz"
- * StringUtils.center("abc", 7, null) = " abc "
- * StringUtils.center("abc", 7, "") = " abc "
- *
- *
- * @param str the String to center, may be null
- * @param size the int size of new String, negative treated as zero
- * @param padStr the String to pad the new String with, must not be null or empty
- * @return centered String, {@code null} if null String input
- * @throws IllegalArgumentException if padStr is {@code null} or empty
- */
- public static String center(String str, int size, String padStr) {
- if (str == null || size <= 0) {
- return str;
- }
- if (isEmpty(padStr)) {
- padStr = " ";
- }
- int strLen = str.length();
- int pads = size - strLen;
- if (pads <= 0) {
- return str;
- }
- str = leftPad(str, strLen + pads / 2, padStr);
- str = rightPad(str, size, padStr);
- return str;
- }
-
- // Case conversion
- //-----------------------------------------------------------------------
- /**
- *
- * StringUtils.upperCase(null) = null
- * StringUtils.upperCase("") = ""
- * StringUtils.upperCase("aBc") = "ABC"
- *
- *
- *
- * StringUtils.upperCase(null, Locale.ENGLISH) = null
- * StringUtils.upperCase("", Locale.ENGLISH) = ""
- * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
- *
- *
- * @param str the String to upper case, may be null
- * @param locale the locale that defines the case transformation rules, must not be null
- * @return the upper cased String, {@code null} if null String input
- * @since 2.5
- */
- public static String upperCase(String str, Locale locale) {
- if (str == null) {
- return null;
- }
- return str.toUpperCase(locale);
- }
-
- /**
- *
- * StringUtils.lowerCase(null) = null
- * StringUtils.lowerCase("") = ""
- * StringUtils.lowerCase("aBc") = "abc"
- *
- *
- *
- * StringUtils.lowerCase(null, Locale.ENGLISH) = null
- * StringUtils.lowerCase("", Locale.ENGLISH) = ""
- * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
- *
- *
- * @param str the String to lower case, may be null
- * @param locale the locale that defines the case transformation rules, must not be null
- * @return the lower cased String, {@code null} if null String input
- * @since 2.5
- */
- public static String lowerCase(String str, Locale locale) {
- if (str == null) {
- return null;
- }
- return str.toLowerCase(locale);
- }
-
- /**
- *
- * StringUtils.capitalize(null) = null
- * StringUtils.capitalize("") = ""
- * StringUtils.capitalize("cat") = "Cat"
- * StringUtils.capitalize("cAt") = "CAt"
- *
- *
- * @param str the String to capitalize, may be null
- * @return the capitalized String, {@code null} if null String input
- * @see org.apache.commons.lang3.text.WordUtils#capitalize(String)
- * @see #uncapitalize(String)
- * @since 2.0
- */
- public static String capitalize(String str) {
- int strLen;
- if (str == null || (strLen = str.length()) == 0) {
- return str;
- }
- return new StringBuilder(strLen)
- .append(Character.toTitleCase(str.charAt(0)))
- .append(str.substring(1))
- .toString();
- }
-
- /**
- *
- * StringUtils.uncapitalize(null) = null
- * StringUtils.uncapitalize("") = ""
- * StringUtils.uncapitalize("Cat") = "cat"
- * StringUtils.uncapitalize("CAT") = "cAT"
- *
- *
- * @param str the String to uncapitalize, may be null
- * @return the uncapitalized String, {@code null} if null String input
- * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String)
- * @see #capitalize(String)
- * @since 2.0
- */
- public static String uncapitalize(String str) {
- int strLen;
- if (str == null || (strLen = str.length()) == 0) {
- return str;
- }
- return new StringBuilder(strLen)
- .append(Character.toLowerCase(str.charAt(0)))
- .append(str.substring(1))
- .toString();
- }
-
- /**
- *
- *
- *
- *
- * StringUtils.swapCase(null) = null
- * StringUtils.swapCase("") = ""
- * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
- *
- *
- *
- * StringUtils.countMatches(null, *) = 0
- * StringUtils.countMatches("", *) = 0
- * StringUtils.countMatches("abba", null) = 0
- * StringUtils.countMatches("abba", "") = 0
- * StringUtils.countMatches("abba", "a") = 2
- * StringUtils.countMatches("abba", "ab") = 1
- * StringUtils.countMatches("abba", "xxx") = 0
- *
- *
- * @param str the CharSequence to check, may be null
- * @param sub the substring to count, may be null
- * @return the number of occurrences, 0 if either CharSequence is {@code null}
- * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
- */
- public static int countMatches(CharSequence str, CharSequence sub) {
- if (isEmpty(str) || isEmpty(sub)) {
- return 0;
- }
- int count = 0;
- int idx = 0;
- while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
- count++;
- idx += sub.length();
- }
- return count;
- }
-
- // Character Tests
- //-----------------------------------------------------------------------
- /**
- *
- * StringUtils.isAlpha(null) = false
- * StringUtils.isAlpha("") = false
- * StringUtils.isAlpha(" ") = false
- * StringUtils.isAlpha("abc") = true
- * StringUtils.isAlpha("ab2c") = false
- * StringUtils.isAlpha("ab-c") = false
- *
- *
- * @param cs the CharSequence to check, may be null
- * @return {@code true} if only contains letters, and is non-null
- * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
- * @since 3.0 Changed "" to return false and not true
- */
- public static boolean isAlpha(CharSequence cs) {
- if (cs == null || cs.length() == 0) {
- return false;
- }
- int sz = cs.length();
- for (int i = 0; i < sz; i++) {
- if (Character.isLetter(cs.charAt(i)) == false) {
- return false;
- }
- }
- return true;
- }
-
- /**
- *
- * StringUtils.isAlphaSpace(null) = false
- * StringUtils.isAlphaSpace("") = true
- * StringUtils.isAlphaSpace(" ") = true
- * StringUtils.isAlphaSpace("abc") = true
- * StringUtils.isAlphaSpace("ab c") = true
- * StringUtils.isAlphaSpace("ab2c") = false
- * StringUtils.isAlphaSpace("ab-c") = false
- *
- *
- * @param cs the CharSequence to check, may be null
- * @return {@code true} if only contains letters and space,
- * and is non-null
- * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
- */
- public static boolean isAlphaSpace(CharSequence cs) {
- if (cs == null) {
- return false;
- }
- int sz = cs.length();
- for (int i = 0; i < sz; i++) {
- if ((Character.isLetter(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) {
- return false;
- }
- }
- return true;
- }
-
- /**
- *
- * StringUtils.isAlphanumeric(null) = false
- * StringUtils.isAlphanumeric("") = false
- * StringUtils.isAlphanumeric(" ") = false
- * StringUtils.isAlphanumeric("abc") = true
- * StringUtils.isAlphanumeric("ab c") = false
- * StringUtils.isAlphanumeric("ab2c") = true
- * StringUtils.isAlphanumeric("ab-c") = false
- *
- *
- * @param cs the CharSequence to check, may be null
- * @return {@code true} if only contains letters or digits,
- * and is non-null
- * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
- * @since 3.0 Changed "" to return false and not true
- */
- public static boolean isAlphanumeric(CharSequence cs) {
- if (cs == null || cs.length() == 0) {
- return false;
- }
- int sz = cs.length();
- for (int i = 0; i < sz; i++) {
- if (Character.isLetterOrDigit(cs.charAt(i)) == false) {
- return false;
- }
- }
- return true;
- }
-
- /**
- *
- * StringUtils.isAlphanumericSpace(null) = false
- * StringUtils.isAlphanumericSpace("") = true
- * StringUtils.isAlphanumericSpace(" ") = true
- * StringUtils.isAlphanumericSpace("abc") = true
- * StringUtils.isAlphanumericSpace("ab c") = true
- * StringUtils.isAlphanumericSpace("ab2c") = true
- * StringUtils.isAlphanumericSpace("ab-c") = false
- *
- *
- * @param cs the CharSequence to check, may be null
- * @return {@code true} if only contains letters, digits or space,
- * and is non-null
- * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
- */
- public static boolean isAlphanumericSpace(CharSequence cs) {
- if (cs == null) {
- return false;
- }
- int sz = cs.length();
- for (int i = 0; i < sz; i++) {
- if ((Character.isLetterOrDigit(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) {
- return false;
- }
- }
- return true;
- }
-
- /**
- *
- * StringUtils.isAsciiPrintable(null) = false
- * StringUtils.isAsciiPrintable("") = true
- * StringUtils.isAsciiPrintable(" ") = true
- * StringUtils.isAsciiPrintable("Ceki") = true
- * StringUtils.isAsciiPrintable("ab2c") = true
- * StringUtils.isAsciiPrintable("!ab-c~") = true
- * StringUtils.isAsciiPrintable("\u0020") = true
- * StringUtils.isAsciiPrintable("\u0021") = true
- * StringUtils.isAsciiPrintable("\u007e") = true
- * StringUtils.isAsciiPrintable("\u007f") = false
- * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
- *
- *
- * @param cs the CharSequence to check, may be null
- * @return {@code true} if every character is in the range
- * 32 thru 126
- * @since 2.1
- * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
- */
- public static boolean isAsciiPrintable(CharSequence cs) {
- if (cs == null) {
- return false;
- }
- int sz = cs.length();
- for (int i = 0; i < sz; i++) {
- if (CharUtils.isAsciiPrintable(cs.charAt(i)) == false) {
- return false;
- }
- }
- return true;
- }
-
- /**
- *
- * StringUtils.isNumeric(null) = false
- * StringUtils.isNumeric("") = false
- * StringUtils.isNumeric(" ") = false
- * StringUtils.isNumeric("123") = true
- * StringUtils.isNumeric("12 3") = false
- * StringUtils.isNumeric("ab2c") = false
- * StringUtils.isNumeric("12-3") = false
- * StringUtils.isNumeric("12.3") = false
- *
- *
- * @param cs the CharSequence to check, may be null
- * @return {@code true} if only contains digits, and is non-null
- * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
- * @since 3.0 Changed "" to return false and not true
- */
- public static boolean isNumeric(CharSequence cs) {
- if (cs == null || cs.length() == 0) {
- return false;
- }
- int sz = cs.length();
- for (int i = 0; i < sz; i++) {
- if (Character.isDigit(cs.charAt(i)) == false) {
- return false;
- }
- }
- return true;
- }
-
- /**
- *
- * StringUtils.isNumericSpace(null) = false
- * StringUtils.isNumericSpace("") = true
- * StringUtils.isNumericSpace(" ") = true
- * StringUtils.isNumericSpace("123") = true
- * StringUtils.isNumericSpace("12 3") = true
- * StringUtils.isNumericSpace("ab2c") = false
- * StringUtils.isNumericSpace("12-3") = false
- * StringUtils.isNumericSpace("12.3") = false
- *
- *
- * @param cs the CharSequence to check, may be null
- * @return {@code true} if only contains digits or space,
- * and is non-null
- * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
- */
- public static boolean isNumericSpace(CharSequence cs) {
- if (cs == null) {
- return false;
- }
- int sz = cs.length();
- for (int i = 0; i < sz; i++) {
- if ((Character.isDigit(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) {
- return false;
- }
- }
- return true;
- }
-
- /**
- *
- * StringUtils.isWhitespace(null) = false
- * StringUtils.isWhitespace("") = true
- * StringUtils.isWhitespace(" ") = true
- * StringUtils.isWhitespace("abc") = false
- * StringUtils.isWhitespace("ab2c") = false
- * StringUtils.isWhitespace("ab-c") = false
- *
- *
- * @param cs the CharSequence to check, may be null
- * @return {@code true} if only contains whitespace, and is non-null
- * @since 2.0
- * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
- */
- public static boolean isWhitespace(CharSequence cs) {
- if (cs == null) {
- return false;
- }
- int sz = cs.length();
- for (int i = 0; i < sz; i++) {
- if ((Character.isWhitespace(cs.charAt(i)) == false)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- *
- * StringUtils.isAllLowerCase(null) = false
- * StringUtils.isAllLowerCase("") = false
- * StringUtils.isAllLowerCase(" ") = false
- * StringUtils.isAllLowerCase("abc") = true
- * StringUtils.isAllLowerCase("abC") = false
- *
- *
- * @param cs the CharSequence to check, may be null
- * @return {@code true} if only contains lowercase characters, and is non-null
- * @since 2.5
- * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
- */
- public static boolean isAllLowerCase(CharSequence cs) {
- if (cs == null || isEmpty(cs)) {
- return false;
- }
- int sz = cs.length();
- for (int i = 0; i < sz; i++) {
- if (Character.isLowerCase(cs.charAt(i)) == false) {
- return false;
- }
- }
- return true;
- }
-
- /**
- *
- * StringUtils.isAllUpperCase(null) = false
- * StringUtils.isAllUpperCase("") = false
- * StringUtils.isAllUpperCase(" ") = false
- * StringUtils.isAllUpperCase("ABC") = true
- * StringUtils.isAllUpperCase("aBC") = false
- *
- *
- * @param cs the CharSequence to check, may be null
- * @return {@code true} if only contains uppercase characters, and is non-null
- * @since 2.5
- * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
- */
- public static boolean isAllUpperCase(CharSequence cs) {
- if (cs == null || isEmpty(cs)) {
- return false;
- }
- int sz = cs.length();
- for (int i = 0; i < sz; i++) {
- if (Character.isUpperCase(cs.charAt(i)) == false) {
- return false;
- }
- }
- return true;
- }
-
- // Defaults
- //-----------------------------------------------------------------------
- /**
- *
- * StringUtils.defaultString(null) = ""
- * StringUtils.defaultString("") = ""
- * StringUtils.defaultString("bat") = "bat"
- *
- *
- * @see ObjectUtils#toString(Object)
- * @see String#valueOf(Object)
- * @param str the String to check, may be null
- * @return the passed in String, or the empty String if it
- * was {@code null}
- */
- public static String defaultString(String str) {
- return str == null ? EMPTY : str;
- }
-
- /**
- *
- * StringUtils.defaultString(null, "NULL") = "NULL"
- * StringUtils.defaultString("", "NULL") = ""
- * StringUtils.defaultString("bat", "NULL") = "bat"
- *
- *
- * @see ObjectUtils#toString(Object,String)
- * @see String#valueOf(Object)
- * @param str the String to check, may be null
- * @param defaultStr the default String to return
- * if the input is {@code null}, may be null
- * @return the passed in String, or the default if it was {@code null}
- */
- public static String defaultString(String str, String defaultStr) {
- return str == null ? defaultStr : str;
- }
-
- /**
- *
- * StringUtils.defaultIfBlank(null, "NULL") = "NULL"
- * StringUtils.defaultIfBlank("", "NULL") = "NULL"
- * StringUtils.defaultIfBlank(" ", "NULL") = "NULL"
- * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
- * StringUtils.defaultIfBlank("", null) = null
- *
- * @param
- * StringUtils.defaultIfEmpty(null, "NULL") = "NULL"
- * StringUtils.defaultIfEmpty("", "NULL") = "NULL"
- * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
- * StringUtils.defaultIfEmpty("", null) = null
- *
- * @param
- * StringUtils.reverse(null) = null
- * StringUtils.reverse("") = ""
- * StringUtils.reverse("bat") = "tab"
- *
- *
- * @param str the String to reverse, may be null
- * @return the reversed String, {@code null} if null String input
- */
- public static String reverse(String str) {
- if (str == null) {
- return null;
- }
- return new StringBuilder(str).reverse().toString();
- }
-
- /**
- *
- * StringUtils.reverseDelimited(null, *) = null
- * StringUtils.reverseDelimited("", *) = ""
- * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
- * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
- *
- *
- * @param str the String to reverse, may be null
- * @param separatorChar the separator character to use
- * @return the reversed String, {@code null} if null String input
- * @since 2.0
- */
- public static String reverseDelimited(String str, char separatorChar) {
- if (str == null) {
- return null;
- }
- // could implement manually, but simple way is to reuse other,
- // probably slower, methods.
- String[] strs = split(str, separatorChar);
- ArrayUtils.reverse(strs);
- return join(strs, separatorChar);
- }
-
- // Abbreviating
- //-----------------------------------------------------------------------
- /**
- *
- *
- *
- * StringUtils.abbreviate(null, *) = null
- * StringUtils.abbreviate("", 4) = ""
- * StringUtils.abbreviate("abcdefg", 6) = "abc..."
- * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
- * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
- * StringUtils.abbreviate("abcdefg", 4) = "a..."
- * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
- *
- *
- * @param str the String to check, may be null
- * @param maxWidth maximum length of result String, must be at least 4
- * @return abbreviated String, {@code null} if null String input
- * @throws IllegalArgumentException if the width is too small
- * @since 2.0
- */
- public static String abbreviate(String str, int maxWidth) {
- return abbreviate(str, 0, maxWidth);
- }
-
- /**
- * Abbreviates a String using ellipses. This will turn - * "Now is the time for all good men" into "...is the time for..."
- * - *Works like {@code abbreviate(String, int)}, but allows you to specify - * a "left edge" offset. Note that this left edge is not necessarily going to - * be the leftmost character in the result, or the first character following the - * ellipses, but it will appear somewhere in the result. - * - *
In no case will it return a String of length greater than - * {@code maxWidth}.
- * - *
- * StringUtils.abbreviate(null, *, *) = null
- * StringUtils.abbreviate("", 0, 4) = ""
- * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
- * StringUtils.abbreviate("abcdefghijklmno", 0, 10) = "abcdefg..."
- * StringUtils.abbreviate("abcdefghijklmno", 1, 10) = "abcdefg..."
- * StringUtils.abbreviate("abcdefghijklmno", 4, 10) = "abcdefg..."
- * StringUtils.abbreviate("abcdefghijklmno", 5, 10) = "...fghi..."
- * StringUtils.abbreviate("abcdefghijklmno", 6, 10) = "...ghij..."
- * StringUtils.abbreviate("abcdefghijklmno", 8, 10) = "...ijklmno"
- * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
- * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
- * StringUtils.abbreviate("abcdefghij", 0, 3) = IllegalArgumentException
- * StringUtils.abbreviate("abcdefghij", 5, 6) = IllegalArgumentException
- *
- *
- * @param str the String to check, may be null
- * @param offset left edge of source String
- * @param maxWidth maximum length of result String, must be at least 4
- * @return abbreviated String, {@code null} if null String input
- * @throws IllegalArgumentException if the width is too small
- * @since 2.0
- */
- public static String abbreviate(String str, int offset, int maxWidth) {
- if (str == null) {
- return null;
- }
- if (maxWidth < 4) {
- throw new IllegalArgumentException("Minimum abbreviation width is 4");
- }
- if (str.length() <= maxWidth) {
- return str;
- }
- if (offset > str.length()) {
- offset = str.length();
- }
- if ((str.length() - offset) < (maxWidth - 3)) {
- offset = str.length() - (maxWidth - 3);
- }
- final String abrevMarker = "...";
- if (offset <= 4) {
- return str.substring(0, maxWidth - 3) + abrevMarker;
- }
- if (maxWidth < 7) {
- throw new IllegalArgumentException("Minimum abbreviation width with offset is 7");
- }
- if ((offset + (maxWidth - 3)) < str.length()) {
- return abrevMarker + abbreviate(str.substring(offset), maxWidth - 3);
- }
- return abrevMarker + str.substring(str.length() - (maxWidth - 3));
- }
-
- /**
- * Abbreviates a String to the length passed, replacing the middle characters with the supplied - * replacement String.
- * - *This abbreviation only occurs if the following criteria is met: - *
- * StringUtils.abbreviateMiddle(null, null, 0) = null
- * StringUtils.abbreviateMiddle("abc", null, 0) = "abc"
- * StringUtils.abbreviateMiddle("abc", ".", 0) = "abc"
- * StringUtils.abbreviateMiddle("abc", ".", 3) = "abc"
- * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f"
- *
- *
- * @param str the String to abbreviate, may be null
- * @param middle the String to replace the middle characters with, may be null
- * @param length the length to abbreviate {@code str} to.
- * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
- * @since 2.5
- */
- public static String abbreviateMiddle(String str, String middle, int length) {
- if (isEmpty(str) || isEmpty(middle)) {
- return str;
- }
-
- if (length >= str.length() || length < (middle.length()+2)) {
- return str;
- }
-
- int targetSting = length-middle.length();
- int startOffset = targetSting/2+targetSting%2;
- int endOffset = str.length()-targetSting/2;
-
- StringBuilder builder = new StringBuilder(length);
- builder.append(str.substring(0,startOffset));
- builder.append(middle);
- builder.append(str.substring(endOffset));
-
- return builder.toString();
- }
-
- // Difference
- //-----------------------------------------------------------------------
- /**
- * Compares two Strings, and returns the portion where they differ. - * (More precisely, return the remainder of the second String, - * starting from where it's different from the first.)
- * - *For example, - * {@code difference("i am a machine", "i am a robot") -> "robot"}.
- * - *
- * StringUtils.difference(null, null) = null
- * StringUtils.difference("", "") = ""
- * StringUtils.difference("", "abc") = "abc"
- * StringUtils.difference("abc", "") = ""
- * StringUtils.difference("abc", "abc") = ""
- * StringUtils.difference("ab", "abxyz") = "xyz"
- * StringUtils.difference("abcde", "abxyz") = "xyz"
- * StringUtils.difference("abcde", "xyz") = "xyz"
- *
- *
- * @param str1 the first String, may be null
- * @param str2 the second String, may be null
- * @return the portion of str2 where it differs from str1; returns the
- * empty String if they are equal
- * @since 2.0
- */
- public static String difference(String str1, String str2) {
- if (str1 == null) {
- return str2;
- }
- if (str2 == null) {
- return str1;
- }
- int at = indexOfDifference(str1, str2);
- if (at == INDEX_NOT_FOUND) {
- return EMPTY;
- }
- return str2.substring(at);
- }
-
- /**
- * Compares two CharSequences, and returns the index at which the - * CharSequences begin to differ.
- * - *For example, - * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}
- * - *
- * StringUtils.indexOfDifference(null, null) = -1
- * StringUtils.indexOfDifference("", "") = -1
- * StringUtils.indexOfDifference("", "abc") = 0
- * StringUtils.indexOfDifference("abc", "") = 0
- * StringUtils.indexOfDifference("abc", "abc") = -1
- * StringUtils.indexOfDifference("ab", "abxyz") = 2
- * StringUtils.indexOfDifference("abcde", "abxyz") = 2
- * StringUtils.indexOfDifference("abcde", "xyz") = 0
- *
- *
- * @param cs1 the first CharSequence, may be null
- * @param cs2 the second CharSequence, may be null
- * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
- * @since 2.0
- * @since 3.0 Changed signature from indexOfDifference(String, String) to
- * indexOfDifference(CharSequence, CharSequence)
- */
- public static int indexOfDifference(CharSequence cs1, CharSequence cs2) {
- if (cs1 == cs2) {
- return INDEX_NOT_FOUND;
- }
- if (cs1 == null || cs2 == null) {
- return 0;
- }
- int i;
- for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
- if (cs1.charAt(i) != cs2.charAt(i)) {
- break;
- }
- }
- if (i < cs2.length() || i < cs1.length()) {
- return i;
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- * Compares all CharSequences in an array and returns the index at which the - * CharSequences begin to differ.
- * - *For example,
- * indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7
- * StringUtils.indexOfDifference(null) = -1
- * StringUtils.indexOfDifference(new String[] {}) = -1
- * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
- * StringUtils.indexOfDifference(new String[] {null, null}) = -1
- * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
- * StringUtils.indexOfDifference(new String[] {"", null}) = 0
- * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
- * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
- * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
- * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
- * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
- * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
- * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
- * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
- * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
- * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
- * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
- *
- *
- * @param css array of CharSequences, entries may be null
- * @return the index where the strings begin to differ; -1 if they are all equal
- * @since 2.4
- * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
- */
- public static int indexOfDifference(CharSequence... css) {
- if (css == null || css.length <= 1) {
- return INDEX_NOT_FOUND;
- }
- boolean anyStringNull = false;
- boolean allStringsNull = true;
- int arrayLen = css.length;
- int shortestStrLen = Integer.MAX_VALUE;
- int longestStrLen = 0;
-
- // find the min and max string lengths; this avoids checking to make
- // sure we are not exceeding the length of the string each time through
- // the bottom loop.
- for (int i = 0; i < arrayLen; i++) {
- if (css[i] == null) {
- anyStringNull = true;
- shortestStrLen = 0;
- } else {
- allStringsNull = false;
- shortestStrLen = Math.min(css[i].length(), shortestStrLen);
- longestStrLen = Math.max(css[i].length(), longestStrLen);
- }
- }
-
- // handle lists containing all nulls or all empty strings
- if (allStringsNull || (longestStrLen == 0 && !anyStringNull)) {
- return INDEX_NOT_FOUND;
- }
-
- // handle lists containing some nulls or some empty strings
- if (shortestStrLen == 0) {
- return 0;
- }
-
- // find the position with the first difference across all strings
- int firstDiff = -1;
- for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
- char comparisonChar = css[0].charAt(stringPos);
- for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
- if (css[arrayPos].charAt(stringPos) != comparisonChar) {
- firstDiff = stringPos;
- break;
- }
- }
- if (firstDiff != -1) {
- break;
- }
- }
-
- if (firstDiff == -1 && shortestStrLen != longestStrLen) {
- // we compared all of the characters up to the length of the
- // shortest string and didn't find a match, but the string lengths
- // vary, so return the length of the shortest string.
- return shortestStrLen;
- }
- return firstDiff;
- }
-
- /**
- * Compares all Strings in an array and returns the initial sequence of - * characters that is common to all of them.
- * - *For example,
- * getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -> "i am a "
- * StringUtils.getCommonPrefix(null) = ""
- * StringUtils.getCommonPrefix(new String[] {}) = ""
- * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
- * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
- * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
- * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
- * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
- * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
- * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
- * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
- * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
- * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
- * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
- * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
- * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
- * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
- * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
- *
- *
- * @param strs array of String objects, entries may be null
- * @return the initial sequence of characters that are common to all Strings
- * in the array; empty String if the array is null, the elements are all null
- * or if there is no common prefix.
- * @since 2.4
- */
- public static String getCommonPrefix(String... strs) {
- if (strs == null || strs.length == 0) {
- return EMPTY;
- }
- int smallestIndexOfDiff = indexOfDifference(strs);
- if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
- // all strings were identical
- if (strs[0] == null) {
- return EMPTY;
- }
- return strs[0];
- } else if (smallestIndexOfDiff == 0) {
- // there were no common initial characters
- return EMPTY;
- } else {
- // we found a common initial character sequence
- return strs[0].substring(0, smallestIndexOfDiff);
- }
- }
-
- // Misc
- //-----------------------------------------------------------------------
- /**
- * Find the Levenshtein distance between two Strings.
- * - *This is the number of changes needed to change one String into - * another, where each change is a single character modification (deletion, - * insertion or substitution).
- * - *The previous implementation of the Levenshtein distance algorithm - * was from http://www.merriampark.com/ld.htm
- * - *Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError
- * which can occur when my Java implementation is used with very large strings.
- * This implementation of the Levenshtein distance algorithm
- * is from http://www.merriampark.com/ldjava.htm
- * StringUtils.getLevenshteinDistance(null, *) = IllegalArgumentException
- * StringUtils.getLevenshteinDistance(*, null) = IllegalArgumentException
- * StringUtils.getLevenshteinDistance("","") = 0
- * StringUtils.getLevenshteinDistance("","a") = 1
- * StringUtils.getLevenshteinDistance("aaapppp", "") = 7
- * StringUtils.getLevenshteinDistance("frog", "fog") = 1
- * StringUtils.getLevenshteinDistance("fly", "ant") = 3
- * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
- * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
- * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
- * StringUtils.getLevenshteinDistance("hello", "hallo") = 1
- *
- *
- * @param s the first String, must not be null
- * @param t the second String, must not be null
- * @return result distance
- * @throws IllegalArgumentException if either String input {@code null}
- * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
- * getLevenshteinDistance(CharSequence, CharSequence)
- */
- public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
- if (s == null || t == null) {
- throw new IllegalArgumentException("Strings must not be null");
- }
-
- /*
- The difference between this impl. and the previous is that, rather
- than creating and retaining a matrix of size s.length() + 1 by t.length() + 1,
- we maintain two single-dimensional arrays of length s.length() + 1. The first, d,
- is the 'current working' distance array that maintains the newest distance cost
- counts as we iterate through the characters of String s. Each time we increment
- the index of String t we are comparing, d is copied to p, the second int[]. Doing so
- allows us to retain the previous cost counts as required by the algorithm (taking
- the minimum of the cost count to the left, up one, and diagonally up and to the left
- of the current cost count being calculated). (Note that the arrays aren't really
- copied anymore, just switched...this is clearly much better than cloning an array
- or doing a System.arraycopy() each time through the outer loop.)
-
- Effectively, the difference between the two implementations is this one does not
- cause an out of memory condition when calculating the LD over two very large strings.
- */
-
- int n = s.length(); // length of s
- int m = t.length(); // length of t
-
- if (n == 0) {
- return m;
- } else if (m == 0) {
- return n;
- }
-
- if (n > m) {
- // swap the input strings to consume less memory
- CharSequence tmp = s;
- s = t;
- t = tmp;
- n = m;
- m = t.length();
- }
-
- int p[] = new int[n + 1]; //'previous' cost array, horizontally
- int d[] = new int[n + 1]; // cost array, horizontally
- int _d[]; //placeholder to assist in swapping p and d
-
- // indexes into strings s and t
- int i; // iterates through s
- int j; // iterates through t
-
- char t_j; // jth character of t
-
- int cost; // cost
-
- for (i = 0; i <= n; i++) {
- p[i] = i;
- }
-
- for (j = 1; j <= m; j++) {
- t_j = t.charAt(j - 1);
- d[0] = j;
-
- for (i = 1; i <= n; i++) {
- cost = s.charAt(i - 1) == t_j ? 0 : 1;
- // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
- d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
- }
-
- // copy current distance counts to 'previous row' distance counts
- _d = p;
- p = d;
- d = _d;
- }
-
- // our last action in the above loop was to switch d and p, so p now
- // actually has the most recent cost counts
- return p[n];
- }
-
- /**
- * Find the Levenshtein distance between two Strings if it's less than or equal to a given - * threshold.
- * - *This is the number of changes needed to change one String into - * another, where each change is a single character modification (deletion, - * insertion or substitution).
- * - *This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield - * and Chas Emerick's implementation of the Levenshtein distance algorithm from - * http://www.merriampark.com/ld.htm
- * - *
- * StringUtils.getLevenshteinDistance(null, *, *) = IllegalArgumentException
- * StringUtils.getLevenshteinDistance(*, null, *) = IllegalArgumentException
- * StringUtils.getLevenshteinDistance(*, *, -1) = IllegalArgumentException
- * StringUtils.getLevenshteinDistance("","", 0) = 0
- * StringUtils.getLevenshteinDistance("aaapppp", "", 8) = 7
- * StringUtils.getLevenshteinDistance("aaapppp", "", 7) = 7
- * StringUtils.getLevenshteinDistance("aaapppp", "", 6)) = -1
- * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
- * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
- * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
- * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
- *
- *
- * @param s the first String, must not be null
- * @param t the second String, must not be null
- * @param threshold the target threshold, must not be negative
- * @return result distance, or {@code -1} if the distance would be greater than the threshold
- * @throws IllegalArgumentException if either String input {@code null} or negative threshold
- */
- public static int getLevenshteinDistance(CharSequence s, CharSequence t, int threshold) {
- if (s == null || t == null) {
- throw new IllegalArgumentException("Strings must not be null");
- }
- if (threshold < 0) {
- throw new IllegalArgumentException("Threshold must not be negative");
- }
-
- /*
- This implementation only computes the distance if it's less than or equal to the
- threshold value, returning -1 if it's greater. The advantage is performance: unbounded
- distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
- computing a diagonal stripe of width 2k + 1 of the cost table.
- It is also possible to use this to compute the unbounded Levenshtein distance by starting
- the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
- d is the distance.
-
- One subtlety comes from needing to ignore entries on the border of our stripe
- eg.
- p[] = |#|#|#|*
- d[] = *|#|#|#|
- We must ignore the entry to the left of the leftmost member
- We must ignore the entry above the rightmost member
-
- Another subtlety comes from our stripe running off the matrix if the strings aren't
- of the same size. Since string s is always swapped to be the shorter of the two,
- the stripe will always run off to the upper right instead of the lower left of the matrix.
-
- As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
- In this case we're going to walk a stripe of length 3. The matrix would look like so:
-
- 1 2 3 4 5
- 1 |#|#| | | |
- 2 |#|#|#| | |
- 3 | |#|#|#| |
- 4 | | |#|#|#|
- 5 | | | |#|#|
- 6 | | | | |#|
- 7 | | | | | |
-
- Note how the stripe leads off the table as there is no possible way to turn a string of length 5
- into one of length 7 in edit distance of 1.
-
- Additionally, this implementation decreases memory usage by using two
- single-dimensional arrays and swapping them back and forth instead of allocating
- an entire n by m matrix. This requires a few minor changes, such as immediately returning
- when it's detected that the stripe has run off the matrix and initially filling the arrays with
- large values so that entries we don't compute are ignored.
-
- See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
- */
-
- int n = s.length(); // length of s
- int m = t.length(); // length of t
-
- // if one string is empty, the edit distance is necessarily the length of the other
- if (n == 0) {
- return m <= threshold ? m : -1;
- } else if (m == 0) {
- return n <= threshold ? n : -1;
- }
-
- if (n > m) {
- // swap the two strings to consume less memory
- CharSequence tmp = s;
- s = t;
- t = tmp;
- n = m;
- m = t.length();
- }
-
- int p[] = new int[n + 1]; // 'previous' cost array, horizontally
- int d[] = new int[n + 1]; // cost array, horizontally
- int _d[]; // placeholder to assist in swapping p and d
-
- // fill in starting table values
- int boundary = Math.min(n, threshold) + 1;
- for (int i = 0; i < boundary; i++) {
- p[i] = i;
- }
- // these fills ensure that the value above the rightmost entry of our
- // stripe will be ignored in following loop iterations
- Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
- Arrays.fill(d, Integer.MAX_VALUE);
-
- // iterates through t
- for (int j = 1; j <= m; j++) {
- char t_j = t.charAt(j - 1); // jth character of t
- d[0] = j;
-
- // compute stripe indices, constrain to array size
- int min = Math.max(1, j - threshold);
- int max = Math.min(n, j + threshold);
-
- // the stripe may lead off of the table if s and t are of different sizes
- if (min > max) {
- return -1;
- }
-
- // ignore entry left of leftmost
- if (min > 1) {
- d[min - 1] = Integer.MAX_VALUE;
- }
-
- // iterates through [min, max] in s
- for (int i = min; i <= max; i++) {
- if (s.charAt(i - 1) == t_j) {
- // diagonally left and up
- d[i] = p[i - 1];
- } else {
- // 1 + minimum of cell to the left, to the top, diagonally left and up
- d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
- }
- }
-
- // copy current distance counts to 'previous row' distance counts
- _d = p;
- p = d;
- d = _d;
- }
-
- // if p[n] is greater than the threshold, there's no guarantee on it being the correct
- // distance
- if (p[n] <= threshold) {
- return p[n];
- } else {
- return -1;
- }
- }
-
- // startsWith
- //-----------------------------------------------------------------------
-
- /**
- * Check if a CharSequence starts with a specified prefix.
- * - *{@code null}s are handled without exceptions. Two {@code null} - * references are considered to be equal. The comparison is case sensitive.
- * - *
- * StringUtils.startsWith(null, null) = true
- * StringUtils.startsWith(null, "abc") = false
- * StringUtils.startsWith("abcdef", null) = false
- * StringUtils.startsWith("abcdef", "abc") = true
- * StringUtils.startsWith("ABCDEF", "abc") = false
- *
- *
- * @see java.lang.String#startsWith(String)
- * @param str the CharSequence to check, may be null
- * @param prefix the prefix to find, may be null
- * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or
- * both {@code null}
- * @since 2.4
- * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
- */
- public static boolean startsWith(CharSequence str, CharSequence prefix) {
- return startsWith(str, prefix, false);
- }
-
- /**
- * Case insensitive check if a CharSequence starts with a specified prefix.
- * - *{@code null}s are handled without exceptions. Two {@code null} - * references are considered to be equal. The comparison is case insensitive.
- * - *
- * StringUtils.startsWithIgnoreCase(null, null) = true
- * StringUtils.startsWithIgnoreCase(null, "abc") = false
- * StringUtils.startsWithIgnoreCase("abcdef", null) = false
- * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
- * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
- *
- *
- * @see java.lang.String#startsWith(String)
- * @param str the CharSequence to check, may be null
- * @param prefix the prefix to find, may be null
- * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or
- * both {@code null}
- * @since 2.4
- * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
- */
- public static boolean startsWithIgnoreCase(CharSequence str, CharSequence prefix) {
- return startsWith(str, prefix, true);
- }
-
- /**
- * Check if a CharSequence starts with a specified prefix (optionally case insensitive).
- * - * @see java.lang.String#startsWith(String) - * @param str the CharSequence to check, may be null - * @param prefix the prefix to find, may be null - * @param ignoreCase indicates whether the compare should ignore case - * (case insensitive) or not. - * @return {@code true} if the CharSequence starts with the prefix or - * both {@code null} - */ - private static boolean startsWith(CharSequence str, CharSequence prefix, boolean ignoreCase) { - if (str == null || prefix == null) { - return (str == null && prefix == null); - } - if (prefix.length() > str.length()) { - return false; - } - return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length()); - } - - /** - *Check if a CharSequence starts with any of an array of specified strings.
- * - *
- * StringUtils.startsWithAny(null, null) = false
- * StringUtils.startsWithAny(null, new String[] {"abc"}) = false
- * StringUtils.startsWithAny("abcxyz", null) = false
- * StringUtils.startsWithAny("abcxyz", new String[] {""}) = false
- * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
- * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
- *
- *
- * @param string the CharSequence to check, may be null
- * @param searchStrings the CharSequences to find, may be null or empty
- * @return {@code true} if the CharSequence starts with any of the the prefixes, case insensitive, or
- * both {@code null}
- * @since 2.5
- * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
- */
- public static boolean startsWithAny(CharSequence string, CharSequence... searchStrings) {
- if (isEmpty(string) || ArrayUtils.isEmpty(searchStrings)) {
- return false;
- }
- for (CharSequence searchString : searchStrings) {
- if (StringUtils.startsWith(string, searchString)) {
- return true;
- }
- }
- return false;
- }
-
- // endsWith
- //-----------------------------------------------------------------------
-
- /**
- * Check if a CharSequence ends with a specified suffix.
- * - *{@code null}s are handled without exceptions. Two {@code null} - * references are considered to be equal. The comparison is case sensitive.
- * - *
- * StringUtils.endsWith(null, null) = true
- * StringUtils.endsWith(null, "def") = false
- * StringUtils.endsWith("abcdef", null) = false
- * StringUtils.endsWith("abcdef", "def") = true
- * StringUtils.endsWith("ABCDEF", "def") = false
- * StringUtils.endsWith("ABCDEF", "cde") = false
- *
- *
- * @see java.lang.String#endsWith(String)
- * @param str the CharSequence to check, may be null
- * @param suffix the suffix to find, may be null
- * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or
- * both {@code null}
- * @since 2.4
- * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
- */
- public static boolean endsWith(CharSequence str, CharSequence suffix) {
- return endsWith(str, suffix, false);
- }
-
- /**
- * Case insensitive check if a CharSequence ends with a specified suffix.
- * - *{@code null}s are handled without exceptions. Two {@code null} - * references are considered to be equal. The comparison is case insensitive.
- * - *
- * StringUtils.endsWithIgnoreCase(null, null) = true
- * StringUtils.endsWithIgnoreCase(null, "def") = false
- * StringUtils.endsWithIgnoreCase("abcdef", null) = false
- * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
- * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
- * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
- *
- *
- * @see java.lang.String#endsWith(String)
- * @param str the CharSequence to check, may be null
- * @param suffix the suffix to find, may be null
- * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or
- * both {@code null}
- * @since 2.4
- * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
- */
- public static boolean endsWithIgnoreCase(CharSequence str, CharSequence suffix) {
- return endsWith(str, suffix, true);
- }
-
- /**
- * Check if a CharSequence ends with a specified suffix (optionally case insensitive).
- * - * @see java.lang.String#endsWith(String) - * @param str the CharSequence to check, may be null - * @param suffix the suffix to find, may be null - * @param ignoreCase indicates whether the compare should ignore case - * (case insensitive) or not. - * @return {@code true} if the CharSequence starts with the prefix or - * both {@code null} - */ - private static boolean endsWith(CharSequence str, CharSequence suffix, boolean ignoreCase) { - if (str == null || suffix == null) { - return str == null && suffix == null; - } - if (suffix.length() > str.length()) { - return false; - } - int strOffset = str.length() - suffix.length(); - return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length()); - } - - /** - *- * Similar to http://www.w3.org/TR/xpath/#function-normalize - * -space - *
- *
- * The function returns the argument string with whitespace normalized by using
- * {@link #trim(String)} to remove leading and trailing whitespace
- * and then replacing sequences of whitespace characters by a single space.
- *
- * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r] - *
- * For reference: - *
- * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
- * normalize. Additionally {@link #trim(String)} removes control characters (char <= 32) from both
- * ends of this String.
- *
Check if a CharSequence ends with any of an array of specified strings.
- * - *
- * StringUtils.endsWithAny(null, null) = false
- * StringUtils.endsWithAny(null, new String[] {"abc"}) = false
- * StringUtils.endsWithAny("abcxyz", null) = false
- * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
- * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
- * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
- *
- *
- * @param string the CharSequence to check, may be null
- * @param searchStrings the CharSequences to find, may be null or empty
- * @return {@code true} if the CharSequence ends with any of the the prefixes, case insensitive, or
- * both {@code null}
- * @since 3.0
- */
- public static boolean endsWithAny(CharSequence string, CharSequence... searchStrings) {
- if (isEmpty(string) || ArrayUtils.isEmpty(searchStrings)) {
- return false;
- }
- for (CharSequence searchString : searchStrings) {
- if (StringUtils.endsWith(string, searchString)) {
- return true;
- }
- }
- return false;
- }
-
+/*
+ * 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.commons.lang3;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.regex.Pattern;
+
+/**
+ * Operations on {@link java.lang.String} that are + * {@code null} safe.
+ * + *The {@code StringUtils} class defines certain words related to + * String handling.
+ * + *{@code StringUtils} handles {@code null} input Strings quietly. + * That is to say that a {@code null} input will return {@code null}. + * Where a {@code boolean} or {@code int} is being returned + * details vary by method.
+ * + *A side effect of the {@code null} handling is that a + * {@code NullPointerException} should be considered a bug in + * {@code StringUtils}.
+ * + *Methods in this class give sample code to explain their operation. + * The symbol {@code *} is used to indicate any input including {@code null}.
+ * + *#ThreadSafe#
+ * @see java.lang.String + * @since 1.0 + * @version $Id$ + */ +//@Immutable +public class StringUtils { + // Performance testing notes (JDK 1.4, Jul03, scolebourne) + // Whitespace: + // Character.isWhitespace() is faster than WHITESPACE.indexOf() + // where WHITESPACE is a string of all whitespace characters + // + // Character access: + // String.charAt(n) versus toCharArray(), then array[n] + // String.charAt(n) is about 15% worse for a 10K string + // They are about equal for a length 50 string + // String.charAt(n) is about 4 times better for a length 3 string + // String.charAt(n) is best bet overall + // + // Append: + // String.concat about twice as fast as StringBuffer.append + // (not sure who tested this) + + /** + * The empty String {@code ""}. + * @since 2.0 + */ + public static final String EMPTY = ""; + + /** + * Represents a failed index search. + * @since 2.1 + */ + public static final int INDEX_NOT_FOUND = -1; + + /** + *The maximum size to which the padding constant(s) can expand.
+ */ + private static final int PAD_LIMIT = 8192; + + /** + * A regex pattern for recognizing blocks of whitespace characters. + */ + private static final Pattern WHITESPACE_BLOCK = Pattern.compile("\\s+"); + + /** + *{@code StringUtils} instances should NOT be constructed in + * standard programming. Instead, the class should be used as + * {@code StringUtils.trim(" foo ");}.
+ * + *This constructor is public to permit tools that require a JavaBean + * instance to operate.
+ */ + public StringUtils() { + super(); + } + + // Empty checks + //----------------------------------------------------------------------- + /** + *Checks if a CharSequence is empty ("") or null.
+ * + *
+ * StringUtils.isEmpty(null) = true
+ * StringUtils.isEmpty("") = true
+ * StringUtils.isEmpty(" ") = false
+ * StringUtils.isEmpty("bob") = false
+ * StringUtils.isEmpty(" bob ") = false
+ *
+ *
+ * NOTE: This method changed in Lang version 2.0. + * It no longer trims the CharSequence. + * That functionality is available in isBlank().
+ * + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is empty or null + * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) + */ + public static boolean isEmpty(CharSequence cs) { + return cs == null || cs.length() == 0; + } + + /** + *Checks if a CharSequence is not empty ("") and not null.
+ * + *
+ * StringUtils.isNotEmpty(null) = false
+ * StringUtils.isNotEmpty("") = false
+ * StringUtils.isNotEmpty(" ") = true
+ * StringUtils.isNotEmpty("bob") = true
+ * StringUtils.isNotEmpty(" bob ") = true
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if the CharSequence is not empty and not null
+ * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
+ */
+ public static boolean isNotEmpty(CharSequence cs) {
+ return !StringUtils.isEmpty(cs);
+ }
+
+ /**
+ * Checks if a CharSequence is whitespace, empty ("") or null.
+ * + *
+ * StringUtils.isBlank(null) = true
+ * StringUtils.isBlank("") = true
+ * StringUtils.isBlank(" ") = true
+ * StringUtils.isBlank("bob") = false
+ * StringUtils.isBlank(" bob ") = false
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if the CharSequence is null, empty or whitespace
+ * @since 2.0
+ * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
+ */
+ public static boolean isBlank(CharSequence cs) {
+ int strLen;
+ if (cs == null || (strLen = cs.length()) == 0) {
+ return true;
+ }
+ for (int i = 0; i < strLen; i++) {
+ if ((Character.isWhitespace(cs.charAt(i)) == false)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks if a CharSequence is not empty (""), not null and not whitespace only.
+ * + *
+ * StringUtils.isNotBlank(null) = false
+ * StringUtils.isNotBlank("") = false
+ * StringUtils.isNotBlank(" ") = false
+ * StringUtils.isNotBlank("bob") = true
+ * StringUtils.isNotBlank(" bob ") = true
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if the CharSequence is
+ * not empty and not null and not whitespace
+ * @since 2.0
+ * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
+ */
+ public static boolean isNotBlank(CharSequence cs) {
+ return !StringUtils.isBlank(cs);
+ }
+
+ // Trim
+ //-----------------------------------------------------------------------
+ /**
+ * Removes control characters (char <= 32) from both + * ends of this String, handling {@code null} by returning + * {@code null}.
+ * + *The String is trimmed using {@link String#trim()}. + * Trim removes start and end characters <= 32. + * To strip whitespace use {@link #strip(String)}.
+ * + *To trim your choice of characters, use the + * {@link #strip(String, String)} methods.
+ * + *
+ * StringUtils.trim(null) = null
+ * StringUtils.trim("") = ""
+ * StringUtils.trim(" ") = ""
+ * StringUtils.trim("abc") = "abc"
+ * StringUtils.trim(" abc ") = "abc"
+ *
+ *
+ * @param str the String to be trimmed, may be null
+ * @return the trimmed string, {@code null} if null String input
+ */
+ public static String trim(String str) {
+ return str == null ? null : str.trim();
+ }
+
+ /**
+ * Removes control characters (char <= 32) from both + * ends of this String returning {@code null} if the String is + * empty ("") after the trim or if it is {@code null}. + * + *
The String is trimmed using {@link String#trim()}. + * Trim removes start and end characters <= 32. + * To strip whitespace use {@link #stripToNull(String)}.
+ * + *
+ * StringUtils.trimToNull(null) = null
+ * StringUtils.trimToNull("") = null
+ * StringUtils.trimToNull(" ") = null
+ * StringUtils.trimToNull("abc") = "abc"
+ * StringUtils.trimToNull(" abc ") = "abc"
+ *
+ *
+ * @param str the String to be trimmed, may be null
+ * @return the trimmed String,
+ * {@code null} if only chars <= 32, empty or null String input
+ * @since 2.0
+ */
+ public static String trimToNull(String str) {
+ String ts = trim(str);
+ return isEmpty(ts) ? null : ts;
+ }
+
+ /**
+ * Removes control characters (char <= 32) from both + * ends of this String returning an empty String ("") if the String + * is empty ("") after the trim or if it is {@code null}. + * + *
The String is trimmed using {@link String#trim()}. + * Trim removes start and end characters <= 32. + * To strip whitespace use {@link #stripToEmpty(String)}.
+ * + *
+ * StringUtils.trimToEmpty(null) = ""
+ * StringUtils.trimToEmpty("") = ""
+ * StringUtils.trimToEmpty(" ") = ""
+ * StringUtils.trimToEmpty("abc") = "abc"
+ * StringUtils.trimToEmpty(" abc ") = "abc"
+ *
+ *
+ * @param str the String to be trimmed, may be null
+ * @return the trimmed String, or an empty String if {@code null} input
+ * @since 2.0
+ */
+ public static String trimToEmpty(String str) {
+ return str == null ? EMPTY : str.trim();
+ }
+
+ // Stripping
+ //-----------------------------------------------------------------------
+ /**
+ * Strips whitespace from the start and end of a String.
+ * + *This is similar to {@link #trim(String)} but removes whitespace. + * Whitespace is defined by {@link Character#isWhitespace(char)}.
+ * + *A {@code null} input String returns {@code null}.
+ * + *
+ * StringUtils.strip(null) = null
+ * StringUtils.strip("") = ""
+ * StringUtils.strip(" ") = ""
+ * StringUtils.strip("abc") = "abc"
+ * StringUtils.strip(" abc") = "abc"
+ * StringUtils.strip("abc ") = "abc"
+ * StringUtils.strip(" abc ") = "abc"
+ * StringUtils.strip(" ab c ") = "ab c"
+ *
+ *
+ * @param str the String to remove whitespace from, may be null
+ * @return the stripped String, {@code null} if null String input
+ */
+ public static String strip(String str) {
+ return strip(str, null);
+ }
+
+ /**
+ * Strips whitespace from the start and end of a String returning + * {@code null} if the String is empty ("") after the strip.
+ * + *This is similar to {@link #trimToNull(String)} but removes whitespace. + * Whitespace is defined by {@link Character#isWhitespace(char)}.
+ * + *
+ * StringUtils.stripToNull(null) = null
+ * StringUtils.stripToNull("") = null
+ * StringUtils.stripToNull(" ") = null
+ * StringUtils.stripToNull("abc") = "abc"
+ * StringUtils.stripToNull(" abc") = "abc"
+ * StringUtils.stripToNull("abc ") = "abc"
+ * StringUtils.stripToNull(" abc ") = "abc"
+ * StringUtils.stripToNull(" ab c ") = "ab c"
+ *
+ *
+ * @param str the String to be stripped, may be null
+ * @return the stripped String,
+ * {@code null} if whitespace, empty or null String input
+ * @since 2.0
+ */
+ public static String stripToNull(String str) {
+ if (str == null) {
+ return null;
+ }
+ str = strip(str, null);
+ return str.length() == 0 ? null : str;
+ }
+
+ /**
+ * Strips whitespace from the start and end of a String returning + * an empty String if {@code null} input.
+ * + *This is similar to {@link #trimToEmpty(String)} but removes whitespace. + * Whitespace is defined by {@link Character#isWhitespace(char)}.
+ * + *
+ * StringUtils.stripToEmpty(null) = ""
+ * StringUtils.stripToEmpty("") = ""
+ * StringUtils.stripToEmpty(" ") = ""
+ * StringUtils.stripToEmpty("abc") = "abc"
+ * StringUtils.stripToEmpty(" abc") = "abc"
+ * StringUtils.stripToEmpty("abc ") = "abc"
+ * StringUtils.stripToEmpty(" abc ") = "abc"
+ * StringUtils.stripToEmpty(" ab c ") = "ab c"
+ *
+ *
+ * @param str the String to be stripped, may be null
+ * @return the trimmed String, or an empty String if {@code null} input
+ * @since 2.0
+ */
+ public static String stripToEmpty(String str) {
+ return str == null ? EMPTY : strip(str, null);
+ }
+
+ /**
+ * Strips any of a set of characters from the start and end of a String. + * This is similar to {@link String#trim()} but allows the characters + * to be stripped to be controlled.
+ * + *A {@code null} input String returns {@code null}. + * An empty string ("") input returns the empty string.
+ * + *If the stripChars String is {@code null}, whitespace is + * stripped as defined by {@link Character#isWhitespace(char)}. + * Alternatively use {@link #strip(String)}.
+ * + *
+ * StringUtils.strip(null, *) = null
+ * StringUtils.strip("", *) = ""
+ * StringUtils.strip("abc", null) = "abc"
+ * StringUtils.strip(" abc", null) = "abc"
+ * StringUtils.strip("abc ", null) = "abc"
+ * StringUtils.strip(" abc ", null) = "abc"
+ * StringUtils.strip(" abcyx", "xyz") = " abc"
+ *
+ *
+ * @param str the String to remove characters from, may be null
+ * @param stripChars the characters to remove, null treated as whitespace
+ * @return the stripped String, {@code null} if null String input
+ */
+ public static String strip(String str, String stripChars) {
+ if (isEmpty(str)) {
+ return str;
+ }
+ str = stripStart(str, stripChars);
+ return stripEnd(str, stripChars);
+ }
+
+ /**
+ * Strips any of a set of characters from the start of a String.
+ * + *A {@code null} input String returns {@code null}. + * An empty string ("") input returns the empty string.
+ * + *If the stripChars String is {@code null}, whitespace is + * stripped as defined by {@link Character#isWhitespace(char)}.
+ * + *
+ * StringUtils.stripStart(null, *) = null
+ * StringUtils.stripStart("", *) = ""
+ * StringUtils.stripStart("abc", "") = "abc"
+ * StringUtils.stripStart("abc", null) = "abc"
+ * StringUtils.stripStart(" abc", null) = "abc"
+ * StringUtils.stripStart("abc ", null) = "abc "
+ * StringUtils.stripStart(" abc ", null) = "abc "
+ * StringUtils.stripStart("yxabc ", "xyz") = "abc "
+ *
+ *
+ * @param str the String to remove characters from, may be null
+ * @param stripChars the characters to remove, null treated as whitespace
+ * @return the stripped String, {@code null} if null String input
+ */
+ public static String stripStart(String str, String stripChars) {
+ int strLen;
+ if (str == null || (strLen = str.length()) == 0) {
+ return str;
+ }
+ int start = 0;
+ if (stripChars == null) {
+ while ((start != strLen) && Character.isWhitespace(str.charAt(start))) {
+ start++;
+ }
+ } else if (stripChars.length() == 0) {
+ return str;
+ } else {
+ while ((start != strLen) && (stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND)) {
+ start++;
+ }
+ }
+ return str.substring(start);
+ }
+
+ /**
+ * Strips any of a set of characters from the end of a String.
+ * + *A {@code null} input String returns {@code null}. + * An empty string ("") input returns the empty string.
+ * + *If the stripChars String is {@code null}, whitespace is + * stripped as defined by {@link Character#isWhitespace(char)}.
+ * + *
+ * StringUtils.stripEnd(null, *) = null
+ * StringUtils.stripEnd("", *) = ""
+ * StringUtils.stripEnd("abc", "") = "abc"
+ * StringUtils.stripEnd("abc", null) = "abc"
+ * StringUtils.stripEnd(" abc", null) = " abc"
+ * StringUtils.stripEnd("abc ", null) = "abc"
+ * StringUtils.stripEnd(" abc ", null) = " abc"
+ * StringUtils.stripEnd(" abcyx", "xyz") = " abc"
+ * StringUtils.stripEnd("120.00", ".0") = "12"
+ *
+ *
+ * @param str the String to remove characters from, may be null
+ * @param stripChars the set of characters to remove, null treated as whitespace
+ * @return the stripped String, {@code null} if null String input
+ */
+ public static String stripEnd(String str, String stripChars) {
+ int end;
+ if (str == null || (end = str.length()) == 0) {
+ return str;
+ }
+
+ if (stripChars == null) {
+ while ((end != 0) && Character.isWhitespace(str.charAt(end - 1))) {
+ end--;
+ }
+ } else if (stripChars.length() == 0) {
+ return str;
+ } else {
+ while ((end != 0) && (stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND)) {
+ end--;
+ }
+ }
+ return str.substring(0, end);
+ }
+
+ // StripAll
+ //-----------------------------------------------------------------------
+ /**
+ * Strips whitespace from the start and end of every String in an array. + * Whitespace is defined by {@link Character#isWhitespace(char)}.
+ * + *A new array is returned each time, except for length zero. + * A {@code null} array will return {@code null}. + * An empty array will return itself. + * A {@code null} array entry will be ignored.
+ * + *+ * StringUtils.stripAll(null) = null + * StringUtils.stripAll([]) = [] + * StringUtils.stripAll(["abc", " abc"]) = ["abc", "abc"] + * StringUtils.stripAll(["abc ", null]) = ["abc", null] + *+ * + * @param strs the array to remove whitespace from, may be null + * @return the stripped Strings, {@code null} if null array input + */ + public static String[] stripAll(String... strs) { + return stripAll(strs, null); + } + + /** + *
Strips any of a set of characters from the start and end of every + * String in an array.
+ * Whitespace is defined by {@link Character#isWhitespace(char)}. + * + *A new array is returned each time, except for length zero. + * A {@code null} array will return {@code null}. + * An empty array will return itself. + * A {@code null} array entry will be ignored. + * A {@code null} stripChars will strip whitespace as defined by + * {@link Character#isWhitespace(char)}.
+ * + *+ * StringUtils.stripAll(null, *) = null + * StringUtils.stripAll([], *) = [] + * StringUtils.stripAll(["abc", " abc"], null) = ["abc", "abc"] + * StringUtils.stripAll(["abc ", null], null) = ["abc", null] + * StringUtils.stripAll(["abc ", null], "yz") = ["abc ", null] + * StringUtils.stripAll(["yabcz", null], "yz") = ["abc", null] + *+ * + * @param strs the array to remove characters from, may be null + * @param stripChars the characters to remove, null treated as whitespace + * @return the stripped Strings, {@code null} if null array input + */ + public static String[] stripAll(String[] strs, String stripChars) { + int strsLen; + if (strs == null || (strsLen = strs.length) == 0) { + return strs; + } + String[] newArr = new String[strsLen]; + for (int i = 0; i < strsLen; i++) { + newArr[i] = strip(strs[i], stripChars); + } + return newArr; + } + + /** + *
Removes diacritics (~= accents) from a string. The case will not be altered.
+ *For instance, 'à' will be replaced by 'a'.
+ *Note that ligatures will be left as is.
+ * + *This method will use the first available implementation of: + * Java 6's {@link java.text.Normalizer}, Java 1.3–1.5's {@code sun.text.Normalizer}
+ * + *
+ * StringUtils.stripAccents(null) = null
+ * StringUtils.stripAccents("") = ""
+ * StringUtils.stripAccents("control") = "control"
+ * StringUtils.stripAccents("éclair") = "eclair"
+ *
+ *
+ * @param input String to be stripped
+ * @return input text with diacritics removed
+ *
+ * @since 3.0
+ */
+ // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix: https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
+ public static String stripAccents(String input) {
+ if(input == null) {
+ return null;
+ }
+ try {
+ String result = null;
+ if (java6Available) {
+ result = removeAccentsJava6(input);
+ } else if (sunAvailable) {
+ result = removeAccentsSUN(input);
+ } else {
+ throw new UnsupportedOperationException(
+ "The stripAccents(CharSequence) method requires at least Java 1.6 or a Sun JVM");
+ }
+ // Note that none of the above methods correctly remove ligatures...
+ return result;
+ } catch(IllegalArgumentException iae) {
+ throw new RuntimeException("IllegalArgumentException occurred", iae);
+ } catch(IllegalAccessException iae) {
+ throw new RuntimeException("IllegalAccessException occurred", iae);
+ } catch(InvocationTargetException ite) {
+ throw new RuntimeException("InvocationTargetException occurred", ite);
+ } catch(SecurityException se) {
+ throw new RuntimeException("SecurityException occurred", se);
+ }
+ }
+
+ /**
+ * Use {@code java.text.Normalizer#normalize(CharSequence, Normalizer.Form)}
+ * (but be careful, this class exists in Java 1.3, with an entirely different meaning!)
+ *
+ * @param text the text to be processed
+ * @return the processed string
+ * @throws IllegalAccessException may be thrown by a reflection call
+ * @throws InvocationTargetException if a reflection call throws an exception
+ * @throws IllegalStateException if the {@code Normalizer} class is not available
+ */
+ private static String removeAccentsJava6(CharSequence text)
+ throws IllegalAccessException, InvocationTargetException {
+ /*
+ String decomposed = java.text.Normalizer.normalize(CharSequence, Normalizer.Form.NFD);
+ return java6Pattern.matcher(decomposed).replaceAll("");//$NON-NLS-1$
+ */
+ if (!java6Available || java6NormalizerFormNFD == null) {
+ throw new IllegalStateException("java.text.Normalizer is not available");
+ }
+ String result;
+ result = (String) java6NormalizeMethod.invoke(null, new Object[] {text, java6NormalizerFormNFD});
+ result = java6Pattern.matcher(result).replaceAll("");//$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * Use {@code sun.text.Normalizer#decompose(String, boolean, int)}
+ *
+ * @param text the text to be processed
+ * @return the processed string
+ * @throws IllegalAccessException may be thrown by a reflection call
+ * @throws InvocationTargetException if a reflection call throws an exception
+ * @throws IllegalStateException if the {@code Normalizer} class is not available
+ */
+ private static String removeAccentsSUN(CharSequence text)
+ throws IllegalAccessException, InvocationTargetException {
+ /*
+ String decomposed = sun.text.Normalizer.decompose(text, false, 0);
+ return sunPattern.matcher(decomposed).replaceAll("");//$NON-NLS-1$
+ */
+ if (! sunAvailable) {
+ throw new IllegalStateException("sun.text.Normalizer is not available");
+ }
+ String result;
+ result = (String) sunDecomposeMethod.invoke(null, new Object[] {text, Boolean.FALSE, Integer.valueOf(0)});
+ result = sunPattern.matcher(result).replaceAll("");//$NON-NLS-1$
+ return result;
+ }
+
+ // SUN internal, Java 1.3 -> Java 5
+ private static boolean sunAvailable = false;
+ private static Method sunDecomposeMethod = null;
+ private static final Pattern sunPattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");//$NON-NLS-1$
+ // Java 6+
+ private static boolean java6Available = false;
+ private static Method java6NormalizeMethod = null;
+ private static Object java6NormalizerFormNFD = null;
+ private static final Pattern java6Pattern = sunPattern;
+
+ static {
+ try {
+ // java.text.Normalizer.normalize(CharSequence, Normalizer.Form.NFD);
+ // Be careful not to get Java 1.3 java.text.Normalizer!
+ Class> normalizerFormClass = Thread.currentThread().getContextClassLoader()
+ .loadClass("java.text.Normalizer$Form");//$NON-NLS-1$
+ java6NormalizerFormNFD = normalizerFormClass.getField("NFD").get(null);//$NON-NLS-1$
+ Class> normalizerClass = Thread.currentThread().getContextClassLoader()
+ .loadClass("java.text.Normalizer");//$NON-NLS-1$
+ java6NormalizeMethod = normalizerClass.getMethod("normalize",
+ new Class[] {CharSequence.class, normalizerFormClass});//$NON-NLS-1$
+ java6Available = true;
+ } catch (ClassNotFoundException e) {
+ java6Available = false;
+ } catch (NoSuchFieldException e) {
+ java6Available = false;
+ } catch (IllegalAccessException e) {
+ java6Available = false;
+ } catch (NoSuchMethodException e) {
+ java6Available = false;
+ }
+
+ try {
+ // sun.text.Normalizer.decompose(text, false, 0);
+ Class> normalizerClass = Thread.currentThread().getContextClassLoader()
+ .loadClass("sun.text.Normalizer");//$NON-NLS-1$
+ sunDecomposeMethod = normalizerClass.getMethod("decompose",
+ new Class[] {String.class, Boolean.TYPE, Integer.TYPE});//$NON-NLS-1$
+ sunAvailable = true;
+ } catch (ClassNotFoundException e) {
+ sunAvailable = false;
+ } catch (NoSuchMethodException e) {
+ sunAvailable = false;
+ } catch (java.security.AccessControlException e) {
+ // LANG-744 - thrown in Google App Engine
+ sunAvailable = false;
+ }
+ }
+
+ // Equals
+ //-----------------------------------------------------------------------
+ /**
+ * Compares two CharSequences, returning {@code true} if they are equal.
+ * + *{@code null}s are handled without exceptions. Two {@code null} + * references are considered to be equal. The comparison is case sensitive.
+ * + *
+ * StringUtils.equals(null, null) = true
+ * StringUtils.equals(null, "abc") = false
+ * StringUtils.equals("abc", null) = false
+ * StringUtils.equals("abc", "abc") = true
+ * StringUtils.equals("abc", "ABC") = false
+ *
+ *
+ * @see java.lang.String#equals(Object)
+ * @param cs1 the first CharSequence, may be null
+ * @param cs2 the second CharSequence, may be null
+ * @return {@code true} if the CharSequences are equal, case sensitive, or
+ * both {@code null}
+ * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
+ */
+ public static boolean equals(CharSequence cs1, CharSequence cs2) {
+ return cs1 == null ? cs2 == null : cs1.equals(cs2);
+ }
+
+ /**
+ * Compares two CharSequences, returning {@code true} if they are equal ignoring + * the case.
+ * + *{@code null}s are handled without exceptions. Two {@code null} + * references are considered equal. Comparison is case insensitive.
+ * + *
+ * StringUtils.equalsIgnoreCase(null, null) = true
+ * StringUtils.equalsIgnoreCase(null, "abc") = false
+ * StringUtils.equalsIgnoreCase("abc", null) = false
+ * StringUtils.equalsIgnoreCase("abc", "abc") = true
+ * StringUtils.equalsIgnoreCase("abc", "ABC") = true
+ *
+ *
+ * @param str1 the first CharSequence, may be null
+ * @param str2 the second CharSequence, may be null
+ * @return {@code true} if the CharSequence are equal, case insensitive, or
+ * both {@code null}
+ * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
+ */
+ public static boolean equalsIgnoreCase(CharSequence str1, CharSequence str2) {
+ if (str1 == null || str2 == null) {
+ return str1 == str2;
+ } else {
+ return CharSequenceUtils.regionMatches(str1, true, 0, str2, 0, Math.max(str1.length(), str2.length()));
+ }
+ }
+
+ // IndexOf
+ //-----------------------------------------------------------------------
+ /**
+ * Finds the first index within a CharSequence, handling {@code null}. + * This method uses {@link String#indexOf(int, int)} if possible.
+ * + *A {@code null} or empty ("") CharSequence will return {@code INDEX_NOT_FOUND (-1)}.
+ * + *
+ * StringUtils.indexOf(null, *) = -1
+ * StringUtils.indexOf("", *) = -1
+ * StringUtils.indexOf("aabaabaa", 'a') = 0
+ * StringUtils.indexOf("aabaabaa", 'b') = 2
+ *
+ *
+ * @param seq the CharSequence to check, may be null
+ * @param searchChar the character to find
+ * @return the first index of the search character,
+ * -1 if no match or {@code null} string input
+ * @since 2.0
+ * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
+ */
+ public static int indexOf(CharSequence seq, int searchChar) {
+ if (isEmpty(seq)) {
+ return INDEX_NOT_FOUND;
+ }
+ return CharSequenceUtils.indexOf(seq, searchChar, 0);
+ }
+
+ /**
+ * Finds the first index within a CharSequence from a start position, + * handling {@code null}. + * This method uses {@link String#indexOf(int, int)} if possible.
+ * + *A {@code null} or empty ("") CharSequence will return {@code (INDEX_NOT_FOUND) -1}. + * A negative start position is treated as zero. + * A start position greater than the string length returns {@code -1}.
+ * + *
+ * StringUtils.indexOf(null, *, *) = -1
+ * StringUtils.indexOf("", *, *) = -1
+ * StringUtils.indexOf("aabaabaa", 'b', 0) = 2
+ * StringUtils.indexOf("aabaabaa", 'b', 3) = 5
+ * StringUtils.indexOf("aabaabaa", 'b', 9) = -1
+ * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
+ *
+ *
+ * @param seq the CharSequence to check, may be null
+ * @param searchChar the character to find
+ * @param startPos the start position, negative treated as zero
+ * @return the first index of the search character,
+ * -1 if no match or {@code null} string input
+ * @since 2.0
+ * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
+ */
+ public static int indexOf(CharSequence seq, int searchChar, int startPos) {
+ if (isEmpty(seq)) {
+ return INDEX_NOT_FOUND;
+ }
+ return CharSequenceUtils.indexOf(seq, searchChar, startPos);
+ }
+
+ /**
+ * Finds the first index within a CharSequence, handling {@code null}. + * This method uses {@link String#indexOf(String, int)} if possible.
+ * + *A {@code null} CharSequence will return {@code -1}.
+ * + *
+ * StringUtils.indexOf(null, *) = -1
+ * StringUtils.indexOf(*, null) = -1
+ * StringUtils.indexOf("", "") = 0
+ * StringUtils.indexOf("", *) = -1 (except when * = "")
+ * StringUtils.indexOf("aabaabaa", "a") = 0
+ * StringUtils.indexOf("aabaabaa", "b") = 2
+ * StringUtils.indexOf("aabaabaa", "ab") = 1
+ * StringUtils.indexOf("aabaabaa", "") = 0
+ *
+ *
+ * @param seq the CharSequence to check, may be null
+ * @param searchSeq the CharSequence to find, may be null
+ * @return the first index of the search CharSequence,
+ * -1 if no match or {@code null} string input
+ * @since 2.0
+ * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
+ */
+ public static int indexOf(CharSequence seq, CharSequence searchSeq) {
+ if (seq == null || searchSeq == null) {
+ return INDEX_NOT_FOUND;
+ }
+ return CharSequenceUtils.indexOf(seq, searchSeq, 0);
+ }
+
+ /**
+ * Finds the first index within a CharSequence, handling {@code null}. + * This method uses {@link String#indexOf(String, int)} if possible.
+ * + *A {@code null} CharSequence will return {@code -1}. + * A negative start position is treated as zero. + * An empty ("") search CharSequence always matches. + * A start position greater than the string length only matches + * an empty search CharSequence.
+ * + *
+ * StringUtils.indexOf(null, *, *) = -1
+ * StringUtils.indexOf(*, null, *) = -1
+ * StringUtils.indexOf("", "", 0) = 0
+ * StringUtils.indexOf("", *, 0) = -1 (except when * = "")
+ * StringUtils.indexOf("aabaabaa", "a", 0) = 0
+ * StringUtils.indexOf("aabaabaa", "b", 0) = 2
+ * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
+ * StringUtils.indexOf("aabaabaa", "b", 3) = 5
+ * StringUtils.indexOf("aabaabaa", "b", 9) = -1
+ * StringUtils.indexOf("aabaabaa", "b", -1) = 2
+ * StringUtils.indexOf("aabaabaa", "", 2) = 2
+ * StringUtils.indexOf("abc", "", 9) = 3
+ *
+ *
+ * @param seq the CharSequence to check, may be null
+ * @param searchSeq the CharSequence to find, may be null
+ * @param startPos the start position, negative treated as zero
+ * @return the first index of the search CharSequence,
+ * -1 if no match or {@code null} string input
+ * @since 2.0
+ * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
+ */
+ public static int indexOf(CharSequence seq, CharSequence searchSeq, int startPos) {
+ if (seq == null || searchSeq == null) {
+ return INDEX_NOT_FOUND;
+ }
+ return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
+ }
+
+ /**
+ * Finds the n-th index within a CharSequence, handling {@code null}. + * This method uses {@link String#indexOf(String)} if possible.
+ * + *A {@code null} CharSequence will return {@code -1}.
+ * + *
+ * StringUtils.ordinalIndexOf(null, *, *) = -1
+ * StringUtils.ordinalIndexOf(*, null, *) = -1
+ * StringUtils.ordinalIndexOf("", "", *) = 0
+ * StringUtils.ordinalIndexOf("aabaabaa", "a", 1) = 0
+ * StringUtils.ordinalIndexOf("aabaabaa", "a", 2) = 1
+ * StringUtils.ordinalIndexOf("aabaabaa", "b", 1) = 2
+ * StringUtils.ordinalIndexOf("aabaabaa", "b", 2) = 5
+ * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
+ * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
+ * StringUtils.ordinalIndexOf("aabaabaa", "", 1) = 0
+ * StringUtils.ordinalIndexOf("aabaabaa", "", 2) = 0
+ *
+ *
+ * Note that 'head(CharSequence str, int n)' may be implemented as:
+ * + *+ * str.substring(0, lastOrdinalIndexOf(str, "\n", n)) + *+ * + * @param str the CharSequence to check, may be null + * @param searchStr the CharSequence to find, may be null + * @param ordinal the n-th {@code searchStr} to find + * @return the n-th index of the search CharSequence, + * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input + * @since 2.1 + * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int) + */ + public static int ordinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal) { + return ordinalIndexOf(str, searchStr, ordinal, false); + } + + /** + *
Finds the n-th index within a String, handling {@code null}. + * This method uses {@link String#indexOf(String)} if possible.
+ * + *A {@code null} CharSequence will return {@code -1}.
+ * + * @param str the CharSequence to check, may be null + * @param searchStr the CharSequence to find, may be null + * @param ordinal the n-th {@code searchStr} to find + * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf() + * @return the n-th index of the search CharSequence, + * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input + */ + // Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int) + private static int ordinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal, boolean lastIndex) { + if (str == null || searchStr == null || ordinal <= 0) { + return INDEX_NOT_FOUND; + } + if (searchStr.length() == 0) { + return lastIndex ? str.length() : 0; + } + int found = 0; + int index = lastIndex ? str.length() : INDEX_NOT_FOUND; + do { + if (lastIndex) { + index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); + } else { + index = CharSequenceUtils.indexOf(str, searchStr, index + 1); + } + if (index < 0) { + return index; + } + found++; + } while (found < ordinal); + return index; + } + + /** + *Case in-sensitive find of the first index within a CharSequence.
+ * + *A {@code null} CharSequence will return {@code -1}. + * A negative start position is treated as zero. + * An empty ("") search CharSequence always matches. + * A start position greater than the string length only matches + * an empty search CharSequence.
+ * + *
+ * StringUtils.indexOfIgnoreCase(null, *) = -1
+ * StringUtils.indexOfIgnoreCase(*, null) = -1
+ * StringUtils.indexOfIgnoreCase("", "") = 0
+ * StringUtils.indexOfIgnoreCase("aabaabaa", "a") = 0
+ * StringUtils.indexOfIgnoreCase("aabaabaa", "b") = 2
+ * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
+ *
+ *
+ * @param str the CharSequence to check, may be null
+ * @param searchStr the CharSequence to find, may be null
+ * @return the first index of the search CharSequence,
+ * -1 if no match or {@code null} string input
+ * @since 2.5
+ * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
+ */
+ public static int indexOfIgnoreCase(CharSequence str, CharSequence searchStr) {
+ return indexOfIgnoreCase(str, searchStr, 0);
+ }
+
+ /**
+ * Case in-sensitive find of the first index within a CharSequence + * from the specified position.
+ * + *A {@code null} CharSequence will return {@code -1}. + * A negative start position is treated as zero. + * An empty ("") search CharSequence always matches. + * A start position greater than the string length only matches + * an empty search CharSequence.
+ * + *
+ * StringUtils.indexOfIgnoreCase(null, *, *) = -1
+ * StringUtils.indexOfIgnoreCase(*, null, *) = -1
+ * StringUtils.indexOfIgnoreCase("", "", 0) = 0
+ * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0) = 0
+ * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0) = 2
+ * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
+ * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3) = 5
+ * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9) = -1
+ * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
+ * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2) = 2
+ * StringUtils.indexOfIgnoreCase("abc", "", 9) = 3
+ *
+ *
+ * @param str the CharSequence to check, may be null
+ * @param searchStr the CharSequence to find, may be null
+ * @param startPos the start position, negative treated as zero
+ * @return the first index of the search CharSequence,
+ * -1 if no match or {@code null} string input
+ * @since 2.5
+ * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
+ */
+ public static int indexOfIgnoreCase(CharSequence str, CharSequence searchStr, int startPos) {
+ if (str == null || searchStr == null) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startPos < 0) {
+ startPos = 0;
+ }
+ int endLimit = (str.length() - searchStr.length()) + 1;
+ if (startPos > endLimit) {
+ return INDEX_NOT_FOUND;
+ }
+ if (searchStr.length() == 0) {
+ return startPos;
+ }
+ for (int i = startPos; i < endLimit; i++) {
+ if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ // LastIndexOf
+ //-----------------------------------------------------------------------
+ /**
+ * Finds the last index within a CharSequence, handling {@code null}. + * This method uses {@link String#lastIndexOf(int)} if possible.
+ * + *A {@code null} or empty ("") CharSequence will return {@code -1}.
+ * + *
+ * StringUtils.lastIndexOf(null, *) = -1
+ * StringUtils.lastIndexOf("", *) = -1
+ * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
+ * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
+ *
+ *
+ * @param seq the CharSequence to check, may be null
+ * @param searchChar the character to find
+ * @return the last index of the search character,
+ * -1 if no match or {@code null} string input
+ * @since 2.0
+ * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
+ */
+ public static int lastIndexOf(CharSequence seq, int searchChar) {
+ if (isEmpty(seq)) {
+ return INDEX_NOT_FOUND;
+ }
+ return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
+ }
+
+ /**
+ * Finds the last index within a CharSequence from a start position, + * handling {@code null}. + * This method uses {@link String#lastIndexOf(int, int)} if possible.
+ * + *A {@code null} or empty ("") CharSequence will return {@code -1}. + * A negative start position returns {@code -1}. + * A start position greater than the string length searches the whole string.
+ * + *
+ * StringUtils.lastIndexOf(null, *, *) = -1
+ * StringUtils.lastIndexOf("", *, *) = -1
+ * StringUtils.lastIndexOf("aabaabaa", 'b', 8) = 5
+ * StringUtils.lastIndexOf("aabaabaa", 'b', 4) = 2
+ * StringUtils.lastIndexOf("aabaabaa", 'b', 0) = -1
+ * StringUtils.lastIndexOf("aabaabaa", 'b', 9) = 5
+ * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
+ * StringUtils.lastIndexOf("aabaabaa", 'a', 0) = 0
+ *
+ *
+ * @param seq the CharSequence to check, may be null
+ * @param searchChar the character to find
+ * @param startPos the start position
+ * @return the last index of the search character,
+ * -1 if no match or {@code null} string input
+ * @since 2.0
+ * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
+ */
+ public static int lastIndexOf(CharSequence seq, int searchChar, int startPos) {
+ if (isEmpty(seq)) {
+ return INDEX_NOT_FOUND;
+ }
+ return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
+ }
+
+ /**
+ * Finds the last index within a CharSequence, handling {@code null}. + * This method uses {@link String#lastIndexOf(String)} if possible.
+ * + *A {@code null} CharSequence will return {@code -1}.
+ * + *
+ * StringUtils.lastIndexOf(null, *) = -1
+ * StringUtils.lastIndexOf(*, null) = -1
+ * StringUtils.lastIndexOf("", "") = 0
+ * StringUtils.lastIndexOf("aabaabaa", "a") = 7
+ * StringUtils.lastIndexOf("aabaabaa", "b") = 5
+ * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
+ * StringUtils.lastIndexOf("aabaabaa", "") = 8
+ *
+ *
+ * @param seq the CharSequence to check, may be null
+ * @param searchSeq the CharSequence to find, may be null
+ * @return the last index of the search String,
+ * -1 if no match or {@code null} string input
+ * @since 2.0
+ * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
+ */
+ public static int lastIndexOf(CharSequence seq, CharSequence searchSeq) {
+ if (seq == null || searchSeq == null) {
+ return INDEX_NOT_FOUND;
+ }
+ return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
+ }
+
+ /**
+ * Finds the n-th last index within a String, handling {@code null}. + * This method uses {@link String#lastIndexOf(String)}.
+ * + *A {@code null} String will return {@code -1}.
+ * + *
+ * StringUtils.lastOrdinalIndexOf(null, *, *) = -1
+ * StringUtils.lastOrdinalIndexOf(*, null, *) = -1
+ * StringUtils.lastOrdinalIndexOf("", "", *) = 0
+ * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1) = 7
+ * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2) = 6
+ * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1) = 5
+ * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2) = 2
+ * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
+ * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
+ * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1) = 8
+ * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2) = 8
+ *
+ *
+ * Note that 'tail(CharSequence str, int n)' may be implemented as:
+ * + *+ * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1) + *+ * + * @param str the CharSequence to check, may be null + * @param searchStr the CharSequence to find, may be null + * @param ordinal the n-th last {@code searchStr} to find + * @return the n-th last index of the search CharSequence, + * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input + * @since 2.5 + * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int) + */ + public static int lastOrdinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal) { + return ordinalIndexOf(str, searchStr, ordinal, true); + } + + /** + *
Finds the first index within a CharSequence, handling {@code null}. + * This method uses {@link String#lastIndexOf(String, int)} if possible.
+ * + *A {@code null} CharSequence will return {@code -1}. + * A negative start position returns {@code -1}. + * An empty ("") search CharSequence always matches unless the start position is negative. + * A start position greater than the string length searches the whole string.
+ * + *
+ * StringUtils.lastIndexOf(null, *, *) = -1
+ * StringUtils.lastIndexOf(*, null, *) = -1
+ * StringUtils.lastIndexOf("aabaabaa", "a", 8) = 7
+ * StringUtils.lastIndexOf("aabaabaa", "b", 8) = 5
+ * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
+ * StringUtils.lastIndexOf("aabaabaa", "b", 9) = 5
+ * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
+ * StringUtils.lastIndexOf("aabaabaa", "a", 0) = 0
+ * StringUtils.lastIndexOf("aabaabaa", "b", 0) = -1
+ *
+ *
+ * @param seq the CharSequence to check, may be null
+ * @param searchSeq the CharSequence to find, may be null
+ * @param startPos the start position, negative treated as zero
+ * @return the first index of the search CharSequence,
+ * -1 if no match or {@code null} string input
+ * @since 2.0
+ * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
+ */
+ public static int lastIndexOf(CharSequence seq, CharSequence searchSeq, int startPos) {
+ if (seq == null || searchSeq == null) {
+ return INDEX_NOT_FOUND;
+ }
+ return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
+ }
+
+ /**
+ * Case in-sensitive find of the last index within a CharSequence.
+ * + *A {@code null} CharSequence will return {@code -1}. + * A negative start position returns {@code -1}. + * An empty ("") search CharSequence always matches unless the start position is negative. + * A start position greater than the string length searches the whole string.
+ * + *
+ * StringUtils.lastIndexOfIgnoreCase(null, *) = -1
+ * StringUtils.lastIndexOfIgnoreCase(*, null) = -1
+ * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A") = 7
+ * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B") = 5
+ * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
+ *
+ *
+ * @param str the CharSequence to check, may be null
+ * @param searchStr the CharSequence to find, may be null
+ * @return the first index of the search CharSequence,
+ * -1 if no match or {@code null} string input
+ * @since 2.5
+ * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
+ */
+ public static int lastIndexOfIgnoreCase(CharSequence str, CharSequence searchStr) {
+ if (str == null || searchStr == null) {
+ return INDEX_NOT_FOUND;
+ }
+ return lastIndexOfIgnoreCase(str, searchStr, str.length());
+ }
+
+ /**
+ * Case in-sensitive find of the last index within a CharSequence + * from the specified position.
+ * + *A {@code null} CharSequence will return {@code -1}. + * A negative start position returns {@code -1}. + * An empty ("") search CharSequence always matches unless the start position is negative. + * A start position greater than the string length searches the whole string.
+ * + *
+ * StringUtils.lastIndexOfIgnoreCase(null, *, *) = -1
+ * StringUtils.lastIndexOfIgnoreCase(*, null, *) = -1
+ * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8) = 7
+ * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8) = 5
+ * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
+ * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9) = 5
+ * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
+ * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0) = 0
+ * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0) = -1
+ *
+ *
+ * @param str the CharSequence to check, may be null
+ * @param searchStr the CharSequence to find, may be null
+ * @param startPos the start position
+ * @return the first index of the search CharSequence,
+ * -1 if no match or {@code null} input
+ * @since 2.5
+ * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
+ */
+ public static int lastIndexOfIgnoreCase(CharSequence str, CharSequence searchStr, int startPos) {
+ if (str == null || searchStr == null) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startPos > (str.length() - searchStr.length())) {
+ startPos = str.length() - searchStr.length();
+ }
+ if (startPos < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (searchStr.length() == 0) {
+ return startPos;
+ }
+
+ for (int i = startPos; i >= 0; i--) {
+ if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ // Contains
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if CharSequence contains a search character, handling {@code null}. + * This method uses {@link String#indexOf(int)} if possible.
+ * + *A {@code null} or empty ("") CharSequence will return {@code false}.
+ * + *
+ * StringUtils.contains(null, *) = false
+ * StringUtils.contains("", *) = false
+ * StringUtils.contains("abc", 'a') = true
+ * StringUtils.contains("abc", 'z') = false
+ *
+ *
+ * @param seq the CharSequence to check, may be null
+ * @param searchChar the character to find
+ * @return true if the CharSequence contains the search character,
+ * false if not or {@code null} string input
+ * @since 2.0
+ * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
+ */
+ public static boolean contains(CharSequence seq, int searchChar) {
+ if (isEmpty(seq)) {
+ return false;
+ }
+ return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
+ }
+
+ /**
+ * Checks if CharSequence contains a search CharSequence, handling {@code null}. + * This method uses {@link String#indexOf(String)} if possible.
+ * + *A {@code null} CharSequence will return {@code false}.
+ * + *
+ * StringUtils.contains(null, *) = false
+ * StringUtils.contains(*, null) = false
+ * StringUtils.contains("", "") = true
+ * StringUtils.contains("abc", "") = true
+ * StringUtils.contains("abc", "a") = true
+ * StringUtils.contains("abc", "z") = false
+ *
+ *
+ * @param seq the CharSequence to check, may be null
+ * @param searchSeq the CharSequence to find, may be null
+ * @return true if the CharSequence contains the search CharSequence,
+ * false if not or {@code null} string input
+ * @since 2.0
+ * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
+ */
+ public static boolean contains(CharSequence seq, CharSequence searchSeq) {
+ if (seq == null || searchSeq == null) {
+ return false;
+ }
+ return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
+ }
+
+ /**
+ * Checks if CharSequence contains a search CharSequence irrespective of case, + * handling {@code null}. Case-insensitivity is defined as by + * {@link String#equalsIgnoreCase(String)}. + * + *
A {@code null} CharSequence will return {@code false}.
+ * + *
+ * StringUtils.contains(null, *) = false
+ * StringUtils.contains(*, null) = false
+ * StringUtils.contains("", "") = true
+ * StringUtils.contains("abc", "") = true
+ * StringUtils.contains("abc", "a") = true
+ * StringUtils.contains("abc", "z") = false
+ * StringUtils.contains("abc", "A") = true
+ * StringUtils.contains("abc", "Z") = false
+ *
+ *
+ * @param str the CharSequence to check, may be null
+ * @param searchStr the CharSequence to find, may be null
+ * @return true if the CharSequence contains the search CharSequence irrespective of
+ * case or false if not or {@code null} string input
+ * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
+ */
+ public static boolean containsIgnoreCase(CharSequence str, CharSequence searchStr) {
+ if (str == null || searchStr == null) {
+ return false;
+ }
+ int len = searchStr.length();
+ int max = str.length() - len;
+ for (int i = 0; i <= max; i++) {
+ if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check whether the given CharSequence contains any whitespace characters.
+ * @param seq the CharSequence to check (may be {@code null})
+ * @return {@code true} if the CharSequence is not empty and
+ * contains at least 1 whitespace character
+ * @see java.lang.Character#isWhitespace
+ * @since 3.0
+ */
+ // From org.springframework.util.StringUtils, under Apache License 2.0
+ public static boolean containsWhitespace(CharSequence seq) {
+ if (isEmpty(seq)) {
+ return false;
+ }
+ int strLen = seq.length();
+ for (int i = 0; i < strLen; i++) {
+ if (Character.isWhitespace(seq.charAt(i))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // IndexOfAny chars
+ //-----------------------------------------------------------------------
+ /**
+ * Search a CharSequence to find the first index of any + * character in the given set of characters.
+ * + *A {@code null} String will return {@code -1}. + * A {@code null} or zero length search array will return {@code -1}.
+ * + *
+ * StringUtils.indexOfAny(null, *) = -1
+ * StringUtils.indexOfAny("", *) = -1
+ * StringUtils.indexOfAny(*, null) = -1
+ * StringUtils.indexOfAny(*, []) = -1
+ * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0
+ * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3
+ * StringUtils.indexOfAny("aba", ['z']) = -1
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @param searchChars the chars to search for, may be null
+ * @return the index of any of the chars, -1 if no match or null input
+ * @since 2.0
+ * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
+ */
+ public static int indexOfAny(CharSequence cs, char... searchChars) {
+ if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
+ return INDEX_NOT_FOUND;
+ }
+ int csLen = cs.length();
+ int csLast = csLen - 1;
+ int searchLen = searchChars.length;
+ int searchLast = searchLen - 1;
+ for (int i = 0; i < csLen; i++) {
+ char ch = cs.charAt(i);
+ for (int j = 0; j < searchLen; j++) {
+ if (searchChars[j] == ch) {
+ if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
+ // ch is a supplementary character
+ if (searchChars[j + 1] == cs.charAt(i + 1)) {
+ return i;
+ }
+ } else {
+ return i;
+ }
+ }
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Search a CharSequence to find the first index of any + * character in the given set of characters.
+ * + *A {@code null} String will return {@code -1}. + * A {@code null} search string will return {@code -1}.
+ * + *
+ * StringUtils.indexOfAny(null, *) = -1
+ * StringUtils.indexOfAny("", *) = -1
+ * StringUtils.indexOfAny(*, null) = -1
+ * StringUtils.indexOfAny(*, "") = -1
+ * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
+ * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
+ * StringUtils.indexOfAny("aba","z") = -1
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @param searchChars the chars to search for, may be null
+ * @return the index of any of the chars, -1 if no match or null input
+ * @since 2.0
+ * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
+ */
+ public static int indexOfAny(CharSequence cs, String searchChars) {
+ if (isEmpty(cs) || isEmpty(searchChars)) {
+ return INDEX_NOT_FOUND;
+ }
+ return indexOfAny(cs, searchChars.toCharArray());
+ }
+
+ // ContainsAny
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if the CharSequence contains any character in the given + * set of characters.
+ * + *A {@code null} CharSequence will return {@code false}. + * A {@code null} or zero length search array will return {@code false}.
+ * + *
+ * StringUtils.containsAny(null, *) = false
+ * StringUtils.containsAny("", *) = false
+ * StringUtils.containsAny(*, null) = false
+ * StringUtils.containsAny(*, []) = false
+ * StringUtils.containsAny("zzabyycdxx",['z','a']) = true
+ * StringUtils.containsAny("zzabyycdxx",['b','y']) = true
+ * StringUtils.containsAny("aba", ['z']) = false
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @param searchChars the chars to search for, may be null
+ * @return the {@code true} if any of the chars are found,
+ * {@code false} if no match or null input
+ * @since 2.4
+ * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
+ */
+ public static boolean containsAny(CharSequence cs, char... searchChars) {
+ if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
+ return false;
+ }
+ int csLength = cs.length();
+ int searchLength = searchChars.length;
+ int csLast = csLength - 1;
+ int searchLast = searchLength - 1;
+ for (int i = 0; i < csLength; i++) {
+ char ch = cs.charAt(i);
+ for (int j = 0; j < searchLength; j++) {
+ if (searchChars[j] == ch) {
+ if (Character.isHighSurrogate(ch)) {
+ if (j == searchLast) {
+ // missing low surrogate, fine, like String.indexOf(String)
+ return true;
+ }
+ if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
+ return true;
+ }
+ } else {
+ // ch is in the Basic Multilingual Plane
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * + * Checks if the CharSequence contains any character in the given set of characters. + *
+ * + *+ * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return + * {@code false}. + *
+ * + *
+ * StringUtils.containsAny(null, *) = false
+ * StringUtils.containsAny("", *) = false
+ * StringUtils.containsAny(*, null) = false
+ * StringUtils.containsAny(*, "") = false
+ * StringUtils.containsAny("zzabyycdxx", "za") = true
+ * StringUtils.containsAny("zzabyycdxx", "by") = true
+ * StringUtils.containsAny("aba","z") = false
+ *
+ *
+ * @param cs
+ * the CharSequence to check, may be null
+ * @param searchChars
+ * the chars to search for, may be null
+ * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
+ * @since 2.4
+ * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
+ */
+ public static boolean containsAny(CharSequence cs, CharSequence searchChars) {
+ if (searchChars == null) {
+ return false;
+ }
+ return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
+ }
+
+ // IndexOfAnyBut chars
+ //-----------------------------------------------------------------------
+ /**
+ * Searches a CharSequence to find the first index of any + * character not in the given set of characters.
+ * + *A {@code null} CharSequence will return {@code -1}. + * A {@code null} or zero length search array will return {@code -1}.
+ * + *
+ * StringUtils.indexOfAnyBut(null, *) = -1
+ * StringUtils.indexOfAnyBut("", *) = -1
+ * StringUtils.indexOfAnyBut(*, null) = -1
+ * StringUtils.indexOfAnyBut(*, []) = -1
+ * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
+ * StringUtils.indexOfAnyBut("aba", new char[] {'z'} ) = 0
+ * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} ) = -1
+
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @param searchChars the chars to search for, may be null
+ * @return the index of any of the chars, -1 if no match or null input
+ * @since 2.0
+ * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
+ */
+ public static int indexOfAnyBut(CharSequence cs, char... searchChars) {
+ if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
+ return INDEX_NOT_FOUND;
+ }
+ int csLen = cs.length();
+ int csLast = csLen - 1;
+ int searchLen = searchChars.length;
+ int searchLast = searchLen - 1;
+ outer:
+ for (int i = 0; i < csLen; i++) {
+ char ch = cs.charAt(i);
+ for (int j = 0; j < searchLen; j++) {
+ if (searchChars[j] == ch) {
+ if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
+ if (searchChars[j + 1] == cs.charAt(i + 1)) {
+ continue outer;
+ }
+ } else {
+ continue outer;
+ }
+ }
+ }
+ return i;
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Search a CharSequence to find the first index of any + * character not in the given set of characters.
+ * + *A {@code null} CharSequence will return {@code -1}. + * A {@code null} or empty search string will return {@code -1}.
+ * + *
+ * StringUtils.indexOfAnyBut(null, *) = -1
+ * StringUtils.indexOfAnyBut("", *) = -1
+ * StringUtils.indexOfAnyBut(*, null) = -1
+ * StringUtils.indexOfAnyBut(*, "") = -1
+ * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
+ * StringUtils.indexOfAnyBut("zzabyycdxx", "") = -1
+ * StringUtils.indexOfAnyBut("aba","ab") = -1
+ *
+ *
+ * @param seq the CharSequence to check, may be null
+ * @param searchChars the chars to search for, may be null
+ * @return the index of any of the chars, -1 if no match or null input
+ * @since 2.0
+ * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
+ */
+ public static int indexOfAnyBut(CharSequence seq, CharSequence searchChars) {
+ if (isEmpty(seq) || isEmpty(searchChars)) {
+ return INDEX_NOT_FOUND;
+ }
+ int strLen = seq.length();
+ for (int i = 0; i < strLen; i++) {
+ char ch = seq.charAt(i);
+ boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
+ if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
+ char ch2 = seq.charAt(i + 1);
+ if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
+ return i;
+ }
+ } else {
+ if (!chFound) {
+ return i;
+ }
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ // ContainsOnly
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if the CharSequence contains only certain characters.
+ * + *A {@code null} CharSequence will return {@code false}. + * A {@code null} valid character array will return {@code false}. + * An empty CharSequence (length()=0) always returns {@code true}.
+ * + *
+ * StringUtils.containsOnly(null, *) = false
+ * StringUtils.containsOnly(*, null) = false
+ * StringUtils.containsOnly("", *) = true
+ * StringUtils.containsOnly("ab", '') = false
+ * StringUtils.containsOnly("abab", 'abc') = true
+ * StringUtils.containsOnly("ab1", 'abc') = false
+ * StringUtils.containsOnly("abz", 'abc') = false
+ *
+ *
+ * @param cs the String to check, may be null
+ * @param valid an array of valid chars, may be null
+ * @return true if it only contains valid chars and is non-null
+ * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
+ */
+ public static boolean containsOnly(CharSequence cs, char... valid) {
+ // All these pre-checks are to maintain API with an older version
+ if (valid == null || cs == null) {
+ return false;
+ }
+ if (cs.length() == 0) {
+ return true;
+ }
+ if (valid.length == 0) {
+ return false;
+ }
+ return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the CharSequence contains only certain characters.
+ * + *A {@code null} CharSequence will return {@code false}. + * A {@code null} valid character String will return {@code false}. + * An empty String (length()=0) always returns {@code true}.
+ * + *
+ * StringUtils.containsOnly(null, *) = false
+ * StringUtils.containsOnly(*, null) = false
+ * StringUtils.containsOnly("", *) = true
+ * StringUtils.containsOnly("ab", "") = false
+ * StringUtils.containsOnly("abab", "abc") = true
+ * StringUtils.containsOnly("ab1", "abc") = false
+ * StringUtils.containsOnly("abz", "abc") = false
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @param validChars a String of valid chars, may be null
+ * @return true if it only contains valid chars and is non-null
+ * @since 2.0
+ * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
+ */
+ public static boolean containsOnly(CharSequence cs, String validChars) {
+ if (cs == null || validChars == null) {
+ return false;
+ }
+ return containsOnly(cs, validChars.toCharArray());
+ }
+
+ // ContainsNone
+ //-----------------------------------------------------------------------
+ /**
+ * Checks that the CharSequence does not contain certain characters.
+ * + *A {@code null} CharSequence will return {@code true}. + * A {@code null} invalid character array will return {@code true}. + * An empty CharSequence (length()=0) always returns true.
+ * + *
+ * StringUtils.containsNone(null, *) = true
+ * StringUtils.containsNone(*, null) = true
+ * StringUtils.containsNone("", *) = true
+ * StringUtils.containsNone("ab", '') = true
+ * StringUtils.containsNone("abab", 'xyz') = true
+ * StringUtils.containsNone("ab1", 'xyz') = true
+ * StringUtils.containsNone("abz", 'xyz') = false
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @param searchChars an array of invalid chars, may be null
+ * @return true if it contains none of the invalid chars, or is null
+ * @since 2.0
+ * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
+ */
+ public static boolean containsNone(CharSequence cs, char... searchChars) {
+ if (cs == null || searchChars == null) {
+ return true;
+ }
+ int csLen = cs.length();
+ int csLast = csLen - 1;
+ int searchLen = searchChars.length;
+ int searchLast = searchLen - 1;
+ for (int i = 0; i < csLen; i++) {
+ char ch = cs.charAt(i);
+ for (int j = 0; j < searchLen; j++) {
+ if (searchChars[j] == ch) {
+ if (Character.isHighSurrogate(ch)) {
+ if (j == searchLast) {
+ // missing low surrogate, fine, like String.indexOf(String)
+ return false;
+ }
+ if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
+ return false;
+ }
+ } else {
+ // ch is in the Basic Multilingual Plane
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks that the CharSequence does not contain certain characters.
+ * + *A {@code null} CharSequence will return {@code true}. + * A {@code null} invalid character array will return {@code true}. + * An empty String ("") always returns true.
+ * + *
+ * StringUtils.containsNone(null, *) = true
+ * StringUtils.containsNone(*, null) = true
+ * StringUtils.containsNone("", *) = true
+ * StringUtils.containsNone("ab", "") = true
+ * StringUtils.containsNone("abab", "xyz") = true
+ * StringUtils.containsNone("ab1", "xyz") = true
+ * StringUtils.containsNone("abz", "xyz") = false
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @param invalidChars a String of invalid chars, may be null
+ * @return true if it contains none of the invalid chars, or is null
+ * @since 2.0
+ * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
+ */
+ public static boolean containsNone(CharSequence cs, String invalidChars) {
+ if (cs == null || invalidChars == null) {
+ return true;
+ }
+ return containsNone(cs, invalidChars.toCharArray());
+ }
+
+ // IndexOfAny strings
+ //-----------------------------------------------------------------------
+ /**
+ * Find the first index of any of a set of potential substrings.
+ * + *A {@code null} CharSequence will return {@code -1}. + * A {@code null} or zero length search array will return {@code -1}. + * A {@code null} search array entry will be ignored, but a search + * array containing "" will return {@code 0} if {@code str} is not + * null. This method uses {@link String#indexOf(String)} if possible.
+ * + *
+ * StringUtils.indexOfAny(null, *) = -1
+ * StringUtils.indexOfAny(*, null) = -1
+ * StringUtils.indexOfAny(*, []) = -1
+ * StringUtils.indexOfAny("zzabyycdxx", ["ab","cd"]) = 2
+ * StringUtils.indexOfAny("zzabyycdxx", ["cd","ab"]) = 2
+ * StringUtils.indexOfAny("zzabyycdxx", ["mn","op"]) = -1
+ * StringUtils.indexOfAny("zzabyycdxx", ["zab","aby"]) = 1
+ * StringUtils.indexOfAny("zzabyycdxx", [""]) = 0
+ * StringUtils.indexOfAny("", [""]) = 0
+ * StringUtils.indexOfAny("", ["a"]) = -1
+ *
+ *
+ * @param str the CharSequence to check, may be null
+ * @param searchStrs the CharSequences to search for, may be null
+ * @return the first index of any of the searchStrs in str, -1 if no match
+ * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
+ */
+ public static int indexOfAny(CharSequence str, CharSequence... searchStrs) {
+ if (str == null || searchStrs == null) {
+ return INDEX_NOT_FOUND;
+ }
+ int sz = searchStrs.length;
+
+ // String's can't have a MAX_VALUEth index.
+ int ret = Integer.MAX_VALUE;
+
+ int tmp = 0;
+ for (int i = 0; i < sz; i++) {
+ CharSequence search = searchStrs[i];
+ if (search == null) {
+ continue;
+ }
+ tmp = CharSequenceUtils.indexOf(str, search, 0);
+ if (tmp == INDEX_NOT_FOUND) {
+ continue;
+ }
+
+ if (tmp < ret) {
+ ret = tmp;
+ }
+ }
+
+ return (ret == Integer.MAX_VALUE) ? INDEX_NOT_FOUND : ret;
+ }
+
+ /**
+ * Find the latest index of any of a set of potential substrings.
+ * + *A {@code null} CharSequence will return {@code -1}. + * A {@code null} search array will return {@code -1}. + * A {@code null} or zero length search array entry will be ignored, + * but a search array containing "" will return the length of {@code str} + * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible
+ * + *
+ * StringUtils.lastIndexOfAny(null, *) = -1
+ * StringUtils.lastIndexOfAny(*, null) = -1
+ * StringUtils.lastIndexOfAny(*, []) = -1
+ * StringUtils.lastIndexOfAny(*, [null]) = -1
+ * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab","cd"]) = 6
+ * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd","ab"]) = 6
+ * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
+ * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
+ * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn",""]) = 10
+ *
+ *
+ * @param str the CharSequence to check, may be null
+ * @param searchStrs the CharSequences to search for, may be null
+ * @return the last index of any of the CharSequences, -1 if no match
+ * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
+ */
+ public static int lastIndexOfAny(CharSequence str, CharSequence... searchStrs) {
+ if (str == null || searchStrs == null) {
+ return INDEX_NOT_FOUND;
+ }
+ int sz = searchStrs.length;
+ int ret = INDEX_NOT_FOUND;
+ int tmp = 0;
+ for (int i = 0; i < sz; i++) {
+ CharSequence search = searchStrs[i];
+ if (search == null) {
+ continue;
+ }
+ tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
+ if (tmp > ret) {
+ ret = tmp;
+ }
+ }
+ return ret;
+ }
+
+ // Substring
+ //-----------------------------------------------------------------------
+ /**
+ * Gets a substring from the specified String avoiding exceptions.
+ * + *A negative start position can be used to start {@code n} + * characters from the end of the String.
+ * + *A {@code null} String will return {@code null}. + * An empty ("") String will return "".
+ * + *
+ * StringUtils.substring(null, *) = null
+ * StringUtils.substring("", *) = ""
+ * StringUtils.substring("abc", 0) = "abc"
+ * StringUtils.substring("abc", 2) = "c"
+ * StringUtils.substring("abc", 4) = ""
+ * StringUtils.substring("abc", -2) = "bc"
+ * StringUtils.substring("abc", -4) = "abc"
+ *
+ *
+ * @param str the String to get the substring from, may be null
+ * @param start the position to start from, negative means
+ * count back from the end of the String by this many characters
+ * @return substring from start position, {@code null} if null String input
+ */
+ public static String substring(String str, int start) {
+ if (str == null) {
+ return null;
+ }
+
+ // handle negatives, which means last n characters
+ if (start < 0) {
+ start = str.length() + start; // remember start is negative
+ }
+
+ if (start < 0) {
+ start = 0;
+ }
+ if (start > str.length()) {
+ return EMPTY;
+ }
+
+ return str.substring(start);
+ }
+
+ /**
+ * Gets a substring from the specified String avoiding exceptions.
+ * + *A negative start position can be used to start/end {@code n} + * characters from the end of the String.
+ * + *The returned substring starts with the character in the {@code start} + * position and ends before the {@code end} position. All position counting is + * zero-based -- i.e., to start at the beginning of the string use + * {@code start = 0}. Negative start and end positions can be used to + * specify offsets relative to the end of the String.
+ * + *If {@code start} is not strictly to the left of {@code end}, "" + * is returned.
+ * + *
+ * StringUtils.substring(null, *, *) = null
+ * StringUtils.substring("", * , *) = "";
+ * StringUtils.substring("abc", 0, 2) = "ab"
+ * StringUtils.substring("abc", 2, 0) = ""
+ * StringUtils.substring("abc", 2, 4) = "c"
+ * StringUtils.substring("abc", 4, 6) = ""
+ * StringUtils.substring("abc", 2, 2) = ""
+ * StringUtils.substring("abc", -2, -1) = "b"
+ * StringUtils.substring("abc", -4, 2) = "ab"
+ *
+ *
+ * @param str the String to get the substring from, may be null
+ * @param start the position to start from, negative means
+ * count back from the end of the String by this many characters
+ * @param end the position to end at (exclusive), negative means
+ * count back from the end of the String by this many characters
+ * @return substring from start position to end position,
+ * {@code null} if null String input
+ */
+ public static String substring(String str, int start, int end) {
+ if (str == null) {
+ return null;
+ }
+
+ // handle negatives
+ if (end < 0) {
+ end = str.length() + end; // remember end is negative
+ }
+ if (start < 0) {
+ start = str.length() + start; // remember start is negative
+ }
+
+ // check length next
+ if (end > str.length()) {
+ end = str.length();
+ }
+
+ // if start is greater than end, return ""
+ if (start > end) {
+ return EMPTY;
+ }
+
+ if (start < 0) {
+ start = 0;
+ }
+ if (end < 0) {
+ end = 0;
+ }
+
+ return str.substring(start, end);
+ }
+
+ // Left/Right/Mid
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the leftmost {@code len} characters of a String.
+ * + *If {@code len} characters are not available, or the + * String is {@code null}, the String will be returned without + * an exception. An empty String is returned if len is negative.
+ * + *
+ * StringUtils.left(null, *) = null
+ * StringUtils.left(*, -ve) = ""
+ * StringUtils.left("", *) = ""
+ * StringUtils.left("abc", 0) = ""
+ * StringUtils.left("abc", 2) = "ab"
+ * StringUtils.left("abc", 4) = "abc"
+ *
+ *
+ * @param str the String to get the leftmost characters from, may be null
+ * @param len the length of the required String
+ * @return the leftmost characters, {@code null} if null String input
+ */
+ public static String left(String str, int len) {
+ if (str == null) {
+ return null;
+ }
+ if (len < 0) {
+ return EMPTY;
+ }
+ if (str.length() <= len) {
+ return str;
+ }
+ return str.substring(0, len);
+ }
+
+ /**
+ * Gets the rightmost {@code len} characters of a String.
+ * + *If {@code len} characters are not available, or the String + * is {@code null}, the String will be returned without an + * an exception. An empty String is returned if len is negative.
+ * + *
+ * StringUtils.right(null, *) = null
+ * StringUtils.right(*, -ve) = ""
+ * StringUtils.right("", *) = ""
+ * StringUtils.right("abc", 0) = ""
+ * StringUtils.right("abc", 2) = "bc"
+ * StringUtils.right("abc", 4) = "abc"
+ *
+ *
+ * @param str the String to get the rightmost characters from, may be null
+ * @param len the length of the required String
+ * @return the rightmost characters, {@code null} if null String input
+ */
+ public static String right(String str, int len) {
+ if (str == null) {
+ return null;
+ }
+ if (len < 0) {
+ return EMPTY;
+ }
+ if (str.length() <= len) {
+ return str;
+ }
+ return str.substring(str.length() - len);
+ }
+
+ /**
+ * Gets {@code len} characters from the middle of a String.
+ * + *If {@code len} characters are not available, the remainder + * of the String will be returned without an exception. If the + * String is {@code null}, {@code null} will be returned. + * An empty String is returned if len is negative or exceeds the + * length of {@code str}.
+ * + *
+ * StringUtils.mid(null, *, *) = null
+ * StringUtils.mid(*, *, -ve) = ""
+ * StringUtils.mid("", 0, *) = ""
+ * StringUtils.mid("abc", 0, 2) = "ab"
+ * StringUtils.mid("abc", 0, 4) = "abc"
+ * StringUtils.mid("abc", 2, 4) = "c"
+ * StringUtils.mid("abc", 4, 2) = ""
+ * StringUtils.mid("abc", -2, 2) = "ab"
+ *
+ *
+ * @param str the String to get the characters from, may be null
+ * @param pos the position to start from, negative treated as zero
+ * @param len the length of the required String
+ * @return the middle characters, {@code null} if null String input
+ */
+ public static String mid(String str, int pos, int len) {
+ if (str == null) {
+ return null;
+ }
+ if (len < 0 || pos > str.length()) {
+ return EMPTY;
+ }
+ if (pos < 0) {
+ pos = 0;
+ }
+ if (str.length() <= (pos + len)) {
+ return str.substring(pos);
+ }
+ return str.substring(pos, pos + len);
+ }
+
+ // SubStringAfter/SubStringBefore
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the substring before the first occurrence of a separator. + * The separator is not returned.
+ * + *A {@code null} string input will return {@code null}. + * An empty ("") string input will return the empty string. + * A {@code null} separator will return the input string.
+ * + *If nothing is found, the string input is returned.
+ * + *
+ * StringUtils.substringBefore(null, *) = null
+ * StringUtils.substringBefore("", *) = ""
+ * StringUtils.substringBefore("abc", "a") = ""
+ * StringUtils.substringBefore("abcba", "b") = "a"
+ * StringUtils.substringBefore("abc", "c") = "ab"
+ * StringUtils.substringBefore("abc", "d") = "abc"
+ * StringUtils.substringBefore("abc", "") = ""
+ * StringUtils.substringBefore("abc", null) = "abc"
+ *
+ *
+ * @param str the String to get a substring from, may be null
+ * @param separator the String to search for, may be null
+ * @return the substring before the first occurrence of the separator,
+ * {@code null} if null String input
+ * @since 2.0
+ */
+ public static String substringBefore(String str, String separator) {
+ if (isEmpty(str) || separator == null) {
+ return str;
+ }
+ if (separator.length() == 0) {
+ return EMPTY;
+ }
+ int pos = str.indexOf(separator);
+ if (pos == INDEX_NOT_FOUND) {
+ return str;
+ }
+ return str.substring(0, pos);
+ }
+
+ /**
+ * Gets the substring after the first occurrence of a separator. + * The separator is not returned.
+ * + *A {@code null} string input will return {@code null}. + * An empty ("") string input will return the empty string. + * A {@code null} separator will return the empty string if the + * input string is not {@code null}.
+ * + *If nothing is found, the empty string is returned.
+ * + *
+ * StringUtils.substringAfter(null, *) = null
+ * StringUtils.substringAfter("", *) = ""
+ * StringUtils.substringAfter(*, null) = ""
+ * StringUtils.substringAfter("abc", "a") = "bc"
+ * StringUtils.substringAfter("abcba", "b") = "cba"
+ * StringUtils.substringAfter("abc", "c") = ""
+ * StringUtils.substringAfter("abc", "d") = ""
+ * StringUtils.substringAfter("abc", "") = "abc"
+ *
+ *
+ * @param str the String to get a substring from, may be null
+ * @param separator the String to search for, may be null
+ * @return the substring after the first occurrence of the separator,
+ * {@code null} if null String input
+ * @since 2.0
+ */
+ public static String substringAfter(String str, String separator) {
+ if (isEmpty(str)) {
+ return str;
+ }
+ if (separator == null) {
+ return EMPTY;
+ }
+ int pos = str.indexOf(separator);
+ if (pos == INDEX_NOT_FOUND) {
+ return EMPTY;
+ }
+ return str.substring(pos + separator.length());
+ }
+
+ /**
+ * Gets the substring before the last occurrence of a separator. + * The separator is not returned.
+ * + *A {@code null} string input will return {@code null}. + * An empty ("") string input will return the empty string. + * An empty or {@code null} separator will return the input string.
+ * + *If nothing is found, the string input is returned.
+ * + *
+ * StringUtils.substringBeforeLast(null, *) = null
+ * StringUtils.substringBeforeLast("", *) = ""
+ * StringUtils.substringBeforeLast("abcba", "b") = "abc"
+ * StringUtils.substringBeforeLast("abc", "c") = "ab"
+ * StringUtils.substringBeforeLast("a", "a") = ""
+ * StringUtils.substringBeforeLast("a", "z") = "a"
+ * StringUtils.substringBeforeLast("a", null) = "a"
+ * StringUtils.substringBeforeLast("a", "") = "a"
+ *
+ *
+ * @param str the String to get a substring from, may be null
+ * @param separator the String to search for, may be null
+ * @return the substring before the last occurrence of the separator,
+ * {@code null} if null String input
+ * @since 2.0
+ */
+ public static String substringBeforeLast(String str, String separator) {
+ if (isEmpty(str) || isEmpty(separator)) {
+ return str;
+ }
+ int pos = str.lastIndexOf(separator);
+ if (pos == INDEX_NOT_FOUND) {
+ return str;
+ }
+ return str.substring(0, pos);
+ }
+
+ /**
+ * Gets the substring after the last occurrence of a separator. + * The separator is not returned.
+ * + *A {@code null} string input will return {@code null}. + * An empty ("") string input will return the empty string. + * An empty or {@code null} separator will return the empty string if + * the input string is not {@code null}.
+ * + *If nothing is found, the empty string is returned.
+ * + *
+ * StringUtils.substringAfterLast(null, *) = null
+ * StringUtils.substringAfterLast("", *) = ""
+ * StringUtils.substringAfterLast(*, "") = ""
+ * StringUtils.substringAfterLast(*, null) = ""
+ * StringUtils.substringAfterLast("abc", "a") = "bc"
+ * StringUtils.substringAfterLast("abcba", "b") = "a"
+ * StringUtils.substringAfterLast("abc", "c") = ""
+ * StringUtils.substringAfterLast("a", "a") = ""
+ * StringUtils.substringAfterLast("a", "z") = ""
+ *
+ *
+ * @param str the String to get a substring from, may be null
+ * @param separator the String to search for, may be null
+ * @return the substring after the last occurrence of the separator,
+ * {@code null} if null String input
+ * @since 2.0
+ */
+ public static String substringAfterLast(String str, String separator) {
+ if (isEmpty(str)) {
+ return str;
+ }
+ if (isEmpty(separator)) {
+ return EMPTY;
+ }
+ int pos = str.lastIndexOf(separator);
+ if (pos == INDEX_NOT_FOUND || pos == (str.length() - separator.length())) {
+ return EMPTY;
+ }
+ return str.substring(pos + separator.length());
+ }
+
+ // Substring between
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the String that is nested in between two instances of the + * same String.
+ * + *A {@code null} input String returns {@code null}. + * A {@code null} tag returns {@code null}.
+ * + *
+ * StringUtils.substringBetween(null, *) = null
+ * StringUtils.substringBetween("", "") = ""
+ * StringUtils.substringBetween("", "tag") = null
+ * StringUtils.substringBetween("tagabctag", null) = null
+ * StringUtils.substringBetween("tagabctag", "") = ""
+ * StringUtils.substringBetween("tagabctag", "tag") = "abc"
+ *
+ *
+ * @param str the String containing the substring, may be null
+ * @param tag the String before and after the substring, may be null
+ * @return the substring, {@code null} if no match
+ * @since 2.0
+ */
+ public static String substringBetween(String str, String tag) {
+ return substringBetween(str, tag, tag);
+ }
+
+ /**
+ * Gets the String that is nested in between two Strings. + * Only the first match is returned.
+ * + *A {@code null} input String returns {@code null}. + * A {@code null} open/close returns {@code null} (no match). + * An empty ("") open and close returns an empty string.
+ * + *
+ * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
+ * StringUtils.substringBetween(null, *, *) = null
+ * StringUtils.substringBetween(*, null, *) = null
+ * StringUtils.substringBetween(*, *, null) = null
+ * StringUtils.substringBetween("", "", "") = ""
+ * StringUtils.substringBetween("", "", "]") = null
+ * StringUtils.substringBetween("", "[", "]") = null
+ * StringUtils.substringBetween("yabcz", "", "") = ""
+ * StringUtils.substringBetween("yabcz", "y", "z") = "abc"
+ * StringUtils.substringBetween("yabczyabcz", "y", "z") = "abc"
+ *
+ *
+ * @param str the String containing the substring, may be null
+ * @param open the String before the substring, may be null
+ * @param close the String after the substring, may be null
+ * @return the substring, {@code null} if no match
+ * @since 2.0
+ */
+ public static String substringBetween(String str, String open, String close) {
+ if (str == null || open == null || close == null) {
+ return null;
+ }
+ int start = str.indexOf(open);
+ if (start != INDEX_NOT_FOUND) {
+ int end = str.indexOf(close, start + open.length());
+ if (end != INDEX_NOT_FOUND) {
+ return str.substring(start + open.length(), end);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Searches a String for substrings delimited by a start and end tag, + * returning all matching substrings in an array.
+ * + *A {@code null} input String returns {@code null}. + * A {@code null} open/close returns {@code null} (no match). + * An empty ("") open/close returns {@code null} (no match).
+ * + *
+ * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
+ * StringUtils.substringsBetween(null, *, *) = null
+ * StringUtils.substringsBetween(*, null, *) = null
+ * StringUtils.substringsBetween(*, *, null) = null
+ * StringUtils.substringsBetween("", "[", "]") = []
+ *
+ *
+ * @param str the String containing the substrings, null returns null, empty returns empty
+ * @param open the String identifying the start of the substring, empty returns null
+ * @param close the String identifying the end of the substring, empty returns null
+ * @return a String Array of substrings, or {@code null} if no match
+ * @since 2.3
+ */
+ public static String[] substringsBetween(String str, String open, String close) {
+ if (str == null || isEmpty(open) || isEmpty(close)) {
+ return null;
+ }
+ int strLen = str.length();
+ if (strLen == 0) {
+ return ArrayUtils.EMPTY_STRING_ARRAY;
+ }
+ int closeLen = close.length();
+ int openLen = open.length();
+ ListSplits the provided text into an array, using whitespace as the + * separator. + * Whitespace is defined by {@link Character#isWhitespace(char)}.
+ * + *The separator is not included in the returned String array. + * Adjacent separators are treated as one separator. + * For more control over the split use the StrTokenizer class.
+ * + *A {@code null} input String returns {@code null}.
+ * + *
+ * StringUtils.split(null) = null
+ * StringUtils.split("") = []
+ * StringUtils.split("abc def") = ["abc", "def"]
+ * StringUtils.split("abc def") = ["abc", "def"]
+ * StringUtils.split(" abc ") = ["abc"]
+ *
+ *
+ * @param str the String to parse, may be null
+ * @return an array of parsed Strings, {@code null} if null String input
+ */
+ public static String[] split(String str) {
+ return split(str, null, -1);
+ }
+
+ /**
+ * Splits the provided text into an array, separator specified. + * This is an alternative to using StringTokenizer.
+ * + *The separator is not included in the returned String array. + * Adjacent separators are treated as one separator. + * For more control over the split use the StrTokenizer class.
+ * + *A {@code null} input String returns {@code null}.
+ * + *
+ * StringUtils.split(null, *) = null
+ * StringUtils.split("", *) = []
+ * StringUtils.split("a.b.c", '.') = ["a", "b", "c"]
+ * StringUtils.split("a..b.c", '.') = ["a", "b", "c"]
+ * StringUtils.split("a:b:c", '.') = ["a:b:c"]
+ * StringUtils.split("a b c", ' ') = ["a", "b", "c"]
+ *
+ *
+ * @param str the String to parse, may be null
+ * @param separatorChar the character used as the delimiter
+ * @return an array of parsed Strings, {@code null} if null String input
+ * @since 2.0
+ */
+ public static String[] split(String str, char separatorChar) {
+ return splitWorker(str, separatorChar, false);
+ }
+
+ /**
+ * Splits the provided text into an array, separators specified. + * This is an alternative to using StringTokenizer.
+ * + *The separator is not included in the returned String array. + * Adjacent separators are treated as one separator. + * For more control over the split use the StrTokenizer class.
+ * + *A {@code null} input String returns {@code null}. + * A {@code null} separatorChars splits on whitespace.
+ * + *
+ * StringUtils.split(null, *) = null
+ * StringUtils.split("", *) = []
+ * StringUtils.split("abc def", null) = ["abc", "def"]
+ * StringUtils.split("abc def", " ") = ["abc", "def"]
+ * StringUtils.split("abc def", " ") = ["abc", "def"]
+ * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
+ *
+ *
+ * @param str the String to parse, may be null
+ * @param separatorChars the characters used as the delimiters,
+ * {@code null} splits on whitespace
+ * @return an array of parsed Strings, {@code null} if null String input
+ */
+ public static String[] split(String str, String separatorChars) {
+ return splitWorker(str, separatorChars, -1, false);
+ }
+
+ /**
+ * Splits the provided text into an array with a maximum length, + * separators specified.
+ * + *The separator is not included in the returned String array. + * Adjacent separators are treated as one separator.
+ * + *A {@code null} input String returns {@code null}. + * A {@code null} separatorChars splits on whitespace.
+ * + *If more than {@code max} delimited substrings are found, the last + * returned string includes all characters after the first {@code max - 1} + * returned strings (including separator characters).
+ * + *
+ * StringUtils.split(null, *, *) = null
+ * StringUtils.split("", *, *) = []
+ * StringUtils.split("ab de fg", null, 0) = ["ab", "cd", "ef"]
+ * StringUtils.split("ab de fg", null, 0) = ["ab", "cd", "ef"]
+ * StringUtils.split("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"]
+ * StringUtils.split("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
+ *
+ *
+ * @param str the String to parse, may be null
+ * @param separatorChars the characters used as the delimiters,
+ * {@code null} splits on whitespace
+ * @param max the maximum number of elements to include in the
+ * array. A zero or negative value implies no limit
+ * @return an array of parsed Strings, {@code null} if null String input
+ */
+ public static String[] split(String str, String separatorChars, int max) {
+ return splitWorker(str, separatorChars, max, false);
+ }
+
+ /**
+ * Splits the provided text into an array, separator string specified.
+ * + *The separator(s) will not be included in the returned String array. + * Adjacent separators are treated as one separator.
+ * + *A {@code null} input String returns {@code null}. + * A {@code null} separator splits on whitespace.
+ * + *
+ * StringUtils.splitByWholeSeparator(null, *) = null
+ * StringUtils.splitByWholeSeparator("", *) = []
+ * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"]
+ * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"]
+ * StringUtils.splitByWholeSeparator("ab:cd:ef", ":") = ["ab", "cd", "ef"]
+ * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
+ *
+ *
+ * @param str the String to parse, may be null
+ * @param separator String containing the String to be used as a delimiter,
+ * {@code null} splits on whitespace
+ * @return an array of parsed Strings, {@code null} if null String was input
+ */
+ public static String[] splitByWholeSeparator(String str, String separator) {
+ return splitByWholeSeparatorWorker( str, separator, -1, false ) ;
+ }
+
+ /**
+ * Splits the provided text into an array, separator string specified. + * Returns a maximum of {@code max} substrings.
+ * + *The separator(s) will not be included in the returned String array. + * Adjacent separators are treated as one separator.
+ * + *A {@code null} input String returns {@code null}. + * A {@code null} separator splits on whitespace.
+ * + *
+ * StringUtils.splitByWholeSeparator(null, *, *) = null
+ * StringUtils.splitByWholeSeparator("", *, *) = []
+ * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"]
+ * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"]
+ * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
+ * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
+ * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
+ *
+ *
+ * @param str the String to parse, may be null
+ * @param separator String containing the String to be used as a delimiter,
+ * {@code null} splits on whitespace
+ * @param max the maximum number of elements to include in the returned
+ * array. A zero or negative value implies no limit.
+ * @return an array of parsed Strings, {@code null} if null String was input
+ */
+ public static String[] splitByWholeSeparator( String str, String separator, int max ) {
+ return splitByWholeSeparatorWorker(str, separator, max, false);
+ }
+
+ /**
+ * Splits the provided text into an array, separator string specified.
+ * + *The separator is not included in the returned String array. + * Adjacent separators are treated as separators for empty tokens. + * For more control over the split use the StrTokenizer class.
+ * + *A {@code null} input String returns {@code null}. + * A {@code null} separator splits on whitespace.
+ * + *
+ * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *) = null
+ * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *) = []
+ * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "de", "fg"]
+ * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "", "", "de", "fg"]
+ * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"]
+ * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
+ *
+ *
+ * @param str the String to parse, may be null
+ * @param separator String containing the String to be used as a delimiter,
+ * {@code null} splits on whitespace
+ * @return an array of parsed Strings, {@code null} if null String was input
+ * @since 2.4
+ */
+ public static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator) {
+ return splitByWholeSeparatorWorker(str, separator, -1, true);
+ }
+
+ /**
+ * Splits the provided text into an array, separator string specified. + * Returns a maximum of {@code max} substrings.
+ * + *The separator is not included in the returned String array. + * Adjacent separators are treated as separators for empty tokens. + * For more control over the split use the StrTokenizer class.
+ * + *A {@code null} input String returns {@code null}. + * A {@code null} separator splits on whitespace.
+ * + *
+ * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *) = null
+ * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *) = []
+ * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "de", "fg"]
+ * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "", "", "de", "fg"]
+ * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
+ * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
+ * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
+ *
+ *
+ * @param str the String to parse, may be null
+ * @param separator String containing the String to be used as a delimiter,
+ * {@code null} splits on whitespace
+ * @param max the maximum number of elements to include in the returned
+ * array. A zero or negative value implies no limit.
+ * @return an array of parsed Strings, {@code null} if null String was input
+ * @since 2.4
+ */
+ public static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator, int max) {
+ return splitByWholeSeparatorWorker(str, separator, max, true);
+ }
+
+ /**
+ * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
+ *
+ * @param str the String to parse, may be {@code null}
+ * @param separator String containing the String to be used as a delimiter,
+ * {@code null} splits on whitespace
+ * @param max the maximum number of elements to include in the returned
+ * array. A zero or negative value implies no limit.
+ * @param preserveAllTokens if {@code true}, adjacent separators are
+ * treated as empty token separators; if {@code false}, adjacent
+ * separators are treated as one separator.
+ * @return an array of parsed Strings, {@code null} if null String input
+ * @since 2.4
+ */
+ private static String[] splitByWholeSeparatorWorker(
+ String str, String separator, int max, boolean preserveAllTokens) {
+ if (str == null) {
+ return null;
+ }
+
+ int len = str.length();
+
+ if (len == 0) {
+ return ArrayUtils.EMPTY_STRING_ARRAY;
+ }
+
+ if ((separator == null) || (EMPTY.equals(separator))) {
+ // Split on whitespace.
+ return splitWorker(str, null, max, preserveAllTokens);
+ }
+
+ int separatorLength = separator.length();
+
+ ArrayListSplits the provided text into an array, using whitespace as the + * separator, preserving all tokens, including empty tokens created by + * adjacent separators. This is an alternative to using StringTokenizer. + * Whitespace is defined by {@link Character#isWhitespace(char)}.
+ * + *The separator is not included in the returned String array. + * Adjacent separators are treated as separators for empty tokens. + * For more control over the split use the StrTokenizer class.
+ * + *A {@code null} input String returns {@code null}.
+ * + *
+ * StringUtils.splitPreserveAllTokens(null) = null
+ * StringUtils.splitPreserveAllTokens("") = []
+ * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "def"]
+ * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "", "def"]
+ * StringUtils.splitPreserveAllTokens(" abc ") = ["", "abc", ""]
+ *
+ *
+ * @param str the String to parse, may be {@code null}
+ * @return an array of parsed Strings, {@code null} if null String input
+ * @since 2.1
+ */
+ public static String[] splitPreserveAllTokens(String str) {
+ return splitWorker(str, null, -1, true);
+ }
+
+ /**
+ * Splits the provided text into an array, separator specified, + * preserving all tokens, including empty tokens created by adjacent + * separators. This is an alternative to using StringTokenizer.
+ * + *The separator is not included in the returned String array. + * Adjacent separators are treated as separators for empty tokens. + * For more control over the split use the StrTokenizer class.
+ * + *A {@code null} input String returns {@code null}.
+ * + *
+ * StringUtils.splitPreserveAllTokens(null, *) = null
+ * StringUtils.splitPreserveAllTokens("", *) = []
+ * StringUtils.splitPreserveAllTokens("a.b.c", '.') = ["a", "b", "c"]
+ * StringUtils.splitPreserveAllTokens("a..b.c", '.') = ["a", "", "b", "c"]
+ * StringUtils.splitPreserveAllTokens("a:b:c", '.') = ["a:b:c"]
+ * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
+ * StringUtils.splitPreserveAllTokens("a b c", ' ') = ["a", "b", "c"]
+ * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", ""]
+ * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", "", ""]
+ * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", a", "b", "c"]
+ * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", "", a", "b", "c"]
+ * StringUtils.splitPreserveAllTokens(" a b c ", ' ') = ["", a", "b", "c", ""]
+ *
+ *
+ * @param str the String to parse, may be {@code null}
+ * @param separatorChar the character used as the delimiter,
+ * {@code null} splits on whitespace
+ * @return an array of parsed Strings, {@code null} if null String input
+ * @since 2.1
+ */
+ public static String[] splitPreserveAllTokens(String str, char separatorChar) {
+ return splitWorker(str, separatorChar, true);
+ }
+
+ /**
+ * Performs the logic for the {@code split} and
+ * {@code splitPreserveAllTokens} methods that do not return a
+ * maximum array length.
+ *
+ * @param str the String to parse, may be {@code null}
+ * @param separatorChar the separate character
+ * @param preserveAllTokens if {@code true}, adjacent separators are
+ * treated as empty token separators; if {@code false}, adjacent
+ * separators are treated as one separator.
+ * @return an array of parsed Strings, {@code null} if null String input
+ */
+ private static String[] splitWorker(String str, char separatorChar, boolean preserveAllTokens) {
+ // Performance tuned for 2.0 (JDK1.4)
+
+ if (str == null) {
+ return null;
+ }
+ int len = str.length();
+ if (len == 0) {
+ return ArrayUtils.EMPTY_STRING_ARRAY;
+ }
+ ListSplits the provided text into an array, separators specified, + * preserving all tokens, including empty tokens created by adjacent + * separators. This is an alternative to using StringTokenizer.
+ * + *The separator is not included in the returned String array. + * Adjacent separators are treated as separators for empty tokens. + * For more control over the split use the StrTokenizer class.
+ * + *A {@code null} input String returns {@code null}. + * A {@code null} separatorChars splits on whitespace.
+ * + *
+ * StringUtils.splitPreserveAllTokens(null, *) = null
+ * StringUtils.splitPreserveAllTokens("", *) = []
+ * StringUtils.splitPreserveAllTokens("abc def", null) = ["abc", "def"]
+ * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "def"]
+ * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "", def"]
+ * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"]
+ * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":") = ["ab", "cd", "ef", ""]
+ * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
+ * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":") = ["ab", "", cd", "ef"]
+ * StringUtils.splitPreserveAllTokens(":cd:ef", ":") = ["", cd", "ef"]
+ * StringUtils.splitPreserveAllTokens("::cd:ef", ":") = ["", "", cd", "ef"]
+ * StringUtils.splitPreserveAllTokens(":cd:ef:", ":") = ["", cd", "ef", ""]
+ *
+ *
+ * @param str the String to parse, may be {@code null}
+ * @param separatorChars the characters used as the delimiters,
+ * {@code null} splits on whitespace
+ * @return an array of parsed Strings, {@code null} if null String input
+ * @since 2.1
+ */
+ public static String[] splitPreserveAllTokens(String str, String separatorChars) {
+ return splitWorker(str, separatorChars, -1, true);
+ }
+
+ /**
+ * Splits the provided text into an array with a maximum length, + * separators specified, preserving all tokens, including empty tokens + * created by adjacent separators.
+ * + *The separator is not included in the returned String array. + * Adjacent separators are treated as separators for empty tokens. + * Adjacent separators are treated as one separator.
+ * + *A {@code null} input String returns {@code null}. + * A {@code null} separatorChars splits on whitespace.
+ * + *If more than {@code max} delimited substrings are found, the last + * returned string includes all characters after the first {@code max - 1} + * returned strings (including separator characters).
+ * + *
+ * StringUtils.splitPreserveAllTokens(null, *, *) = null
+ * StringUtils.splitPreserveAllTokens("", *, *) = []
+ * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"]
+ * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"]
+ * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"]
+ * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
+ * StringUtils.splitPreserveAllTokens("ab de fg", null, 2) = ["ab", " de fg"]
+ * StringUtils.splitPreserveAllTokens("ab de fg", null, 3) = ["ab", "", " de fg"]
+ * StringUtils.splitPreserveAllTokens("ab de fg", null, 4) = ["ab", "", "", "de fg"]
+ *
+ *
+ * @param str the String to parse, may be {@code null}
+ * @param separatorChars the characters used as the delimiters,
+ * {@code null} splits on whitespace
+ * @param max the maximum number of elements to include in the
+ * array. A zero or negative value implies no limit
+ * @return an array of parsed Strings, {@code null} if null String input
+ * @since 2.1
+ */
+ public static String[] splitPreserveAllTokens(String str, String separatorChars, int max) {
+ return splitWorker(str, separatorChars, max, true);
+ }
+
+ /**
+ * Performs the logic for the {@code split} and
+ * {@code splitPreserveAllTokens} methods that return a maximum array
+ * length.
+ *
+ * @param str the String to parse, may be {@code null}
+ * @param separatorChars the separate character
+ * @param max the maximum number of elements to include in the
+ * array. A zero or negative value implies no limit.
+ * @param preserveAllTokens if {@code true}, adjacent separators are
+ * treated as empty token separators; if {@code false}, adjacent
+ * separators are treated as one separator.
+ * @return an array of parsed Strings, {@code null} if null String input
+ */
+ private static String[] splitWorker(String str, String separatorChars, int max, boolean preserveAllTokens) {
+ // Performance tuned for 2.0 (JDK1.4)
+ // Direct code is quicker than StringTokenizer.
+ // Also, StringTokenizer uses isSpace() not isWhitespace()
+
+ if (str == null) {
+ return null;
+ }
+ int len = str.length();
+ if (len == 0) {
+ return ArrayUtils.EMPTY_STRING_ARRAY;
+ }
+ ListSplits a String by Character type as returned by + * {@code java.lang.Character.getType(char)}. Groups of contiguous + * characters of the same type are returned as complete tokens. + *
+ * StringUtils.splitByCharacterType(null) = null
+ * StringUtils.splitByCharacterType("") = []
+ * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"]
+ * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"]
+ * StringUtils.splitByCharacterType("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"]
+ * StringUtils.splitByCharacterType("number5") = ["number", "5"]
+ * StringUtils.splitByCharacterType("fooBar") = ["foo", "B", "ar"]
+ * StringUtils.splitByCharacterType("foo200Bar") = ["foo", "200", "B", "ar"]
+ * StringUtils.splitByCharacterType("ASFRules") = ["ASFR", "ules"]
+ *
+ * @param str the String to split, may be {@code null}
+ * @return an array of parsed Strings, {@code null} if null String input
+ * @since 2.4
+ */
+ public static String[] splitByCharacterType(String str) {
+ return splitByCharacterType(str, false);
+ }
+
+ /**
+ * Splits a String by Character type as returned by + * {@code java.lang.Character.getType(char)}. Groups of contiguous + * characters of the same type are returned as complete tokens, with the + * following exception: the character of type + * {@code Character.UPPERCASE_LETTER}, if any, immediately + * preceding a token of type {@code Character.LOWERCASE_LETTER} + * will belong to the following token rather than to the preceding, if any, + * {@code Character.UPPERCASE_LETTER} token. + *
+ * StringUtils.splitByCharacterTypeCamelCase(null) = null
+ * StringUtils.splitByCharacterTypeCamelCase("") = []
+ * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"]
+ * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"]
+ * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"]
+ * StringUtils.splitByCharacterTypeCamelCase("number5") = ["number", "5"]
+ * StringUtils.splitByCharacterTypeCamelCase("fooBar") = ["foo", "Bar"]
+ * StringUtils.splitByCharacterTypeCamelCase("foo200Bar") = ["foo", "200", "Bar"]
+ * StringUtils.splitByCharacterTypeCamelCase("ASFRules") = ["ASF", "Rules"]
+ *
+ * @param str the String to split, may be {@code null}
+ * @return an array of parsed Strings, {@code null} if null String input
+ * @since 2.4
+ */
+ public static String[] splitByCharacterTypeCamelCase(String str) {
+ return splitByCharacterType(str, true);
+ }
+
+ /**
+ * Splits a String by Character type as returned by
+ * {@code java.lang.Character.getType(char)}. Groups of contiguous
+ * characters of the same type are returned as complete tokens, with the
+ * following exception: if {@code camelCase} is {@code true},
+ * the character of type {@code Character.UPPERCASE_LETTER}, if any,
+ * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
+ * will belong to the following token rather than to the preceding, if any,
+ * {@code Character.UPPERCASE_LETTER} token.
+ * @param str the String to split, may be {@code null}
+ * @param camelCase whether to use so-called "camel-case" for letter types
+ * @return an array of parsed Strings, {@code null} if null String input
+ * @since 2.4
+ */
+ private static String[] splitByCharacterType(String str, boolean camelCase) {
+ if (str == null) {
+ return null;
+ }
+ if (str.length() == 0) {
+ return ArrayUtils.EMPTY_STRING_ARRAY;
+ }
+ char[] c = str.toCharArray();
+ List Joins the elements of the provided array into a single String
+ * containing the provided list of elements. No separator is added to the joined String.
+ * Null objects or empty strings within the array are represented by
+ * empty strings. Joins the elements of the provided array into a single String
+ * containing the provided list of elements. No delimiter is added before or after the list.
+ * Null objects or empty strings within the array are represented by
+ * empty strings. Joins the elements of the provided array into a single String
+ * containing the provided list of elements. No delimiter is added before or after the list.
+ * Null objects or empty strings within the array are represented by
+ * empty strings. Joins the elements of the provided array into a single String
+ * containing the provided list of elements. No delimiter is added before or after the list.
+ * A {@code null} separator is the same as an empty String ("").
+ * Null objects or empty strings within the array are represented by
+ * empty strings. Joins the elements of the provided array into a single String
+ * containing the provided list of elements. No delimiter is added before or after the list.
+ * A {@code null} separator is the same as an empty String ("").
+ * Null objects or empty strings within the array are represented by
+ * empty strings. Joins the elements of the provided {@code Iterator} into
+ * a single String containing the provided elements. No delimiter is added before or after the list. Null objects or empty
+ * strings within the iteration are represented by empty strings. See the examples here: {@link #join(Object[],char)}. Joins the elements of the provided {@code Iterator} into
+ * a single String containing the provided elements. No delimiter is added before or after the list.
+ * A {@code null} separator is the same as an empty String (""). See the examples here: {@link #join(Object[],String)}. Joins the elements of the provided {@code Iterable} into
+ * a single String containing the provided elements. No delimiter is added before or after the list. Null objects or empty
+ * strings within the iteration are represented by empty strings. See the examples here: {@link #join(Object[],char)}. Joins the elements of the provided {@code Iterable} into
+ * a single String containing the provided elements. No delimiter is added before or after the list.
+ * A {@code null} separator is the same as an empty String (""). See the examples here: {@link #join(Object[],String)}. Deletes all whitespaces from a String as defined by
+ * {@link Character#isWhitespace(char)}. Removes a substring only if it is at the beginning of a source string,
+ * otherwise returns the source string. A {@code null} source string will return {@code null}.
+ * An empty ("") source string will return the empty string.
+ * A {@code null} search string will return the source string. Case insensitive removal of a substring if it is at the beginning of a source string,
+ * otherwise returns the source string. A {@code null} source string will return {@code null}.
+ * An empty ("") source string will return the empty string.
+ * A {@code null} search string will return the source string. Removes a substring only if it is at the end of a source string,
+ * otherwise returns the source string. A {@code null} source string will return {@code null}.
+ * An empty ("") source string will return the empty string.
+ * A {@code null} search string will return the source string. Case insensitive removal of a substring if it is at the end of a source string,
+ * otherwise returns the source string. A {@code null} source string will return {@code null}.
+ * An empty ("") source string will return the empty string.
+ * A {@code null} search string will return the source string. Removes all occurrences of a substring from within the source string. A {@code null} source string will return {@code null}.
+ * An empty ("") source string will return the empty string.
+ * A {@code null} remove string will return the source string.
+ * An empty ("") remove string will return the source string. Removes all occurrences of a character from within the source string. A {@code null} source string will return {@code null}.
+ * An empty ("") source string will return the empty string. Replaces a String with another String inside a larger String, once. A {@code null} reference passed to this method is a no-op. Replaces all occurrences of a String within another String. A {@code null} reference passed to this method is a no-op. Replaces a String with another String inside a larger String,
+ * for the first {@code max} values of the search String. A {@code null} reference passed to this method is a no-op.
+ * Replaces all occurrences of Strings within another String.
+ *
+ * A {@code null} reference passed to this method is a no-op, or if
+ * any "search string" or "string to replace" is null, that replace will be
+ * ignored. This will not repeat. For repeating replaces, call the
+ * overloaded method.
+ *
+ * Replaces all occurrences of Strings within another String.
+ *
+ * A {@code null} reference passed to this method is a no-op, or if
+ * any "search string" or "string to replace" is null, that replace will be
+ * ignored.
+ *
+ * Replaces all occurrences of Strings within another String.
+ *
+ * A {@code null} reference passed to this method is a no-op, or if
+ * any "search string" or "string to replace" is null, that replace will be
+ * ignored.
+ * Replaces all occurrences of a character in a String with another.
+ * This is a null-safe version of {@link String#replace(char, char)}. A {@code null} string input returns {@code null}.
+ * An empty ("") string input returns an empty string. Replaces multiple characters in a String in one go.
+ * This method can also be used to delete characters. For example: A {@code null} string input returns {@code null}.
+ * An empty ("") string input returns an empty string.
+ * A null or empty set of search characters returns the input string. The length of the search characters should normally equal the length
+ * of the replace characters.
+ * If the search characters is longer, then the extra search characters
+ * are deleted.
+ * If the search characters is shorter, then the extra replace characters
+ * are ignored. Overlays part of a String with another String. A {@code null} string input returns {@code null}.
+ * A negative index is treated as zero.
+ * An index greater than the string length is treated as the string length.
+ * The start index is always the smaller of the two indices. Removes one newline from end of a String if it's there,
+ * otherwise leave it alone. A newline is "{@code \n}",
+ * "{@code \r}", or "{@code \r\n}". NOTE: This method changed in 2.0.
+ * It now more closely matches Perl chomp. Remove the last character from a String. If the String ends in {@code \r\n}, then remove both
+ * of them. Repeat a String {@code repeat} times to form a
+ * new String. Repeat a String {@code repeat} times to form a
+ * new String, with a String separator injected each time. Returns padding using the specified delimiter repeated
+ * to a given length. Note: this method doesn't not support padding with
+ * Unicode Supplementary Characters
+ * as they require a pair of {@code char}s to be represented.
+ * If you are needing to support full I18N of your applications
+ * consider using {@link #repeat(String, int)} instead.
+ * Right pad a String with spaces (' '). The String is padded to the size of {@code size}. Right pad a String with a specified character. The String is padded to the size of {@code size}. Right pad a String with a specified String. The String is padded to the size of {@code size}. Left pad a String with spaces (' '). The String is padded to the size of {@code size}. Left pad a String with a specified character. Pad to a size of {@code size}. Left pad a String with a specified String. Pad to a size of {@code size}. Centers a String in a larger String of size {@code size}
+ * using the space character (' ').
+ *
+ * If the size is less than the String length, the String is returned.
+ * A {@code null} String returns {@code null}.
+ * A negative size is treated as zero. Equivalent to {@code center(str, size, " ")}. Centers a String in a larger String of size {@code size}.
+ * Uses a supplied character as the value to pad the String with. If the size is less than the String length, the String is returned.
+ * A {@code null} String returns {@code null}.
+ * A negative size is treated as zero. Centers a String in a larger String of size {@code size}.
+ * Uses a supplied String as the value to pad the String with. If the size is less than the String length, the String is returned.
+ * A {@code null} String returns {@code null}.
+ * A negative size is treated as zero. Converts a String to upper case as per {@link String#toUpperCase()}. A {@code null} input String returns {@code null}. Note: As described in the documentation for {@link String#toUpperCase()},
+ * the result of this method is affected by the current locale.
+ * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
+ * should be used with a specific locale (e.g. {@link Locale#ENGLISH}). Converts a String to upper case as per {@link String#toUpperCase(Locale)}. A {@code null} input String returns {@code null}. Converts a String to lower case as per {@link String#toLowerCase()}. A {@code null} input String returns {@code null}. Note: As described in the documentation for {@link String#toLowerCase()},
+ * the result of this method is affected by the current locale.
+ * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
+ * should be used with a specific locale (e.g. {@link Locale#ENGLISH}). Converts a String to lower case as per {@link String#toLowerCase(Locale)}. A {@code null} input String returns {@code null}. Capitalizes a String changing the first letter to title case as
+ * per {@link Character#toTitleCase(char)}. No other letters are changed. For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}.
+ * A {@code null} input String returns {@code null}. Uncapitalizes a String changing the first letter to title case as
+ * per {@link Character#toLowerCase(char)}. No other letters are changed. For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}.
+ * A {@code null} input String returns {@code null}. Swaps the case of a String changing upper and title case to
+ * lower case, and lower case to upper case. For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}.
+ * A {@code null} input String returns {@code null}. NOTE: This method changed in Lang version 2.0.
+ * It no longer performs a word based algorithm.
+ * If you only use ASCII, you will notice no change.
+ * That functionality is available in org.apache.commons.lang3.text.WordUtils. Counts how many times the substring appears in the larger string. A {@code null} or empty ("") String input returns {@code 0}. Checks if the CharSequence contains only Unicode letters. {@code null} will return {@code false}.
+ * An empty CharSequence (length()=0) will return {@code false}. Checks if the CharSequence contains only Unicode letters and
+ * space (' '). {@code null} will return {@code false}
+ * An empty CharSequence (length()=0) will return {@code true}. Checks if the CharSequence contains only Unicode letters or digits. {@code null} will return {@code false}.
+ * An empty CharSequence (length()=0) will return {@code false}. Checks if the CharSequence contains only Unicode letters, digits
+ * or space ({@code ' '}). {@code null} will return {@code false}.
+ * An empty CharSequence (length()=0) will return {@code true}. Checks if the CharSequence contains only ASCII printable characters. {@code null} will return {@code false}.
+ * An empty CharSequence (length()=0) will return {@code true}. Checks if the CharSequence contains only Unicode digits.
+ * A decimal point is not a Unicode digit and returns false. {@code null} will return {@code false}.
+ * An empty CharSequence (length()=0) will return {@code false}. Checks if the CharSequence contains only Unicode digits or space
+ * ({@code ' '}).
+ * A decimal point is not a Unicode digit and returns false. {@code null} will return {@code false}.
+ * An empty CharSequence (length()=0) will return {@code true}. Checks if the CharSequence contains only whitespace. {@code null} will return {@code false}.
+ * An empty CharSequence (length()=0) will return {@code true}. Checks if the CharSequence contains only lowercase characters. {@code null} will return {@code false}.
+ * An empty CharSequence (length()=0) will return {@code false}. Checks if the CharSequence contains only uppercase characters. {@code null} will return {@code false}.
+ * An empty String (length()=0) will return {@code false}. Returns either the passed in String,
+ * or if the String is {@code null}, an empty String (""). Returns either the passed in String, or if the String is
+ * {@code null}, the value of {@code defaultStr}. Returns either the passed in CharSequence, or if the CharSequence is
+ * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}. Returns either the passed in CharSequence, or if the CharSequence is
+ * empty or {@code null}, the value of {@code defaultStr}. Reverses a String as per {@link StringBuilder#reverse()}. A {@code null} String returns {@code null}. Reverses a String that is delimited by a specific character. The Strings between the delimiters are not reversed.
+ * Thus java.lang.String becomes String.lang.java (if the delimiter
+ * is {@code '.'}). Abbreviates a String using ellipses. This will turn
+ * "Now is the time for all good men" into "Now is the time for..." Specifically:
+ *
+ * StringUtils.join(null) = null
+ * StringUtils.join([]) = ""
+ * StringUtils.join([null]) = ""
+ * StringUtils.join(["a", "b", "c"]) = "abc"
+ * StringUtils.join([null, "", "a"]) = "a"
+ *
+ *
+ * @param
+ * StringUtils.join(null, *) = null
+ * StringUtils.join([], *) = ""
+ * StringUtils.join([null], *) = ""
+ * StringUtils.join(["a", "b", "c"], ';') = "a;b;c"
+ * StringUtils.join(["a", "b", "c"], null) = "abc"
+ * StringUtils.join([null, "", "a"], ';') = ";;a"
+ *
+ *
+ * @param array the array of values to join together, may be null
+ * @param separator the separator character to use
+ * @return the joined String, {@code null} if null array input
+ * @since 2.0
+ */
+ public static String join(Object[] array, char separator) {
+ if (array == null) {
+ return null;
+ }
+
+ return join(array, separator, 0, array.length);
+ }
+
+ /**
+ *
+ * StringUtils.join(null, *) = null
+ * StringUtils.join([], *) = ""
+ * StringUtils.join([null], *) = ""
+ * StringUtils.join(["a", "b", "c"], ';') = "a;b;c"
+ * StringUtils.join(["a", "b", "c"], null) = "abc"
+ * StringUtils.join([null, "", "a"], ';') = ";;a"
+ *
+ *
+ * @param array the array of values to join together, may be null
+ * @param separator the separator character to use
+ * @param startIndex the first index to start joining from. It is
+ * an error to pass in an end index past the end of the array
+ * @param endIndex the index to stop joining from (exclusive). It is
+ * an error to pass in an end index past the end of the array
+ * @return the joined String, {@code null} if null array input
+ * @since 2.0
+ */
+ public static String join(Object[] array, char separator, int startIndex, int endIndex) {
+ if (array == null) {
+ return null;
+ }
+ int noOfItems = (endIndex - startIndex);
+ if (noOfItems <= 0) {
+ return EMPTY;
+ }
+
+ StringBuilder buf = new StringBuilder(noOfItems * 16);
+
+ for (int i = startIndex; i < endIndex; i++) {
+ if (i > startIndex) {
+ buf.append(separator);
+ }
+ if (array[i] != null) {
+ buf.append(array[i]);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ *
+ * StringUtils.join(null, *) = null
+ * StringUtils.join([], *) = ""
+ * StringUtils.join([null], *) = ""
+ * StringUtils.join(["a", "b", "c"], "--") = "a--b--c"
+ * StringUtils.join(["a", "b", "c"], null) = "abc"
+ * StringUtils.join(["a", "b", "c"], "") = "abc"
+ * StringUtils.join([null, "", "a"], ',') = ",,a"
+ *
+ *
+ * @param array the array of values to join together, may be null
+ * @param separator the separator character to use, null treated as ""
+ * @return the joined String, {@code null} if null array input
+ */
+ public static String join(Object[] array, String separator) {
+ if (array == null) {
+ return null;
+ }
+ return join(array, separator, 0, array.length);
+ }
+
+ /**
+ *
+ * StringUtils.join(null, *) = null
+ * StringUtils.join([], *) = ""
+ * StringUtils.join([null], *) = ""
+ * StringUtils.join(["a", "b", "c"], "--") = "a--b--c"
+ * StringUtils.join(["a", "b", "c"], null) = "abc"
+ * StringUtils.join(["a", "b", "c"], "") = "abc"
+ * StringUtils.join([null, "", "a"], ',') = ",,a"
+ *
+ *
+ * @param array the array of values to join together, may be null
+ * @param separator the separator character to use, null treated as ""
+ * @param startIndex the first index to start joining from. It is
+ * an error to pass in an end index past the end of the array
+ * @param endIndex the index to stop joining from (exclusive). It is
+ * an error to pass in an end index past the end of the array
+ * @return the joined String, {@code null} if null array input
+ */
+ public static String join(Object[] array, String separator, int startIndex, int endIndex) {
+ if (array == null) {
+ return null;
+ }
+ if (separator == null) {
+ separator = EMPTY;
+ }
+
+ // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator))
+ // (Assuming that all Strings are roughly equally long)
+ int noOfItems = (endIndex - startIndex);
+ if (noOfItems <= 0) {
+ return EMPTY;
+ }
+
+ StringBuilder buf = new StringBuilder(noOfItems * 16);
+
+ for (int i = startIndex; i < endIndex; i++) {
+ if (i > startIndex) {
+ buf.append(separator);
+ }
+ if (array[i] != null) {
+ buf.append(array[i]);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ *
+ * StringUtils.deleteWhitespace(null) = null
+ * StringUtils.deleteWhitespace("") = ""
+ * StringUtils.deleteWhitespace("abc") = "abc"
+ * StringUtils.deleteWhitespace(" ab c ") = "abc"
+ *
+ *
+ * @param str the String to delete whitespace from, may be null
+ * @return the String without whitespaces, {@code null} if null String input
+ */
+ public static String deleteWhitespace(String str) {
+ if (isEmpty(str)) {
+ return str;
+ }
+ int sz = str.length();
+ char[] chs = new char[sz];
+ int count = 0;
+ for (int i = 0; i < sz; i++) {
+ if (!Character.isWhitespace(str.charAt(i))) {
+ chs[count++] = str.charAt(i);
+ }
+ }
+ if (count == sz) {
+ return str;
+ }
+ return new String(chs, 0, count);
+ }
+
+ // Remove
+ //-----------------------------------------------------------------------
+ /**
+ *
+ * StringUtils.removeStart(null, *) = null
+ * StringUtils.removeStart("", *) = ""
+ * StringUtils.removeStart(*, null) = *
+ * StringUtils.removeStart("www.domain.com", "www.") = "domain.com"
+ * StringUtils.removeStart("domain.com", "www.") = "domain.com"
+ * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
+ * StringUtils.removeStart("abc", "") = "abc"
+ *
+ *
+ * @param str the source String to search, may be null
+ * @param remove the String to search for and remove, may be null
+ * @return the substring with the string removed if found,
+ * {@code null} if null String input
+ * @since 2.1
+ */
+ public static String removeStart(String str, String remove) {
+ if (isEmpty(str) || isEmpty(remove)) {
+ return str;
+ }
+ if (str.startsWith(remove)){
+ return str.substring(remove.length());
+ }
+ return str;
+ }
+
+ /**
+ *
+ * StringUtils.removeStartIgnoreCase(null, *) = null
+ * StringUtils.removeStartIgnoreCase("", *) = ""
+ * StringUtils.removeStartIgnoreCase(*, null) = *
+ * StringUtils.removeStartIgnoreCase("www.domain.com", "www.") = "domain.com"
+ * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.") = "domain.com"
+ * StringUtils.removeStartIgnoreCase("domain.com", "www.") = "domain.com"
+ * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
+ * StringUtils.removeStartIgnoreCase("abc", "") = "abc"
+ *
+ *
+ * @param str the source String to search, may be null
+ * @param remove the String to search for (case insensitive) and remove, may be null
+ * @return the substring with the string removed if found,
+ * {@code null} if null String input
+ * @since 2.4
+ */
+ public static String removeStartIgnoreCase(String str, String remove) {
+ if (isEmpty(str) || isEmpty(remove)) {
+ return str;
+ }
+ if (startsWithIgnoreCase(str, remove)) {
+ return str.substring(remove.length());
+ }
+ return str;
+ }
+
+ /**
+ *
+ * StringUtils.removeEnd(null, *) = null
+ * StringUtils.removeEnd("", *) = ""
+ * StringUtils.removeEnd(*, null) = *
+ * StringUtils.removeEnd("www.domain.com", ".com.") = "www.domain.com"
+ * StringUtils.removeEnd("www.domain.com", ".com") = "www.domain"
+ * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
+ * StringUtils.removeEnd("abc", "") = "abc"
+ *
+ *
+ * @param str the source String to search, may be null
+ * @param remove the String to search for and remove, may be null
+ * @return the substring with the string removed if found,
+ * {@code null} if null String input
+ * @since 2.1
+ */
+ public static String removeEnd(String str, String remove) {
+ if (isEmpty(str) || isEmpty(remove)) {
+ return str;
+ }
+ if (str.endsWith(remove)) {
+ return str.substring(0, str.length() - remove.length());
+ }
+ return str;
+ }
+
+ /**
+ *
+ * StringUtils.removeEndIgnoreCase(null, *) = null
+ * StringUtils.removeEndIgnoreCase("", *) = ""
+ * StringUtils.removeEndIgnoreCase(*, null) = *
+ * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.") = "www.domain.com"
+ * StringUtils.removeEndIgnoreCase("www.domain.com", ".com") = "www.domain"
+ * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
+ * StringUtils.removeEndIgnoreCase("abc", "") = "abc"
+ * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
+ * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
+ *
+ *
+ * @param str the source String to search, may be null
+ * @param remove the String to search for (case insensitive) and remove, may be null
+ * @return the substring with the string removed if found,
+ * {@code null} if null String input
+ * @since 2.4
+ */
+ public static String removeEndIgnoreCase(String str, String remove) {
+ if (isEmpty(str) || isEmpty(remove)) {
+ return str;
+ }
+ if (endsWithIgnoreCase(str, remove)) {
+ return str.substring(0, str.length() - remove.length());
+ }
+ return str;
+ }
+
+ /**
+ *
+ * StringUtils.remove(null, *) = null
+ * StringUtils.remove("", *) = ""
+ * StringUtils.remove(*, null) = *
+ * StringUtils.remove(*, "") = *
+ * StringUtils.remove("queued", "ue") = "qd"
+ * StringUtils.remove("queued", "zz") = "queued"
+ *
+ *
+ * @param str the source String to search, may be null
+ * @param remove the String to search for and remove, may be null
+ * @return the substring with the string removed if found,
+ * {@code null} if null String input
+ * @since 2.1
+ */
+ public static String remove(String str, String remove) {
+ if (isEmpty(str) || isEmpty(remove)) {
+ return str;
+ }
+ return replace(str, remove, EMPTY, -1);
+ }
+
+ /**
+ *
+ * StringUtils.remove(null, *) = null
+ * StringUtils.remove("", *) = ""
+ * StringUtils.remove("queued", 'u') = "qeed"
+ * StringUtils.remove("queued", 'z') = "queued"
+ *
+ *
+ * @param str the source String to search, may be null
+ * @param remove the char to search for and remove, may be null
+ * @return the substring with the char removed if found,
+ * {@code null} if null String input
+ * @since 2.1
+ */
+ public static String remove(String str, char remove) {
+ if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
+ return str;
+ }
+ char[] chars = str.toCharArray();
+ int pos = 0;
+ for (int i = 0; i < chars.length; i++) {
+ if (chars[i] != remove) {
+ chars[pos++] = chars[i];
+ }
+ }
+ return new String(chars, 0, pos);
+ }
+
+ // Replacing
+ //-----------------------------------------------------------------------
+ /**
+ *
+ * StringUtils.replaceOnce(null, *, *) = null
+ * StringUtils.replaceOnce("", *, *) = ""
+ * StringUtils.replaceOnce("any", null, *) = "any"
+ * StringUtils.replaceOnce("any", *, null) = "any"
+ * StringUtils.replaceOnce("any", "", *) = "any"
+ * StringUtils.replaceOnce("aba", "a", null) = "aba"
+ * StringUtils.replaceOnce("aba", "a", "") = "ba"
+ * StringUtils.replaceOnce("aba", "a", "z") = "zba"
+ *
+ *
+ * @see #replace(String text, String searchString, String replacement, int max)
+ * @param text text to search and replace in, may be null
+ * @param searchString the String to search for, may be null
+ * @param replacement the String to replace with, may be null
+ * @return the text with any replacements processed,
+ * {@code null} if null String input
+ */
+ public static String replaceOnce(String text, String searchString, String replacement) {
+ return replace(text, searchString, replacement, 1);
+ }
+
+ /**
+ *
+ * StringUtils.replace(null, *, *) = null
+ * StringUtils.replace("", *, *) = ""
+ * StringUtils.replace("any", null, *) = "any"
+ * StringUtils.replace("any", *, null) = "any"
+ * StringUtils.replace("any", "", *) = "any"
+ * StringUtils.replace("aba", "a", null) = "aba"
+ * StringUtils.replace("aba", "a", "") = "b"
+ * StringUtils.replace("aba", "a", "z") = "zbz"
+ *
+ *
+ * @see #replace(String text, String searchString, String replacement, int max)
+ * @param text text to search and replace in, may be null
+ * @param searchString the String to search for, may be null
+ * @param replacement the String to replace it with, may be null
+ * @return the text with any replacements processed,
+ * {@code null} if null String input
+ */
+ public static String replace(String text, String searchString, String replacement) {
+ return replace(text, searchString, replacement, -1);
+ }
+
+ /**
+ *
+ * StringUtils.replace(null, *, *, *) = null
+ * StringUtils.replace("", *, *, *) = ""
+ * StringUtils.replace("any", null, *, *) = "any"
+ * StringUtils.replace("any", *, null, *) = "any"
+ * StringUtils.replace("any", "", *, *) = "any"
+ * StringUtils.replace("any", *, *, 0) = "any"
+ * StringUtils.replace("abaa", "a", null, -1) = "abaa"
+ * StringUtils.replace("abaa", "a", "", -1) = "b"
+ * StringUtils.replace("abaa", "a", "z", 0) = "abaa"
+ * StringUtils.replace("abaa", "a", "z", 1) = "zbaa"
+ * StringUtils.replace("abaa", "a", "z", 2) = "zbza"
+ * StringUtils.replace("abaa", "a", "z", -1) = "zbzz"
+ *
+ *
+ * @param text text to search and replace in, may be null
+ * @param searchString the String to search for, may be null
+ * @param replacement the String to replace it with, may be null
+ * @param max maximum number of values to replace, or {@code -1} if no maximum
+ * @return the text with any replacements processed,
+ * {@code null} if null String input
+ */
+ public static String replace(String text, String searchString, String replacement, int max) {
+ if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
+ return text;
+ }
+ int start = 0;
+ int end = text.indexOf(searchString, start);
+ if (end == INDEX_NOT_FOUND) {
+ return text;
+ }
+ int replLength = searchString.length();
+ int increase = replacement.length() - replLength;
+ increase = (increase < 0 ? 0 : increase);
+ increase *= (max < 0 ? 16 : (max > 64 ? 64 : max));
+ StringBuilder buf = new StringBuilder(text.length() + increase);
+ while (end != INDEX_NOT_FOUND) {
+ buf.append(text.substring(start, end)).append(replacement);
+ start = end + replLength;
+ if (--max == 0) {
+ break;
+ }
+ end = text.indexOf(searchString, start);
+ }
+ buf.append(text.substring(start));
+ return buf.toString();
+ }
+
+ /**
+ *
+ * StringUtils.replaceEach(null, *, *) = null
+ * StringUtils.replaceEach("", *, *) = ""
+ * StringUtils.replaceEach("aba", null, null) = "aba"
+ * StringUtils.replaceEach("aba", new String[0], null) = "aba"
+ * StringUtils.replaceEach("aba", null, new String[0]) = "aba"
+ * StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba"
+ * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b"
+ * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba"
+ * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
+ * (example of how it does not repeat)
+ * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte"
+ *
+ *
+ * @param text
+ * text to search and replace in, no-op if null
+ * @param searchList
+ * the Strings to search for, no-op if null
+ * @param replacementList
+ * the Strings to replace them with, no-op if null
+ * @return the text with any replacements processed, {@code null} if
+ * null String input
+ * @throws IllegalArgumentException
+ * if the lengths of the arrays are not the same (null is ok,
+ * and/or size 0)
+ * @since 2.4
+ */
+ public static String replaceEach(String text, String[] searchList, String[] replacementList) {
+ return replaceEach(text, searchList, replacementList, false, 0);
+ }
+
+ /**
+ *
+ * StringUtils.replaceEach(null, *, *, *) = null
+ * StringUtils.replaceEach("", *, *, *) = ""
+ * StringUtils.replaceEach("aba", null, null, *) = "aba"
+ * StringUtils.replaceEach("aba", new String[0], null, *) = "aba"
+ * StringUtils.replaceEach("aba", null, new String[0], *) = "aba"
+ * StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba"
+ * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b"
+ * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba"
+ * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte"
+ * (example of how it repeats)
+ * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte"
+ * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte"
+ * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, true) = IllegalStateException
+ * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, false) = "dcabe"
+ *
+ *
+ * @param text
+ * text to search and replace in, no-op if null
+ * @param searchList
+ * the Strings to search for, no-op if null
+ * @param replacementList
+ * the Strings to replace them with, no-op if null
+ * @return the text with any replacements processed, {@code null} if
+ * null String input
+ * @throws IllegalStateException
+ * if the search is repeating and there is an endless loop due
+ * to outputs of one being inputs to another
+ * @throws IllegalArgumentException
+ * if the lengths of the arrays are not the same (null is ok,
+ * and/or size 0)
+ * @since 2.4
+ */
+ public static String replaceEachRepeatedly(String text, String[] searchList, String[] replacementList) {
+ // timeToLive should be 0 if not used or nothing to replace, else it's
+ // the length of the replace array
+ int timeToLive = searchList == null ? 0 : searchList.length;
+ return replaceEach(text, searchList, replacementList, true, timeToLive);
+ }
+
+ /**
+ *
+ * StringUtils.replaceEach(null, *, *, *) = null
+ * StringUtils.replaceEach("", *, *, *) = ""
+ * StringUtils.replaceEach("aba", null, null, *) = "aba"
+ * StringUtils.replaceEach("aba", new String[0], null, *) = "aba"
+ * StringUtils.replaceEach("aba", null, new String[0], *) = "aba"
+ * StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba"
+ * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b"
+ * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba"
+ * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte"
+ * (example of how it repeats)
+ * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte"
+ * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte"
+ * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *) = IllegalStateException
+ *
+ *
+ * @param text
+ * text to search and replace in, no-op if null
+ * @param searchList
+ * the Strings to search for, no-op if null
+ * @param replacementList
+ * the Strings to replace them with, no-op if null
+ * @param repeat if true, then replace repeatedly
+ * until there are no more possible replacements or timeToLive < 0
+ * @param timeToLive
+ * if less than 0 then there is a circular reference and endless
+ * loop
+ * @return the text with any replacements processed, {@code null} if
+ * null String input
+ * @throws IllegalStateException
+ * if the search is repeating and there is an endless loop due
+ * to outputs of one being inputs to another
+ * @throws IllegalArgumentException
+ * if the lengths of the arrays are not the same (null is ok,
+ * and/or size 0)
+ * @since 2.4
+ */
+ private static String replaceEach(
+ String text, String[] searchList, String[] replacementList, boolean repeat, int timeToLive) {
+
+ // mchyzer Performance note: This creates very few new objects (one major goal)
+ // let me know if there are performance requests, we can create a harness to measure
+
+ if (text == null || text.length() == 0 || searchList == null ||
+ searchList.length == 0 || replacementList == null || replacementList.length == 0) {
+ return text;
+ }
+
+ // if recursing, this shouldn't be less than 0
+ if (timeToLive < 0) {
+ throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
+ "output of one loop is the input of another");
+ }
+
+ int searchLength = searchList.length;
+ int replacementLength = replacementList.length;
+
+ // make sure lengths are ok, these need to be equal
+ if (searchLength != replacementLength) {
+ throw new IllegalArgumentException("Search and Replace array lengths don't match: "
+ + searchLength
+ + " vs "
+ + replacementLength);
+ }
+
+ // keep track of which still have matches
+ boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
+
+ // index on index that the match was found
+ int textIndex = -1;
+ int replaceIndex = -1;
+ int tempIndex = -1;
+
+ // index of replace array that will replace the search string found
+ // NOTE: logic duplicated below START
+ for (int i = 0; i < searchLength; i++) {
+ if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
+ searchList[i].length() == 0 || replacementList[i] == null) {
+ continue;
+ }
+ tempIndex = text.indexOf(searchList[i]);
+
+ // see if we need to keep searching for this
+ if (tempIndex == -1) {
+ noMoreMatchesForReplIndex[i] = true;
+ } else {
+ if (textIndex == -1 || tempIndex < textIndex) {
+ textIndex = tempIndex;
+ replaceIndex = i;
+ }
+ }
+ }
+ // NOTE: logic mostly below END
+
+ // no search strings found, we are done
+ if (textIndex == -1) {
+ return text;
+ }
+
+ int start = 0;
+
+ // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
+ int increase = 0;
+
+ // count the replacement text elements that are larger than their corresponding text being replaced
+ for (int i = 0; i < searchList.length; i++) {
+ if (searchList[i] == null || replacementList[i] == null) {
+ continue;
+ }
+ int greater = replacementList[i].length() - searchList[i].length();
+ if (greater > 0) {
+ increase += 3 * greater; // assume 3 matches
+ }
+ }
+ // have upper-bound at 20% increase, then let Java take over
+ increase = Math.min(increase, text.length() / 5);
+
+ StringBuilder buf = new StringBuilder(text.length() + increase);
+
+ while (textIndex != -1) {
+
+ for (int i = start; i < textIndex; i++) {
+ buf.append(text.charAt(i));
+ }
+ buf.append(replacementList[replaceIndex]);
+
+ start = textIndex + searchList[replaceIndex].length();
+
+ textIndex = -1;
+ replaceIndex = -1;
+ tempIndex = -1;
+ // find the next earliest match
+ // NOTE: logic mostly duplicated above START
+ for (int i = 0; i < searchLength; i++) {
+ if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
+ searchList[i].length() == 0 || replacementList[i] == null) {
+ continue;
+ }
+ tempIndex = text.indexOf(searchList[i], start);
+
+ // see if we need to keep searching for this
+ if (tempIndex == -1) {
+ noMoreMatchesForReplIndex[i] = true;
+ } else {
+ if (textIndex == -1 || tempIndex < textIndex) {
+ textIndex = tempIndex;
+ replaceIndex = i;
+ }
+ }
+ }
+ // NOTE: logic duplicated above END
+
+ }
+ int textLength = text.length();
+ for (int i = start; i < textLength; i++) {
+ buf.append(text.charAt(i));
+ }
+ String result = buf.toString();
+ if (!repeat) {
+ return result;
+ }
+
+ return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
+ }
+
+ // Replace, character based
+ //-----------------------------------------------------------------------
+ /**
+ *
+ * StringUtils.replaceChars(null, *, *) = null
+ * StringUtils.replaceChars("", *, *) = ""
+ * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
+ * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
+ *
+ *
+ * @param str String to replace characters in, may be null
+ * @param searchChar the character to search for, may be null
+ * @param replaceChar the character to replace, may be null
+ * @return modified String, {@code null} if null string input
+ * @since 2.0
+ */
+ public static String replaceChars(String str, char searchChar, char replaceChar) {
+ if (str == null) {
+ return null;
+ }
+ return str.replace(searchChar, replaceChar);
+ }
+
+ /**
+ *
+ * replaceChars("hello", "ho", "jy") = jelly.
+ * StringUtils.replaceChars(null, *, *) = null
+ * StringUtils.replaceChars("", *, *) = ""
+ * StringUtils.replaceChars("abc", null, *) = "abc"
+ * StringUtils.replaceChars("abc", "", *) = "abc"
+ * StringUtils.replaceChars("abc", "b", null) = "ac"
+ * StringUtils.replaceChars("abc", "b", "") = "ac"
+ * StringUtils.replaceChars("abcba", "bc", "yz") = "ayzya"
+ * StringUtils.replaceChars("abcba", "bc", "y") = "ayya"
+ * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
+ *
+ *
+ * @param str String to replace characters in, may be null
+ * @param searchChars a set of characters to search for, may be null
+ * @param replaceChars a set of characters to replace, may be null
+ * @return modified String, {@code null} if null string input
+ * @since 2.0
+ */
+ public static String replaceChars(String str, String searchChars, String replaceChars) {
+ if (isEmpty(str) || isEmpty(searchChars)) {
+ return str;
+ }
+ if (replaceChars == null) {
+ replaceChars = EMPTY;
+ }
+ boolean modified = false;
+ int replaceCharsLength = replaceChars.length();
+ int strLength = str.length();
+ StringBuilder buf = new StringBuilder(strLength);
+ for (int i = 0; i < strLength; i++) {
+ char ch = str.charAt(i);
+ int index = searchChars.indexOf(ch);
+ if (index >= 0) {
+ modified = true;
+ if (index < replaceCharsLength) {
+ buf.append(replaceChars.charAt(index));
+ }
+ } else {
+ buf.append(ch);
+ }
+ }
+ if (modified) {
+ return buf.toString();
+ }
+ return str;
+ }
+
+ // Overlay
+ //-----------------------------------------------------------------------
+ /**
+ *
+ * StringUtils.overlay(null, *, *, *) = null
+ * StringUtils.overlay("", "abc", 0, 0) = "abc"
+ * StringUtils.overlay("abcdef", null, 2, 4) = "abef"
+ * StringUtils.overlay("abcdef", "", 2, 4) = "abef"
+ * StringUtils.overlay("abcdef", "", 4, 2) = "abef"
+ * StringUtils.overlay("abcdef", "zzzz", 2, 4) = "abzzzzef"
+ * StringUtils.overlay("abcdef", "zzzz", 4, 2) = "abzzzzef"
+ * StringUtils.overlay("abcdef", "zzzz", -1, 4) = "zzzzef"
+ * StringUtils.overlay("abcdef", "zzzz", 2, 8) = "abzzzz"
+ * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
+ * StringUtils.overlay("abcdef", "zzzz", 8, 10) = "abcdefzzzz"
+ *
+ *
+ * @param str the String to do overlaying in, may be null
+ * @param overlay the String to overlay, may be null
+ * @param start the position to start overlaying at
+ * @param end the position to stop overlaying before
+ * @return overlayed String, {@code null} if null String input
+ * @since 2.0
+ */
+ public static String overlay(String str, String overlay, int start, int end) {
+ if (str == null) {
+ return null;
+ }
+ if (overlay == null) {
+ overlay = EMPTY;
+ }
+ int len = str.length();
+ if (start < 0) {
+ start = 0;
+ }
+ if (start > len) {
+ start = len;
+ }
+ if (end < 0) {
+ end = 0;
+ }
+ if (end > len) {
+ end = len;
+ }
+ if (start > end) {
+ int temp = start;
+ start = end;
+ end = temp;
+ }
+ return new StringBuilder(len + start - end + overlay.length() + 1)
+ .append(str.substring(0, start))
+ .append(overlay)
+ .append(str.substring(end))
+ .toString();
+ }
+
+ // Chomping
+ //-----------------------------------------------------------------------
+ /**
+ *
+ * StringUtils.chomp(null) = null
+ * StringUtils.chomp("") = ""
+ * StringUtils.chomp("abc \r") = "abc "
+ * StringUtils.chomp("abc\n") = "abc"
+ * StringUtils.chomp("abc\r\n") = "abc"
+ * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
+ * StringUtils.chomp("abc\n\r") = "abc\n"
+ * StringUtils.chomp("abc\n\rabc") = "abc\n\rabc"
+ * StringUtils.chomp("\r") = ""
+ * StringUtils.chomp("\n") = ""
+ * StringUtils.chomp("\r\n") = ""
+ *
+ *
+ * @param str the String to chomp a newline from, may be null
+ * @return String without newline, {@code null} if null String input
+ */
+ public static String chomp(String str) {
+ if (isEmpty(str)) {
+ return str;
+ }
+
+ if (str.length() == 1) {
+ char ch = str.charAt(0);
+ if (ch == CharUtils.CR || ch == CharUtils.LF) {
+ return EMPTY;
+ }
+ return str;
+ }
+
+ int lastIdx = str.length() - 1;
+ char last = str.charAt(lastIdx);
+
+ if (last == CharUtils.LF) {
+ if (str.charAt(lastIdx - 1) == CharUtils.CR) {
+ lastIdx--;
+ }
+ } else if (last != CharUtils.CR) {
+ lastIdx++;
+ }
+ return str.substring(0, lastIdx);
+ }
+
+ // Chopping
+ //-----------------------------------------------------------------------
+ /**
+ *
+ * StringUtils.chop(null) = null
+ * StringUtils.chop("") = ""
+ * StringUtils.chop("abc \r") = "abc "
+ * StringUtils.chop("abc\n") = "abc"
+ * StringUtils.chop("abc\r\n") = "abc"
+ * StringUtils.chop("abc") = "ab"
+ * StringUtils.chop("abc\nabc") = "abc\nab"
+ * StringUtils.chop("a") = ""
+ * StringUtils.chop("\r") = ""
+ * StringUtils.chop("\n") = ""
+ * StringUtils.chop("\r\n") = ""
+ *
+ *
+ * @param str the String to chop last character from, may be null
+ * @return String without last character, {@code null} if null String input
+ */
+ public static String chop(String str) {
+ if (str == null) {
+ return null;
+ }
+ int strLen = str.length();
+ if (strLen < 2) {
+ return EMPTY;
+ }
+ int lastIdx = strLen - 1;
+ String ret = str.substring(0, lastIdx);
+ char last = str.charAt(lastIdx);
+ if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
+ return ret.substring(0, lastIdx - 1);
+ }
+ return ret;
+ }
+
+ // Conversion
+ //-----------------------------------------------------------------------
+
+ // Padding
+ //-----------------------------------------------------------------------
+ /**
+ *
+ * StringUtils.repeat(null, 2) = null
+ * StringUtils.repeat("", 0) = ""
+ * StringUtils.repeat("", 2) = ""
+ * StringUtils.repeat("a", 3) = "aaa"
+ * StringUtils.repeat("ab", 2) = "abab"
+ * StringUtils.repeat("a", -2) = ""
+ *
+ *
+ * @param str the String to repeat, may be null
+ * @param repeat number of times to repeat str, negative treated as zero
+ * @return a new String consisting of the original String repeated,
+ * {@code null} if null String input
+ */
+ public static String repeat(String str, int repeat) {
+ // Performance tuned for 2.0 (JDK1.4)
+
+ if (str == null) {
+ return null;
+ }
+ if (repeat <= 0) {
+ return EMPTY;
+ }
+ int inputLength = str.length();
+ if (repeat == 1 || inputLength == 0) {
+ return str;
+ }
+ if (inputLength == 1 && repeat <= PAD_LIMIT) {
+ return repeat(str.charAt(0), repeat);
+ }
+
+ int outputLength = inputLength * repeat;
+ switch (inputLength) {
+ case 1 :
+ return repeat(str.charAt(0), repeat);
+ case 2 :
+ char ch0 = str.charAt(0);
+ char ch1 = str.charAt(1);
+ char[] output2 = new char[outputLength];
+ for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
+ output2[i] = ch0;
+ output2[i + 1] = ch1;
+ }
+ return new String(output2);
+ default :
+ StringBuilder buf = new StringBuilder(outputLength);
+ for (int i = 0; i < repeat; i++) {
+ buf.append(str);
+ }
+ return buf.toString();
+ }
+ }
+
+ /**
+ *
+ * StringUtils.repeat(null, null, 2) = null
+ * StringUtils.repeat(null, "x", 2) = null
+ * StringUtils.repeat("", null, 0) = ""
+ * StringUtils.repeat("", "", 2) = ""
+ * StringUtils.repeat("", "x", 3) = "xxx"
+ * StringUtils.repeat("?", ", ", 3) = "?, ?, ?"
+ *
+ *
+ * @param str the String to repeat, may be null
+ * @param separator the String to inject, may be null
+ * @param repeat number of times to repeat str, negative treated as zero
+ * @return a new String consisting of the original String repeated,
+ * {@code null} if null String input
+ * @since 2.5
+ */
+ public static String repeat(String str, String separator, int repeat) {
+ if(str == null || separator == null) {
+ return repeat(str, repeat);
+ } else {
+ // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
+ String result = repeat(str + separator, repeat);
+ return removeEnd(result, separator);
+ }
+ }
+
+ /**
+ *
+ * StringUtils.repeat(0, 'e') = ""
+ * StringUtils.repeat(3, 'e') = "eee"
+ * StringUtils.repeat(-2, 'e') = ""
+ *
+ *
+ *
+ * StringUtils.rightPad(null, *) = null
+ * StringUtils.rightPad("", 3) = " "
+ * StringUtils.rightPad("bat", 3) = "bat"
+ * StringUtils.rightPad("bat", 5) = "bat "
+ * StringUtils.rightPad("bat", 1) = "bat"
+ * StringUtils.rightPad("bat", -1) = "bat"
+ *
+ *
+ * @param str the String to pad out, may be null
+ * @param size the size to pad to
+ * @return right padded String or original String if no padding is necessary,
+ * {@code null} if null String input
+ */
+ public static String rightPad(String str, int size) {
+ return rightPad(str, size, ' ');
+ }
+
+ /**
+ *
+ * StringUtils.rightPad(null, *, *) = null
+ * StringUtils.rightPad("", 3, 'z') = "zzz"
+ * StringUtils.rightPad("bat", 3, 'z') = "bat"
+ * StringUtils.rightPad("bat", 5, 'z') = "batzz"
+ * StringUtils.rightPad("bat", 1, 'z') = "bat"
+ * StringUtils.rightPad("bat", -1, 'z') = "bat"
+ *
+ *
+ * @param str the String to pad out, may be null
+ * @param size the size to pad to
+ * @param padChar the character to pad with
+ * @return right padded String or original String if no padding is necessary,
+ * {@code null} if null String input
+ * @since 2.0
+ */
+ public static String rightPad(String str, int size, char padChar) {
+ if (str == null) {
+ return null;
+ }
+ int pads = size - str.length();
+ if (pads <= 0) {
+ return str; // returns original String when possible
+ }
+ if (pads > PAD_LIMIT) {
+ return rightPad(str, size, String.valueOf(padChar));
+ }
+ return str.concat(repeat(padChar, pads));
+ }
+
+ /**
+ *
+ * StringUtils.rightPad(null, *, *) = null
+ * StringUtils.rightPad("", 3, "z") = "zzz"
+ * StringUtils.rightPad("bat", 3, "yz") = "bat"
+ * StringUtils.rightPad("bat", 5, "yz") = "batyz"
+ * StringUtils.rightPad("bat", 8, "yz") = "batyzyzy"
+ * StringUtils.rightPad("bat", 1, "yz") = "bat"
+ * StringUtils.rightPad("bat", -1, "yz") = "bat"
+ * StringUtils.rightPad("bat", 5, null) = "bat "
+ * StringUtils.rightPad("bat", 5, "") = "bat "
+ *
+ *
+ * @param str the String to pad out, may be null
+ * @param size the size to pad to
+ * @param padStr the String to pad with, null or empty treated as single space
+ * @return right padded String or original String if no padding is necessary,
+ * {@code null} if null String input
+ */
+ public static String rightPad(String str, int size, String padStr) {
+ if (str == null) {
+ return null;
+ }
+ if (isEmpty(padStr)) {
+ padStr = " ";
+ }
+ int padLen = padStr.length();
+ int strLen = str.length();
+ int pads = size - strLen;
+ if (pads <= 0) {
+ return str; // returns original String when possible
+ }
+ if (padLen == 1 && pads <= PAD_LIMIT) {
+ return rightPad(str, size, padStr.charAt(0));
+ }
+
+ if (pads == padLen) {
+ return str.concat(padStr);
+ } else if (pads < padLen) {
+ return str.concat(padStr.substring(0, pads));
+ } else {
+ char[] padding = new char[pads];
+ char[] padChars = padStr.toCharArray();
+ for (int i = 0; i < pads; i++) {
+ padding[i] = padChars[i % padLen];
+ }
+ return str.concat(new String(padding));
+ }
+ }
+
+ /**
+ *
+ * StringUtils.leftPad(null, *) = null
+ * StringUtils.leftPad("", 3) = " "
+ * StringUtils.leftPad("bat", 3) = "bat"
+ * StringUtils.leftPad("bat", 5) = " bat"
+ * StringUtils.leftPad("bat", 1) = "bat"
+ * StringUtils.leftPad("bat", -1) = "bat"
+ *
+ *
+ * @param str the String to pad out, may be null
+ * @param size the size to pad to
+ * @return left padded String or original String if no padding is necessary,
+ * {@code null} if null String input
+ */
+ public static String leftPad(String str, int size) {
+ return leftPad(str, size, ' ');
+ }
+
+ /**
+ *
+ * StringUtils.leftPad(null, *, *) = null
+ * StringUtils.leftPad("", 3, 'z') = "zzz"
+ * StringUtils.leftPad("bat", 3, 'z') = "bat"
+ * StringUtils.leftPad("bat", 5, 'z') = "zzbat"
+ * StringUtils.leftPad("bat", 1, 'z') = "bat"
+ * StringUtils.leftPad("bat", -1, 'z') = "bat"
+ *
+ *
+ * @param str the String to pad out, may be null
+ * @param size the size to pad to
+ * @param padChar the character to pad with
+ * @return left padded String or original String if no padding is necessary,
+ * {@code null} if null String input
+ * @since 2.0
+ */
+ public static String leftPad(String str, int size, char padChar) {
+ if (str == null) {
+ return null;
+ }
+ int pads = size - str.length();
+ if (pads <= 0) {
+ return str; // returns original String when possible
+ }
+ if (pads > PAD_LIMIT) {
+ return leftPad(str, size, String.valueOf(padChar));
+ }
+ return repeat(padChar, pads).concat(str);
+ }
+
+ /**
+ *
+ * StringUtils.leftPad(null, *, *) = null
+ * StringUtils.leftPad("", 3, "z") = "zzz"
+ * StringUtils.leftPad("bat", 3, "yz") = "bat"
+ * StringUtils.leftPad("bat", 5, "yz") = "yzbat"
+ * StringUtils.leftPad("bat", 8, "yz") = "yzyzybat"
+ * StringUtils.leftPad("bat", 1, "yz") = "bat"
+ * StringUtils.leftPad("bat", -1, "yz") = "bat"
+ * StringUtils.leftPad("bat", 5, null) = " bat"
+ * StringUtils.leftPad("bat", 5, "") = " bat"
+ *
+ *
+ * @param str the String to pad out, may be null
+ * @param size the size to pad to
+ * @param padStr the String to pad with, null or empty treated as single space
+ * @return left padded String or original String if no padding is necessary,
+ * {@code null} if null String input
+ */
+ public static String leftPad(String str, int size, String padStr) {
+ if (str == null) {
+ return null;
+ }
+ if (isEmpty(padStr)) {
+ padStr = " ";
+ }
+ int padLen = padStr.length();
+ int strLen = str.length();
+ int pads = size - strLen;
+ if (pads <= 0) {
+ return str; // returns original String when possible
+ }
+ if (padLen == 1 && pads <= PAD_LIMIT) {
+ return leftPad(str, size, padStr.charAt(0));
+ }
+
+ if (pads == padLen) {
+ return padStr.concat(str);
+ } else if (pads < padLen) {
+ return padStr.substring(0, pads).concat(str);
+ } else {
+ char[] padding = new char[pads];
+ char[] padChars = padStr.toCharArray();
+ for (int i = 0; i < pads; i++) {
+ padding[i] = padChars[i % padLen];
+ }
+ return new String(padding).concat(str);
+ }
+ }
+
+ /**
+ * Gets a CharSequence length or {@code 0} if the CharSequence is
+ * {@code null}.
+ *
+ * @param cs
+ * a CharSequence or {@code null}
+ * @return CharSequence length or {@code 0} if the CharSequence is
+ * {@code null}.
+ * @since 2.4
+ * @since 3.0 Changed signature from length(String) to length(CharSequence)
+ */
+ public static int length(CharSequence cs) {
+ return cs == null ? 0 : cs.length();
+ }
+
+ // Centering
+ //-----------------------------------------------------------------------
+ /**
+ *
+ * StringUtils.center(null, *) = null
+ * StringUtils.center("", 4) = " "
+ * StringUtils.center("ab", -1) = "ab"
+ * StringUtils.center("ab", 4) = " ab "
+ * StringUtils.center("abcd", 2) = "abcd"
+ * StringUtils.center("a", 4) = " a "
+ *
+ *
+ * @param str the String to center, may be null
+ * @param size the int size of new String, negative treated as zero
+ * @return centered String, {@code null} if null String input
+ */
+ public static String center(String str, int size) {
+ return center(str, size, ' ');
+ }
+
+ /**
+ *
+ * StringUtils.center(null, *, *) = null
+ * StringUtils.center("", 4, ' ') = " "
+ * StringUtils.center("ab", -1, ' ') = "ab"
+ * StringUtils.center("ab", 4, ' ') = " ab"
+ * StringUtils.center("abcd", 2, ' ') = "abcd"
+ * StringUtils.center("a", 4, ' ') = " a "
+ * StringUtils.center("a", 4, 'y') = "yayy"
+ *
+ *
+ * @param str the String to center, may be null
+ * @param size the int size of new String, negative treated as zero
+ * @param padChar the character to pad the new String with
+ * @return centered String, {@code null} if null String input
+ * @since 2.0
+ */
+ public static String center(String str, int size, char padChar) {
+ if (str == null || size <= 0) {
+ return str;
+ }
+ int strLen = str.length();
+ int pads = size - strLen;
+ if (pads <= 0) {
+ return str;
+ }
+ str = leftPad(str, strLen + pads / 2, padChar);
+ str = rightPad(str, size, padChar);
+ return str;
+ }
+
+ /**
+ *
+ * StringUtils.center(null, *, *) = null
+ * StringUtils.center("", 4, " ") = " "
+ * StringUtils.center("ab", -1, " ") = "ab"
+ * StringUtils.center("ab", 4, " ") = " ab"
+ * StringUtils.center("abcd", 2, " ") = "abcd"
+ * StringUtils.center("a", 4, " ") = " a "
+ * StringUtils.center("a", 4, "yz") = "yayz"
+ * StringUtils.center("abc", 7, null) = " abc "
+ * StringUtils.center("abc", 7, "") = " abc "
+ *
+ *
+ * @param str the String to center, may be null
+ * @param size the int size of new String, negative treated as zero
+ * @param padStr the String to pad the new String with, must not be null or empty
+ * @return centered String, {@code null} if null String input
+ * @throws IllegalArgumentException if padStr is {@code null} or empty
+ */
+ public static String center(String str, int size, String padStr) {
+ if (str == null || size <= 0) {
+ return str;
+ }
+ if (isEmpty(padStr)) {
+ padStr = " ";
+ }
+ int strLen = str.length();
+ int pads = size - strLen;
+ if (pads <= 0) {
+ return str;
+ }
+ str = leftPad(str, strLen + pads / 2, padStr);
+ str = rightPad(str, size, padStr);
+ return str;
+ }
+
+ // Case conversion
+ //-----------------------------------------------------------------------
+ /**
+ *
+ * StringUtils.upperCase(null) = null
+ * StringUtils.upperCase("") = ""
+ * StringUtils.upperCase("aBc") = "ABC"
+ *
+ *
+ *
+ * StringUtils.upperCase(null, Locale.ENGLISH) = null
+ * StringUtils.upperCase("", Locale.ENGLISH) = ""
+ * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
+ *
+ *
+ * @param str the String to upper case, may be null
+ * @param locale the locale that defines the case transformation rules, must not be null
+ * @return the upper cased String, {@code null} if null String input
+ * @since 2.5
+ */
+ public static String upperCase(String str, Locale locale) {
+ if (str == null) {
+ return null;
+ }
+ return str.toUpperCase(locale);
+ }
+
+ /**
+ *
+ * StringUtils.lowerCase(null) = null
+ * StringUtils.lowerCase("") = ""
+ * StringUtils.lowerCase("aBc") = "abc"
+ *
+ *
+ *
+ * StringUtils.lowerCase(null, Locale.ENGLISH) = null
+ * StringUtils.lowerCase("", Locale.ENGLISH) = ""
+ * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
+ *
+ *
+ * @param str the String to lower case, may be null
+ * @param locale the locale that defines the case transformation rules, must not be null
+ * @return the lower cased String, {@code null} if null String input
+ * @since 2.5
+ */
+ public static String lowerCase(String str, Locale locale) {
+ if (str == null) {
+ return null;
+ }
+ return str.toLowerCase(locale);
+ }
+
+ /**
+ *
+ * StringUtils.capitalize(null) = null
+ * StringUtils.capitalize("") = ""
+ * StringUtils.capitalize("cat") = "Cat"
+ * StringUtils.capitalize("cAt") = "CAt"
+ *
+ *
+ * @param str the String to capitalize, may be null
+ * @return the capitalized String, {@code null} if null String input
+ * @see org.apache.commons.lang3.text.WordUtils#capitalize(String)
+ * @see #uncapitalize(String)
+ * @since 2.0
+ */
+ public static String capitalize(String str) {
+ int strLen;
+ if (str == null || (strLen = str.length()) == 0) {
+ return str;
+ }
+ return new StringBuilder(strLen)
+ .append(Character.toTitleCase(str.charAt(0)))
+ .append(str.substring(1))
+ .toString();
+ }
+
+ /**
+ *
+ * StringUtils.uncapitalize(null) = null
+ * StringUtils.uncapitalize("") = ""
+ * StringUtils.uncapitalize("Cat") = "cat"
+ * StringUtils.uncapitalize("CAT") = "cAT"
+ *
+ *
+ * @param str the String to uncapitalize, may be null
+ * @return the uncapitalized String, {@code null} if null String input
+ * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String)
+ * @see #capitalize(String)
+ * @since 2.0
+ */
+ public static String uncapitalize(String str) {
+ int strLen;
+ if (str == null || (strLen = str.length()) == 0) {
+ return str;
+ }
+ return new StringBuilder(strLen)
+ .append(Character.toLowerCase(str.charAt(0)))
+ .append(str.substring(1))
+ .toString();
+ }
+
+ /**
+ *
+ *
+ *
+ *
+ * StringUtils.swapCase(null) = null
+ * StringUtils.swapCase("") = ""
+ * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
+ *
+ *
+ *
+ * StringUtils.countMatches(null, *) = 0
+ * StringUtils.countMatches("", *) = 0
+ * StringUtils.countMatches("abba", null) = 0
+ * StringUtils.countMatches("abba", "") = 0
+ * StringUtils.countMatches("abba", "a") = 2
+ * StringUtils.countMatches("abba", "ab") = 1
+ * StringUtils.countMatches("abba", "xxx") = 0
+ *
+ *
+ * @param str the CharSequence to check, may be null
+ * @param sub the substring to count, may be null
+ * @return the number of occurrences, 0 if either CharSequence is {@code null}
+ * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
+ */
+ public static int countMatches(CharSequence str, CharSequence sub) {
+ if (isEmpty(str) || isEmpty(sub)) {
+ return 0;
+ }
+ int count = 0;
+ int idx = 0;
+ while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
+ count++;
+ idx += sub.length();
+ }
+ return count;
+ }
+
+ // Character Tests
+ //-----------------------------------------------------------------------
+ /**
+ *
+ * StringUtils.isAlpha(null) = false
+ * StringUtils.isAlpha("") = false
+ * StringUtils.isAlpha(" ") = false
+ * StringUtils.isAlpha("abc") = true
+ * StringUtils.isAlpha("ab2c") = false
+ * StringUtils.isAlpha("ab-c") = false
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if only contains letters, and is non-null
+ * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
+ * @since 3.0 Changed "" to return false and not true
+ */
+ public static boolean isAlpha(CharSequence cs) {
+ if (cs == null || cs.length() == 0) {
+ return false;
+ }
+ int sz = cs.length();
+ for (int i = 0; i < sz; i++) {
+ if (Character.isLetter(cs.charAt(i)) == false) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ *
+ * StringUtils.isAlphaSpace(null) = false
+ * StringUtils.isAlphaSpace("") = true
+ * StringUtils.isAlphaSpace(" ") = true
+ * StringUtils.isAlphaSpace("abc") = true
+ * StringUtils.isAlphaSpace("ab c") = true
+ * StringUtils.isAlphaSpace("ab2c") = false
+ * StringUtils.isAlphaSpace("ab-c") = false
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if only contains letters and space,
+ * and is non-null
+ * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
+ */
+ public static boolean isAlphaSpace(CharSequence cs) {
+ if (cs == null) {
+ return false;
+ }
+ int sz = cs.length();
+ for (int i = 0; i < sz; i++) {
+ if ((Character.isLetter(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ *
+ * StringUtils.isAlphanumeric(null) = false
+ * StringUtils.isAlphanumeric("") = false
+ * StringUtils.isAlphanumeric(" ") = false
+ * StringUtils.isAlphanumeric("abc") = true
+ * StringUtils.isAlphanumeric("ab c") = false
+ * StringUtils.isAlphanumeric("ab2c") = true
+ * StringUtils.isAlphanumeric("ab-c") = false
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if only contains letters or digits,
+ * and is non-null
+ * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
+ * @since 3.0 Changed "" to return false and not true
+ */
+ public static boolean isAlphanumeric(CharSequence cs) {
+ if (cs == null || cs.length() == 0) {
+ return false;
+ }
+ int sz = cs.length();
+ for (int i = 0; i < sz; i++) {
+ if (Character.isLetterOrDigit(cs.charAt(i)) == false) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ *
+ * StringUtils.isAlphanumericSpace(null) = false
+ * StringUtils.isAlphanumericSpace("") = true
+ * StringUtils.isAlphanumericSpace(" ") = true
+ * StringUtils.isAlphanumericSpace("abc") = true
+ * StringUtils.isAlphanumericSpace("ab c") = true
+ * StringUtils.isAlphanumericSpace("ab2c") = true
+ * StringUtils.isAlphanumericSpace("ab-c") = false
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if only contains letters, digits or space,
+ * and is non-null
+ * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
+ */
+ public static boolean isAlphanumericSpace(CharSequence cs) {
+ if (cs == null) {
+ return false;
+ }
+ int sz = cs.length();
+ for (int i = 0; i < sz; i++) {
+ if ((Character.isLetterOrDigit(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ *
+ * StringUtils.isAsciiPrintable(null) = false
+ * StringUtils.isAsciiPrintable("") = true
+ * StringUtils.isAsciiPrintable(" ") = true
+ * StringUtils.isAsciiPrintable("Ceki") = true
+ * StringUtils.isAsciiPrintable("ab2c") = true
+ * StringUtils.isAsciiPrintable("!ab-c~") = true
+ * StringUtils.isAsciiPrintable("\u0020") = true
+ * StringUtils.isAsciiPrintable("\u0021") = true
+ * StringUtils.isAsciiPrintable("\u007e") = true
+ * StringUtils.isAsciiPrintable("\u007f") = false
+ * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if every character is in the range
+ * 32 thru 126
+ * @since 2.1
+ * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
+ */
+ public static boolean isAsciiPrintable(CharSequence cs) {
+ if (cs == null) {
+ return false;
+ }
+ int sz = cs.length();
+ for (int i = 0; i < sz; i++) {
+ if (CharUtils.isAsciiPrintable(cs.charAt(i)) == false) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ *
+ * StringUtils.isNumeric(null) = false
+ * StringUtils.isNumeric("") = false
+ * StringUtils.isNumeric(" ") = false
+ * StringUtils.isNumeric("123") = true
+ * StringUtils.isNumeric("12 3") = false
+ * StringUtils.isNumeric("ab2c") = false
+ * StringUtils.isNumeric("12-3") = false
+ * StringUtils.isNumeric("12.3") = false
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if only contains digits, and is non-null
+ * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
+ * @since 3.0 Changed "" to return false and not true
+ */
+ public static boolean isNumeric(CharSequence cs) {
+ if (cs == null || cs.length() == 0) {
+ return false;
+ }
+ int sz = cs.length();
+ for (int i = 0; i < sz; i++) {
+ if (Character.isDigit(cs.charAt(i)) == false) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ *
+ * StringUtils.isNumericSpace(null) = false
+ * StringUtils.isNumericSpace("") = true
+ * StringUtils.isNumericSpace(" ") = true
+ * StringUtils.isNumericSpace("123") = true
+ * StringUtils.isNumericSpace("12 3") = true
+ * StringUtils.isNumericSpace("ab2c") = false
+ * StringUtils.isNumericSpace("12-3") = false
+ * StringUtils.isNumericSpace("12.3") = false
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if only contains digits or space,
+ * and is non-null
+ * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
+ */
+ public static boolean isNumericSpace(CharSequence cs) {
+ if (cs == null) {
+ return false;
+ }
+ int sz = cs.length();
+ for (int i = 0; i < sz; i++) {
+ if ((Character.isDigit(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ *
+ * StringUtils.isWhitespace(null) = false
+ * StringUtils.isWhitespace("") = true
+ * StringUtils.isWhitespace(" ") = true
+ * StringUtils.isWhitespace("abc") = false
+ * StringUtils.isWhitespace("ab2c") = false
+ * StringUtils.isWhitespace("ab-c") = false
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if only contains whitespace, and is non-null
+ * @since 2.0
+ * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
+ */
+ public static boolean isWhitespace(CharSequence cs) {
+ if (cs == null) {
+ return false;
+ }
+ int sz = cs.length();
+ for (int i = 0; i < sz; i++) {
+ if ((Character.isWhitespace(cs.charAt(i)) == false)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ *
+ * StringUtils.isAllLowerCase(null) = false
+ * StringUtils.isAllLowerCase("") = false
+ * StringUtils.isAllLowerCase(" ") = false
+ * StringUtils.isAllLowerCase("abc") = true
+ * StringUtils.isAllLowerCase("abC") = false
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if only contains lowercase characters, and is non-null
+ * @since 2.5
+ * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
+ */
+ public static boolean isAllLowerCase(CharSequence cs) {
+ if (cs == null || isEmpty(cs)) {
+ return false;
+ }
+ int sz = cs.length();
+ for (int i = 0; i < sz; i++) {
+ if (Character.isLowerCase(cs.charAt(i)) == false) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ *
+ * StringUtils.isAllUpperCase(null) = false
+ * StringUtils.isAllUpperCase("") = false
+ * StringUtils.isAllUpperCase(" ") = false
+ * StringUtils.isAllUpperCase("ABC") = true
+ * StringUtils.isAllUpperCase("aBC") = false
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if only contains uppercase characters, and is non-null
+ * @since 2.5
+ * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
+ */
+ public static boolean isAllUpperCase(CharSequence cs) {
+ if (cs == null || isEmpty(cs)) {
+ return false;
+ }
+ int sz = cs.length();
+ for (int i = 0; i < sz; i++) {
+ if (Character.isUpperCase(cs.charAt(i)) == false) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Defaults
+ //-----------------------------------------------------------------------
+ /**
+ *
+ * StringUtils.defaultString(null) = ""
+ * StringUtils.defaultString("") = ""
+ * StringUtils.defaultString("bat") = "bat"
+ *
+ *
+ * @see ObjectUtils#toString(Object)
+ * @see String#valueOf(Object)
+ * @param str the String to check, may be null
+ * @return the passed in String, or the empty String if it
+ * was {@code null}
+ */
+ public static String defaultString(String str) {
+ return str == null ? EMPTY : str;
+ }
+
+ /**
+ *
+ * StringUtils.defaultString(null, "NULL") = "NULL"
+ * StringUtils.defaultString("", "NULL") = ""
+ * StringUtils.defaultString("bat", "NULL") = "bat"
+ *
+ *
+ * @see ObjectUtils#toString(Object,String)
+ * @see String#valueOf(Object)
+ * @param str the String to check, may be null
+ * @param defaultStr the default String to return
+ * if the input is {@code null}, may be null
+ * @return the passed in String, or the default if it was {@code null}
+ */
+ public static String defaultString(String str, String defaultStr) {
+ return str == null ? defaultStr : str;
+ }
+
+ /**
+ *
+ * StringUtils.defaultIfBlank(null, "NULL") = "NULL"
+ * StringUtils.defaultIfBlank("", "NULL") = "NULL"
+ * StringUtils.defaultIfBlank(" ", "NULL") = "NULL"
+ * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
+ * StringUtils.defaultIfBlank("", null) = null
+ *
+ * @param
+ * StringUtils.defaultIfEmpty(null, "NULL") = "NULL"
+ * StringUtils.defaultIfEmpty("", "NULL") = "NULL"
+ * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
+ * StringUtils.defaultIfEmpty("", null) = null
+ *
+ * @param
+ * StringUtils.reverse(null) = null
+ * StringUtils.reverse("") = ""
+ * StringUtils.reverse("bat") = "tab"
+ *
+ *
+ * @param str the String to reverse, may be null
+ * @return the reversed String, {@code null} if null String input
+ */
+ public static String reverse(String str) {
+ if (str == null) {
+ return null;
+ }
+ return new StringBuilder(str).reverse().toString();
+ }
+
+ /**
+ *
+ * StringUtils.reverseDelimited(null, *) = null
+ * StringUtils.reverseDelimited("", *) = ""
+ * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
+ * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
+ *
+ *
+ * @param str the String to reverse, may be null
+ * @param separatorChar the separator character to use
+ * @return the reversed String, {@code null} if null String input
+ * @since 2.0
+ */
+ public static String reverseDelimited(String str, char separatorChar) {
+ if (str == null) {
+ return null;
+ }
+ // could implement manually, but simple way is to reuse other,
+ // probably slower, methods.
+ String[] strs = split(str, separatorChar);
+ ArrayUtils.reverse(strs);
+ return join(strs, separatorChar);
+ }
+
+ // Abbreviating
+ //-----------------------------------------------------------------------
+ /**
+ *
+ *
+ *
+ * StringUtils.abbreviate(null, *) = null
+ * StringUtils.abbreviate("", 4) = ""
+ * StringUtils.abbreviate("abcdefg", 6) = "abc..."
+ * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
+ * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
+ * StringUtils.abbreviate("abcdefg", 4) = "a..."
+ * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
+ *
+ *
+ * @param str the String to check, may be null
+ * @param maxWidth maximum length of result String, must be at least 4
+ * @return abbreviated String, {@code null} if null String input
+ * @throws IllegalArgumentException if the width is too small
+ * @since 2.0
+ */
+ public static String abbreviate(String str, int maxWidth) {
+ return abbreviate(str, 0, maxWidth);
+ }
+
+ /**
+ * Abbreviates a String using ellipses. This will turn + * "Now is the time for all good men" into "...is the time for..."
+ * + *Works like {@code abbreviate(String, int)}, but allows you to specify + * a "left edge" offset. Note that this left edge is not necessarily going to + * be the leftmost character in the result, or the first character following the + * ellipses, but it will appear somewhere in the result. + * + *
In no case will it return a String of length greater than + * {@code maxWidth}.
+ * + *
+ * StringUtils.abbreviate(null, *, *) = null
+ * StringUtils.abbreviate("", 0, 4) = ""
+ * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
+ * StringUtils.abbreviate("abcdefghijklmno", 0, 10) = "abcdefg..."
+ * StringUtils.abbreviate("abcdefghijklmno", 1, 10) = "abcdefg..."
+ * StringUtils.abbreviate("abcdefghijklmno", 4, 10) = "abcdefg..."
+ * StringUtils.abbreviate("abcdefghijklmno", 5, 10) = "...fghi..."
+ * StringUtils.abbreviate("abcdefghijklmno", 6, 10) = "...ghij..."
+ * StringUtils.abbreviate("abcdefghijklmno", 8, 10) = "...ijklmno"
+ * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
+ * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
+ * StringUtils.abbreviate("abcdefghij", 0, 3) = IllegalArgumentException
+ * StringUtils.abbreviate("abcdefghij", 5, 6) = IllegalArgumentException
+ *
+ *
+ * @param str the String to check, may be null
+ * @param offset left edge of source String
+ * @param maxWidth maximum length of result String, must be at least 4
+ * @return abbreviated String, {@code null} if null String input
+ * @throws IllegalArgumentException if the width is too small
+ * @since 2.0
+ */
+ public static String abbreviate(String str, int offset, int maxWidth) {
+ if (str == null) {
+ return null;
+ }
+ if (maxWidth < 4) {
+ throw new IllegalArgumentException("Minimum abbreviation width is 4");
+ }
+ if (str.length() <= maxWidth) {
+ return str;
+ }
+ if (offset > str.length()) {
+ offset = str.length();
+ }
+ if ((str.length() - offset) < (maxWidth - 3)) {
+ offset = str.length() - (maxWidth - 3);
+ }
+ final String abrevMarker = "...";
+ if (offset <= 4) {
+ return str.substring(0, maxWidth - 3) + abrevMarker;
+ }
+ if (maxWidth < 7) {
+ throw new IllegalArgumentException("Minimum abbreviation width with offset is 7");
+ }
+ if ((offset + (maxWidth - 3)) < str.length()) {
+ return abrevMarker + abbreviate(str.substring(offset), maxWidth - 3);
+ }
+ return abrevMarker + str.substring(str.length() - (maxWidth - 3));
+ }
+
+ /**
+ * Abbreviates a String to the length passed, replacing the middle characters with the supplied + * replacement String.
+ * + *This abbreviation only occurs if the following criteria is met: + *
+ * StringUtils.abbreviateMiddle(null, null, 0) = null
+ * StringUtils.abbreviateMiddle("abc", null, 0) = "abc"
+ * StringUtils.abbreviateMiddle("abc", ".", 0) = "abc"
+ * StringUtils.abbreviateMiddle("abc", ".", 3) = "abc"
+ * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f"
+ *
+ *
+ * @param str the String to abbreviate, may be null
+ * @param middle the String to replace the middle characters with, may be null
+ * @param length the length to abbreviate {@code str} to.
+ * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
+ * @since 2.5
+ */
+ public static String abbreviateMiddle(String str, String middle, int length) {
+ if (isEmpty(str) || isEmpty(middle)) {
+ return str;
+ }
+
+ if (length >= str.length() || length < (middle.length()+2)) {
+ return str;
+ }
+
+ int targetSting = length-middle.length();
+ int startOffset = targetSting/2+targetSting%2;
+ int endOffset = str.length()-targetSting/2;
+
+ StringBuilder builder = new StringBuilder(length);
+ builder.append(str.substring(0,startOffset));
+ builder.append(middle);
+ builder.append(str.substring(endOffset));
+
+ return builder.toString();
+ }
+
+ // Difference
+ //-----------------------------------------------------------------------
+ /**
+ * Compares two Strings, and returns the portion where they differ. + * (More precisely, return the remainder of the second String, + * starting from where it's different from the first.)
+ * + *For example, + * {@code difference("i am a machine", "i am a robot") -> "robot"}.
+ * + *
+ * StringUtils.difference(null, null) = null
+ * StringUtils.difference("", "") = ""
+ * StringUtils.difference("", "abc") = "abc"
+ * StringUtils.difference("abc", "") = ""
+ * StringUtils.difference("abc", "abc") = ""
+ * StringUtils.difference("ab", "abxyz") = "xyz"
+ * StringUtils.difference("abcde", "abxyz") = "xyz"
+ * StringUtils.difference("abcde", "xyz") = "xyz"
+ *
+ *
+ * @param str1 the first String, may be null
+ * @param str2 the second String, may be null
+ * @return the portion of str2 where it differs from str1; returns the
+ * empty String if they are equal
+ * @since 2.0
+ */
+ public static String difference(String str1, String str2) {
+ if (str1 == null) {
+ return str2;
+ }
+ if (str2 == null) {
+ return str1;
+ }
+ int at = indexOfDifference(str1, str2);
+ if (at == INDEX_NOT_FOUND) {
+ return EMPTY;
+ }
+ return str2.substring(at);
+ }
+
+ /**
+ * Compares two CharSequences, and returns the index at which the + * CharSequences begin to differ.
+ * + *For example, + * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}
+ * + *
+ * StringUtils.indexOfDifference(null, null) = -1
+ * StringUtils.indexOfDifference("", "") = -1
+ * StringUtils.indexOfDifference("", "abc") = 0
+ * StringUtils.indexOfDifference("abc", "") = 0
+ * StringUtils.indexOfDifference("abc", "abc") = -1
+ * StringUtils.indexOfDifference("ab", "abxyz") = 2
+ * StringUtils.indexOfDifference("abcde", "abxyz") = 2
+ * StringUtils.indexOfDifference("abcde", "xyz") = 0
+ *
+ *
+ * @param cs1 the first CharSequence, may be null
+ * @param cs2 the second CharSequence, may be null
+ * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
+ * @since 2.0
+ * @since 3.0 Changed signature from indexOfDifference(String, String) to
+ * indexOfDifference(CharSequence, CharSequence)
+ */
+ public static int indexOfDifference(CharSequence cs1, CharSequence cs2) {
+ if (cs1 == cs2) {
+ return INDEX_NOT_FOUND;
+ }
+ if (cs1 == null || cs2 == null) {
+ return 0;
+ }
+ int i;
+ for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
+ if (cs1.charAt(i) != cs2.charAt(i)) {
+ break;
+ }
+ }
+ if (i < cs2.length() || i < cs1.length()) {
+ return i;
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Compares all CharSequences in an array and returns the index at which the + * CharSequences begin to differ.
+ * + *For example,
+ * indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7
+ * StringUtils.indexOfDifference(null) = -1
+ * StringUtils.indexOfDifference(new String[] {}) = -1
+ * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
+ * StringUtils.indexOfDifference(new String[] {null, null}) = -1
+ * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
+ * StringUtils.indexOfDifference(new String[] {"", null}) = 0
+ * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
+ * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
+ * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
+ * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
+ * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
+ * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
+ * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
+ * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
+ * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
+ * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
+ * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
+ *
+ *
+ * @param css array of CharSequences, entries may be null
+ * @return the index where the strings begin to differ; -1 if they are all equal
+ * @since 2.4
+ * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
+ */
+ public static int indexOfDifference(CharSequence... css) {
+ if (css == null || css.length <= 1) {
+ return INDEX_NOT_FOUND;
+ }
+ boolean anyStringNull = false;
+ boolean allStringsNull = true;
+ int arrayLen = css.length;
+ int shortestStrLen = Integer.MAX_VALUE;
+ int longestStrLen = 0;
+
+ // find the min and max string lengths; this avoids checking to make
+ // sure we are not exceeding the length of the string each time through
+ // the bottom loop.
+ for (int i = 0; i < arrayLen; i++) {
+ if (css[i] == null) {
+ anyStringNull = true;
+ shortestStrLen = 0;
+ } else {
+ allStringsNull = false;
+ shortestStrLen = Math.min(css[i].length(), shortestStrLen);
+ longestStrLen = Math.max(css[i].length(), longestStrLen);
+ }
+ }
+
+ // handle lists containing all nulls or all empty strings
+ if (allStringsNull || (longestStrLen == 0 && !anyStringNull)) {
+ return INDEX_NOT_FOUND;
+ }
+
+ // handle lists containing some nulls or some empty strings
+ if (shortestStrLen == 0) {
+ return 0;
+ }
+
+ // find the position with the first difference across all strings
+ int firstDiff = -1;
+ for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
+ char comparisonChar = css[0].charAt(stringPos);
+ for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
+ if (css[arrayPos].charAt(stringPos) != comparisonChar) {
+ firstDiff = stringPos;
+ break;
+ }
+ }
+ if (firstDiff != -1) {
+ break;
+ }
+ }
+
+ if (firstDiff == -1 && shortestStrLen != longestStrLen) {
+ // we compared all of the characters up to the length of the
+ // shortest string and didn't find a match, but the string lengths
+ // vary, so return the length of the shortest string.
+ return shortestStrLen;
+ }
+ return firstDiff;
+ }
+
+ /**
+ * Compares all Strings in an array and returns the initial sequence of + * characters that is common to all of them.
+ * + *For example,
+ * getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -> "i am a "
+ * StringUtils.getCommonPrefix(null) = ""
+ * StringUtils.getCommonPrefix(new String[] {}) = ""
+ * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
+ * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
+ * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
+ * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
+ * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
+ * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
+ * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
+ * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
+ * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
+ * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
+ * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
+ * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
+ * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
+ * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
+ * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
+ *
+ *
+ * @param strs array of String objects, entries may be null
+ * @return the initial sequence of characters that are common to all Strings
+ * in the array; empty String if the array is null, the elements are all null
+ * or if there is no common prefix.
+ * @since 2.4
+ */
+ public static String getCommonPrefix(String... strs) {
+ if (strs == null || strs.length == 0) {
+ return EMPTY;
+ }
+ int smallestIndexOfDiff = indexOfDifference(strs);
+ if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
+ // all strings were identical
+ if (strs[0] == null) {
+ return EMPTY;
+ }
+ return strs[0];
+ } else if (smallestIndexOfDiff == 0) {
+ // there were no common initial characters
+ return EMPTY;
+ } else {
+ // we found a common initial character sequence
+ return strs[0].substring(0, smallestIndexOfDiff);
+ }
+ }
+
+ // Misc
+ //-----------------------------------------------------------------------
+ /**
+ * Find the Levenshtein distance between two Strings.
+ * + *This is the number of changes needed to change one String into + * another, where each change is a single character modification (deletion, + * insertion or substitution).
+ * + *The previous implementation of the Levenshtein distance algorithm + * was from http://www.merriampark.com/ld.htm
+ * + *Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError
+ * which can occur when my Java implementation is used with very large strings.
+ * This implementation of the Levenshtein distance algorithm
+ * is from http://www.merriampark.com/ldjava.htm
+ * StringUtils.getLevenshteinDistance(null, *) = IllegalArgumentException
+ * StringUtils.getLevenshteinDistance(*, null) = IllegalArgumentException
+ * StringUtils.getLevenshteinDistance("","") = 0
+ * StringUtils.getLevenshteinDistance("","a") = 1
+ * StringUtils.getLevenshteinDistance("aaapppp", "") = 7
+ * StringUtils.getLevenshteinDistance("frog", "fog") = 1
+ * StringUtils.getLevenshteinDistance("fly", "ant") = 3
+ * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
+ * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
+ * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
+ * StringUtils.getLevenshteinDistance("hello", "hallo") = 1
+ *
+ *
+ * @param s the first String, must not be null
+ * @param t the second String, must not be null
+ * @return result distance
+ * @throws IllegalArgumentException if either String input {@code null}
+ * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
+ * getLevenshteinDistance(CharSequence, CharSequence)
+ */
+ public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
+ if (s == null || t == null) {
+ throw new IllegalArgumentException("Strings must not be null");
+ }
+
+ /*
+ The difference between this impl. and the previous is that, rather
+ than creating and retaining a matrix of size s.length() + 1 by t.length() + 1,
+ we maintain two single-dimensional arrays of length s.length() + 1. The first, d,
+ is the 'current working' distance array that maintains the newest distance cost
+ counts as we iterate through the characters of String s. Each time we increment
+ the index of String t we are comparing, d is copied to p, the second int[]. Doing so
+ allows us to retain the previous cost counts as required by the algorithm (taking
+ the minimum of the cost count to the left, up one, and diagonally up and to the left
+ of the current cost count being calculated). (Note that the arrays aren't really
+ copied anymore, just switched...this is clearly much better than cloning an array
+ or doing a System.arraycopy() each time through the outer loop.)
+
+ Effectively, the difference between the two implementations is this one does not
+ cause an out of memory condition when calculating the LD over two very large strings.
+ */
+
+ int n = s.length(); // length of s
+ int m = t.length(); // length of t
+
+ if (n == 0) {
+ return m;
+ } else if (m == 0) {
+ return n;
+ }
+
+ if (n > m) {
+ // swap the input strings to consume less memory
+ CharSequence tmp = s;
+ s = t;
+ t = tmp;
+ n = m;
+ m = t.length();
+ }
+
+ int p[] = new int[n + 1]; //'previous' cost array, horizontally
+ int d[] = new int[n + 1]; // cost array, horizontally
+ int _d[]; //placeholder to assist in swapping p and d
+
+ // indexes into strings s and t
+ int i; // iterates through s
+ int j; // iterates through t
+
+ char t_j; // jth character of t
+
+ int cost; // cost
+
+ for (i = 0; i <= n; i++) {
+ p[i] = i;
+ }
+
+ for (j = 1; j <= m; j++) {
+ t_j = t.charAt(j - 1);
+ d[0] = j;
+
+ for (i = 1; i <= n; i++) {
+ cost = s.charAt(i - 1) == t_j ? 0 : 1;
+ // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
+ d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
+ }
+
+ // copy current distance counts to 'previous row' distance counts
+ _d = p;
+ p = d;
+ d = _d;
+ }
+
+ // our last action in the above loop was to switch d and p, so p now
+ // actually has the most recent cost counts
+ return p[n];
+ }
+
+ /**
+ * Find the Levenshtein distance between two Strings if it's less than or equal to a given + * threshold.
+ * + *This is the number of changes needed to change one String into + * another, where each change is a single character modification (deletion, + * insertion or substitution).
+ * + *This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield + * and Chas Emerick's implementation of the Levenshtein distance algorithm from + * http://www.merriampark.com/ld.htm
+ * + *
+ * StringUtils.getLevenshteinDistance(null, *, *) = IllegalArgumentException
+ * StringUtils.getLevenshteinDistance(*, null, *) = IllegalArgumentException
+ * StringUtils.getLevenshteinDistance(*, *, -1) = IllegalArgumentException
+ * StringUtils.getLevenshteinDistance("","", 0) = 0
+ * StringUtils.getLevenshteinDistance("aaapppp", "", 8) = 7
+ * StringUtils.getLevenshteinDistance("aaapppp", "", 7) = 7
+ * StringUtils.getLevenshteinDistance("aaapppp", "", 6)) = -1
+ * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
+ * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
+ * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
+ * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
+ *
+ *
+ * @param s the first String, must not be null
+ * @param t the second String, must not be null
+ * @param threshold the target threshold, must not be negative
+ * @return result distance, or {@code -1} if the distance would be greater than the threshold
+ * @throws IllegalArgumentException if either String input {@code null} or negative threshold
+ */
+ public static int getLevenshteinDistance(CharSequence s, CharSequence t, int threshold) {
+ if (s == null || t == null) {
+ throw new IllegalArgumentException("Strings must not be null");
+ }
+ if (threshold < 0) {
+ throw new IllegalArgumentException("Threshold must not be negative");
+ }
+
+ /*
+ This implementation only computes the distance if it's less than or equal to the
+ threshold value, returning -1 if it's greater. The advantage is performance: unbounded
+ distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
+ computing a diagonal stripe of width 2k + 1 of the cost table.
+ It is also possible to use this to compute the unbounded Levenshtein distance by starting
+ the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
+ d is the distance.
+
+ One subtlety comes from needing to ignore entries on the border of our stripe
+ eg.
+ p[] = |#|#|#|*
+ d[] = *|#|#|#|
+ We must ignore the entry to the left of the leftmost member
+ We must ignore the entry above the rightmost member
+
+ Another subtlety comes from our stripe running off the matrix if the strings aren't
+ of the same size. Since string s is always swapped to be the shorter of the two,
+ the stripe will always run off to the upper right instead of the lower left of the matrix.
+
+ As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
+ In this case we're going to walk a stripe of length 3. The matrix would look like so:
+
+ 1 2 3 4 5
+ 1 |#|#| | | |
+ 2 |#|#|#| | |
+ 3 | |#|#|#| |
+ 4 | | |#|#|#|
+ 5 | | | |#|#|
+ 6 | | | | |#|
+ 7 | | | | | |
+
+ Note how the stripe leads off the table as there is no possible way to turn a string of length 5
+ into one of length 7 in edit distance of 1.
+
+ Additionally, this implementation decreases memory usage by using two
+ single-dimensional arrays and swapping them back and forth instead of allocating
+ an entire n by m matrix. This requires a few minor changes, such as immediately returning
+ when it's detected that the stripe has run off the matrix and initially filling the arrays with
+ large values so that entries we don't compute are ignored.
+
+ See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
+ */
+
+ int n = s.length(); // length of s
+ int m = t.length(); // length of t
+
+ // if one string is empty, the edit distance is necessarily the length of the other
+ if (n == 0) {
+ return m <= threshold ? m : -1;
+ } else if (m == 0) {
+ return n <= threshold ? n : -1;
+ }
+
+ if (n > m) {
+ // swap the two strings to consume less memory
+ CharSequence tmp = s;
+ s = t;
+ t = tmp;
+ n = m;
+ m = t.length();
+ }
+
+ int p[] = new int[n + 1]; // 'previous' cost array, horizontally
+ int d[] = new int[n + 1]; // cost array, horizontally
+ int _d[]; // placeholder to assist in swapping p and d
+
+ // fill in starting table values
+ int boundary = Math.min(n, threshold) + 1;
+ for (int i = 0; i < boundary; i++) {
+ p[i] = i;
+ }
+ // these fills ensure that the value above the rightmost entry of our
+ // stripe will be ignored in following loop iterations
+ Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
+ Arrays.fill(d, Integer.MAX_VALUE);
+
+ // iterates through t
+ for (int j = 1; j <= m; j++) {
+ char t_j = t.charAt(j - 1); // jth character of t
+ d[0] = j;
+
+ // compute stripe indices, constrain to array size
+ int min = Math.max(1, j - threshold);
+ int max = Math.min(n, j + threshold);
+
+ // the stripe may lead off of the table if s and t are of different sizes
+ if (min > max) {
+ return -1;
+ }
+
+ // ignore entry left of leftmost
+ if (min > 1) {
+ d[min - 1] = Integer.MAX_VALUE;
+ }
+
+ // iterates through [min, max] in s
+ for (int i = min; i <= max; i++) {
+ if (s.charAt(i - 1) == t_j) {
+ // diagonally left and up
+ d[i] = p[i - 1];
+ } else {
+ // 1 + minimum of cell to the left, to the top, diagonally left and up
+ d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
+ }
+ }
+
+ // copy current distance counts to 'previous row' distance counts
+ _d = p;
+ p = d;
+ d = _d;
+ }
+
+ // if p[n] is greater than the threshold, there's no guarantee on it being the correct
+ // distance
+ if (p[n] <= threshold) {
+ return p[n];
+ } else {
+ return -1;
+ }
+ }
+
+ // startsWith
+ //-----------------------------------------------------------------------
+
+ /**
+ * Check if a CharSequence starts with a specified prefix.
+ * + *{@code null}s are handled without exceptions. Two {@code null} + * references are considered to be equal. The comparison is case sensitive.
+ * + *
+ * StringUtils.startsWith(null, null) = true
+ * StringUtils.startsWith(null, "abc") = false
+ * StringUtils.startsWith("abcdef", null) = false
+ * StringUtils.startsWith("abcdef", "abc") = true
+ * StringUtils.startsWith("ABCDEF", "abc") = false
+ *
+ *
+ * @see java.lang.String#startsWith(String)
+ * @param str the CharSequence to check, may be null
+ * @param prefix the prefix to find, may be null
+ * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or
+ * both {@code null}
+ * @since 2.4
+ * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
+ */
+ public static boolean startsWith(CharSequence str, CharSequence prefix) {
+ return startsWith(str, prefix, false);
+ }
+
+ /**
+ * Case insensitive check if a CharSequence starts with a specified prefix.
+ * + *{@code null}s are handled without exceptions. Two {@code null} + * references are considered to be equal. The comparison is case insensitive.
+ * + *
+ * StringUtils.startsWithIgnoreCase(null, null) = true
+ * StringUtils.startsWithIgnoreCase(null, "abc") = false
+ * StringUtils.startsWithIgnoreCase("abcdef", null) = false
+ * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
+ * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
+ *
+ *
+ * @see java.lang.String#startsWith(String)
+ * @param str the CharSequence to check, may be null
+ * @param prefix the prefix to find, may be null
+ * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or
+ * both {@code null}
+ * @since 2.4
+ * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
+ */
+ public static boolean startsWithIgnoreCase(CharSequence str, CharSequence prefix) {
+ return startsWith(str, prefix, true);
+ }
+
+ /**
+ * Check if a CharSequence starts with a specified prefix (optionally case insensitive).
+ * + * @see java.lang.String#startsWith(String) + * @param str the CharSequence to check, may be null + * @param prefix the prefix to find, may be null + * @param ignoreCase indicates whether the compare should ignore case + * (case insensitive) or not. + * @return {@code true} if the CharSequence starts with the prefix or + * both {@code null} + */ + private static boolean startsWith(CharSequence str, CharSequence prefix, boolean ignoreCase) { + if (str == null || prefix == null) { + return (str == null && prefix == null); + } + if (prefix.length() > str.length()) { + return false; + } + return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length()); + } + + /** + *Check if a CharSequence starts with any of an array of specified strings.
+ * + *
+ * StringUtils.startsWithAny(null, null) = false
+ * StringUtils.startsWithAny(null, new String[] {"abc"}) = false
+ * StringUtils.startsWithAny("abcxyz", null) = false
+ * StringUtils.startsWithAny("abcxyz", new String[] {""}) = false
+ * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
+ * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
+ *
+ *
+ * @param string the CharSequence to check, may be null
+ * @param searchStrings the CharSequences to find, may be null or empty
+ * @return {@code true} if the CharSequence starts with any of the the prefixes, case insensitive, or
+ * both {@code null}
+ * @since 2.5
+ * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
+ */
+ public static boolean startsWithAny(CharSequence string, CharSequence... searchStrings) {
+ if (isEmpty(string) || ArrayUtils.isEmpty(searchStrings)) {
+ return false;
+ }
+ for (CharSequence searchString : searchStrings) {
+ if (StringUtils.startsWith(string, searchString)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // endsWith
+ //-----------------------------------------------------------------------
+
+ /**
+ * Check if a CharSequence ends with a specified suffix.
+ * + *{@code null}s are handled without exceptions. Two {@code null} + * references are considered to be equal. The comparison is case sensitive.
+ * + *
+ * StringUtils.endsWith(null, null) = true
+ * StringUtils.endsWith(null, "def") = false
+ * StringUtils.endsWith("abcdef", null) = false
+ * StringUtils.endsWith("abcdef", "def") = true
+ * StringUtils.endsWith("ABCDEF", "def") = false
+ * StringUtils.endsWith("ABCDEF", "cde") = false
+ *
+ *
+ * @see java.lang.String#endsWith(String)
+ * @param str the CharSequence to check, may be null
+ * @param suffix the suffix to find, may be null
+ * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or
+ * both {@code null}
+ * @since 2.4
+ * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
+ */
+ public static boolean endsWith(CharSequence str, CharSequence suffix) {
+ return endsWith(str, suffix, false);
+ }
+
+ /**
+ * Case insensitive check if a CharSequence ends with a specified suffix.
+ * + *{@code null}s are handled without exceptions. Two {@code null} + * references are considered to be equal. The comparison is case insensitive.
+ * + *
+ * StringUtils.endsWithIgnoreCase(null, null) = true
+ * StringUtils.endsWithIgnoreCase(null, "def") = false
+ * StringUtils.endsWithIgnoreCase("abcdef", null) = false
+ * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
+ * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
+ * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
+ *
+ *
+ * @see java.lang.String#endsWith(String)
+ * @param str the CharSequence to check, may be null
+ * @param suffix the suffix to find, may be null
+ * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or
+ * both {@code null}
+ * @since 2.4
+ * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
+ */
+ public static boolean endsWithIgnoreCase(CharSequence str, CharSequence suffix) {
+ return endsWith(str, suffix, true);
+ }
+
+ /**
+ * Check if a CharSequence ends with a specified suffix (optionally case insensitive).
+ * + * @see java.lang.String#endsWith(String) + * @param str the CharSequence to check, may be null + * @param suffix the suffix to find, may be null + * @param ignoreCase indicates whether the compare should ignore case + * (case insensitive) or not. + * @return {@code true} if the CharSequence starts with the prefix or + * both {@code null} + */ + private static boolean endsWith(CharSequence str, CharSequence suffix, boolean ignoreCase) { + if (str == null || suffix == null) { + return str == null && suffix == null; + } + if (suffix.length() > str.length()) { + return false; + } + int strOffset = str.length() - suffix.length(); + return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length()); + } + + /** + *+ * Similar to http://www.w3.org/TR/xpath/#function-normalize + * -space + *
+ *
+ * The function returns the argument string with whitespace normalized by using
+ * {@link #trim(String)} to remove leading and trailing whitespace
+ * and then replacing sequences of whitespace characters by a single space.
+ *
+ * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r] + *
+ * For reference: + *
+ * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
+ * normalize. Additionally {@link #trim(String)} removes control characters (char <= 32) from both
+ * ends of this String.
+ *
Check if a CharSequence ends with any of an array of specified strings.
+ * + *
+ * StringUtils.endsWithAny(null, null) = false
+ * StringUtils.endsWithAny(null, new String[] {"abc"}) = false
+ * StringUtils.endsWithAny("abcxyz", null) = false
+ * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
+ * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
+ * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
+ *
+ *
+ * @param string the CharSequence to check, may be null
+ * @param searchStrings the CharSequences to find, may be null or empty
+ * @return {@code true} if the CharSequence ends with any of the the prefixes, case insensitive, or
+ * both {@code null}
+ * @since 3.0
+ */
+ public static boolean endsWithAny(CharSequence string, CharSequence... searchStrings) {
+ if (isEmpty(string) || ArrayUtils.isEmpty(searchStrings)) {
+ return false;
+ }
+ for (CharSequence searchString : searchStrings) {
+ if (StringUtils.endsWith(string, searchString)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
}
\ No newline at end of file
diff --git a/src/org/apache/commons/lang3/SystemUtils.java b/src/org/apache/commons/lang3/SystemUtils.java
index c6fb73f..a3da7cd 100644
--- a/src/org/apache/commons/lang3/SystemUtils.java
+++ b/src/org/apache/commons/lang3/SystemUtils.java
@@ -1,1419 +1,1419 @@
-/*
- * 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.commons.lang3;
-
-import java.io.File;
-
-/**
- * - * Helpers for {@code java.lang.System}. - *
- *- * If a system property cannot be read due to security restrictions, the corresponding field in this class will be set - * to {@code null} and a message will be written to {@code System.err}. - *
- *- * #ThreadSafe# - *
- * - * @since 1.0 - * @version $Id: SystemUtils.java 1160564 2011-08-23 06:56:42Z bayard $ - */ -public class SystemUtils { - - /** - * The prefix String for all Windows OS. - */ - private static final String OS_NAME_WINDOWS_PREFIX = "Windows"; - - // System property constants - // ----------------------------------------------------------------------- - // These MUST be declared first. Other constants depend on this. - - /** - * The System property key for the user home directory. - */ - private static final String USER_HOME_KEY = "user.home"; - - /** - * The System property key for the user directory. - */ - private static final String USER_DIR_KEY = "user.dir"; - - /** - * The System property key for the Java IO temporary directory. - */ - private static final String JAVA_IO_TMPDIR_KEY = "java.io.tmpdir"; - - /** - * The System property key for the Java home directory. - */ - private static final String JAVA_HOME_KEY = "java.home"; - - /** - *- * The {@code awt.toolkit} System Property. - *
- *- * Holds a class name, on Windows XP this is {@code sun.awt.windows.WToolkit}. - *
- *- * On platforms without a GUI, this value is {@code null}. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since 2.1 - */ - public static final String AWT_TOOLKIT = getSystemProperty("awt.toolkit"); - - /** - *- * The {@code file.encoding} System Property. - *
- *- * File encoding, such as {@code Cp1252}. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since 2.0 - * @since Java 1.2 - */ - public static final String FILE_ENCODING = getSystemProperty("file.encoding"); - - /** - *
- * The {@code file.separator} System Property. File separator ("/" on UNIX).
- *
- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.1 - */ - public static final String FILE_SEPARATOR = getSystemProperty("file.separator"); - - /** - *- * The {@code java.awt.fonts} System Property. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since 2.1 - */ - public static final String JAVA_AWT_FONTS = getSystemProperty("java.awt.fonts"); - - /** - *- * The {@code java.awt.graphicsenv} System Property. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since 2.1 - */ - public static final String JAVA_AWT_GRAPHICSENV = getSystemProperty("java.awt.graphicsenv"); - - /** - *- * The {@code java.awt.headless} System Property. The value of this property is the String {@code "true"} or - * {@code "false"}. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @see #isJavaAwtHeadless() - * @since 2.1 - * @since Java 1.4 - */ - public static final String JAVA_AWT_HEADLESS = getSystemProperty("java.awt.headless"); - - /** - *- * The {@code java.awt.printerjob} System Property. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since 2.1 - */ - public static final String JAVA_AWT_PRINTERJOB = getSystemProperty("java.awt.printerjob"); - - /** - *- * The {@code java.class.path} System Property. Java class path. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.1 - */ - public static final String JAVA_CLASS_PATH = getSystemProperty("java.class.path"); - - /** - *- * The {@code java.class.version} System Property. Java class format version number. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.1 - */ - public static final String JAVA_CLASS_VERSION = getSystemProperty("java.class.version"); - - /** - *- * The {@code java.compiler} System Property. Name of JIT compiler to use. First in JDK version 1.2. Not used in Sun - * JDKs after 1.2. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.2. Not used in Sun versions after 1.2. - */ - public static final String JAVA_COMPILER = getSystemProperty("java.compiler"); - - /** - *- * The {@code java.endorsed.dirs} System Property. Path of endorsed directory or directories. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.4 - */ - public static final String JAVA_ENDORSED_DIRS = getSystemProperty("java.endorsed.dirs"); - - /** - *- * The {@code java.ext.dirs} System Property. Path of extension directory or directories. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.3 - */ - public static final String JAVA_EXT_DIRS = getSystemProperty("java.ext.dirs"); - - /** - *- * The {@code java.home} System Property. Java installation directory. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.1 - */ - public static final String JAVA_HOME = getSystemProperty(JAVA_HOME_KEY); - - /** - *- * The {@code java.io.tmpdir} System Property. Default temp file path. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.2 - */ - public static final String JAVA_IO_TMPDIR = getSystemProperty(JAVA_IO_TMPDIR_KEY); - - /** - *- * The {@code java.library.path} System Property. List of paths to search when loading libraries. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.2 - */ - public static final String JAVA_LIBRARY_PATH = getSystemProperty("java.library.path"); - - /** - *- * The {@code java.runtime.name} System Property. Java Runtime Environment name. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since 2.0 - * @since Java 1.3 - */ - public static final String JAVA_RUNTIME_NAME = getSystemProperty("java.runtime.name"); - - /** - *- * The {@code java.runtime.version} System Property. Java Runtime Environment version. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since 2.0 - * @since Java 1.3 - */ - public static final String JAVA_RUNTIME_VERSION = getSystemProperty("java.runtime.version"); - - /** - *- * The {@code java.specification.name} System Property. Java Runtime Environment specification name. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.2 - */ - public static final String JAVA_SPECIFICATION_NAME = getSystemProperty("java.specification.name"); - - /** - *- * The {@code java.specification.vendor} System Property. Java Runtime Environment specification vendor. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.2 - */ - public static final String JAVA_SPECIFICATION_VENDOR = getSystemProperty("java.specification.vendor"); - - /** - *- * The {@code java.specification.version} System Property. Java Runtime Environment specification version. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.3 - */ - public static final String JAVA_SPECIFICATION_VERSION = getSystemProperty("java.specification.version"); - private static final JavaVersion JAVA_SPECIFICATION_VERSION_AS_ENUM = JavaVersion.get(JAVA_SPECIFICATION_VERSION); - - /** - *- * The {@code java.util.prefs.PreferencesFactory} System Property. A class name. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since 2.1 - * @since Java 1.4 - */ - public static final String JAVA_UTIL_PREFS_PREFERENCES_FACTORY = - getSystemProperty("java.util.prefs.PreferencesFactory"); - - /** - *- * The {@code java.vendor} System Property. Java vendor-specific string. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.1 - */ - public static final String JAVA_VENDOR = getSystemProperty("java.vendor"); - - /** - *- * The {@code java.vendor.url} System Property. Java vendor URL. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.1 - */ - public static final String JAVA_VENDOR_URL = getSystemProperty("java.vendor.url"); - - /** - *- * The {@code java.version} System Property. Java version number. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.1 - */ - public static final String JAVA_VERSION = getSystemProperty("java.version"); - - /** - *- * The {@code java.vm.info} System Property. Java Virtual Machine implementation info. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since 2.0 - * @since Java 1.2 - */ - public static final String JAVA_VM_INFO = getSystemProperty("java.vm.info"); - - /** - *- * The {@code java.vm.name} System Property. Java Virtual Machine implementation name. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.2 - */ - public static final String JAVA_VM_NAME = getSystemProperty("java.vm.name"); - - /** - *- * The {@code java.vm.specification.name} System Property. Java Virtual Machine specification name. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.2 - */ - public static final String JAVA_VM_SPECIFICATION_NAME = getSystemProperty("java.vm.specification.name"); - - /** - *- * The {@code java.vm.specification.vendor} System Property. Java Virtual Machine specification vendor. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.2 - */ - public static final String JAVA_VM_SPECIFICATION_VENDOR = getSystemProperty("java.vm.specification.vendor"); - - /** - *- * The {@code java.vm.specification.version} System Property. Java Virtual Machine specification version. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.2 - */ - public static final String JAVA_VM_SPECIFICATION_VERSION = getSystemProperty("java.vm.specification.version"); - - /** - *- * The {@code java.vm.vendor} System Property. Java Virtual Machine implementation vendor. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.2 - */ - public static final String JAVA_VM_VENDOR = getSystemProperty("java.vm.vendor"); - - /** - *- * The {@code java.vm.version} System Property. Java Virtual Machine implementation version. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.2 - */ - public static final String JAVA_VM_VERSION = getSystemProperty("java.vm.version"); - - /** - *
- * The {@code line.separator} System Property. Line separator ("\n" on UNIX).
- *
- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.1 - */ - public static final String LINE_SEPARATOR = getSystemProperty("line.separator"); - - /** - *- * The {@code os.arch} System Property. Operating system architecture. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.1 - */ - public static final String OS_ARCH = getSystemProperty("os.arch"); - - /** - *- * The {@code os.name} System Property. Operating system name. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.1 - */ - public static final String OS_NAME = getSystemProperty("os.name"); - - /** - *- * The {@code os.version} System Property. Operating system version. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.1 - */ - public static final String OS_VERSION = getSystemProperty("os.version"); - - /** - *
- * The {@code path.separator} System Property. Path separator (":" on UNIX).
- *
- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.1 - */ - public static final String PATH_SEPARATOR = getSystemProperty("path.separator"); - - /** - *- * The {@code user.country} or {@code user.region} System Property. User's country code, such as {@code GB}. First - * in Java version 1.2 as {@code user.region}. Renamed to {@code user.country} in 1.4 - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since 2.0 - * @since Java 1.2 - */ - public static final String USER_COUNTRY = getSystemProperty("user.country") == null ? - getSystemProperty("user.region") : getSystemProperty("user.country"); - - /** - *- * The {@code user.dir} System Property. User's current working directory. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.1 - */ - public static final String USER_DIR = getSystemProperty(USER_DIR_KEY); - - /** - *- * The {@code user.home} System Property. User's home directory. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.1 - */ - public static final String USER_HOME = getSystemProperty(USER_HOME_KEY); - - /** - *- * The {@code user.language} System Property. User's language code, such as {@code "en"}. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since 2.0 - * @since Java 1.2 - */ - public static final String USER_LANGUAGE = getSystemProperty("user.language"); - - /** - *- * The {@code user.name} System Property. User's account name. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since Java 1.1 - */ - public static final String USER_NAME = getSystemProperty("user.name"); - - /** - *- * The {@code user.timezone} System Property. For example: {@code "America/Los_Angeles"}. - *
- *- * Defaults to {@code null} if the runtime does not have security access to read this property or the property does - * not exist. - *
- *- * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or - * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of - * sync with that System property. - *
- * - * @since 2.1 - */ - public static final String USER_TIMEZONE = getSystemProperty("user.timezone"); - - // Java version checks - // ----------------------------------------------------------------------- - // These MUST be declared after those above as they depend on the - // values being set up - - /** - *- * Is {@code true} if this is Java version 1.1 (also 1.1.x versions). - *
- *- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *
- */ - public static final boolean IS_JAVA_1_1 = getJavaVersionMatches("1.1"); - - /** - *- * Is {@code true} if this is Java version 1.2 (also 1.2.x versions). - *
- *- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *
- */ - public static final boolean IS_JAVA_1_2 = getJavaVersionMatches("1.2"); - - /** - *- * Is {@code true} if this is Java version 1.3 (also 1.3.x versions). - *
- *- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *
- */ - public static final boolean IS_JAVA_1_3 = getJavaVersionMatches("1.3"); - - /** - *- * Is {@code true} if this is Java version 1.4 (also 1.4.x versions). - *
- *- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *
- */ - public static final boolean IS_JAVA_1_4 = getJavaVersionMatches("1.4"); - - /** - *- * Is {@code true} if this is Java version 1.5 (also 1.5.x versions). - *
- *- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *
- */ - public static final boolean IS_JAVA_1_5 = getJavaVersionMatches("1.5"); - - /** - *- * Is {@code true} if this is Java version 1.6 (also 1.6.x versions). - *
- *- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *
- */ - public static final boolean IS_JAVA_1_6 = getJavaVersionMatches("1.6"); - - /** - *- * Is {@code true} if this is Java version 1.7 (also 1.7.x versions). - *
- *- * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. - *
- * - * @since 3.0 - */ - public static final boolean IS_JAVA_1_7 = getJavaVersionMatches("1.7"); - - // Operating system checks - // ----------------------------------------------------------------------- - // These MUST be declared after those above as they depend on the - // values being set up - // OS names from http://www.vamphq.com/os.html - // Selected ones included - please advise dev@commons.apache.org - // if you want another added or a mistake corrected - - /** - *- * Is {@code true} if this is AIX. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_AIX = getOSMatchesName("AIX"); - - /** - *- * Is {@code true} if this is HP-UX. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_HP_UX = getOSMatchesName("HP-UX"); - - /** - *- * Is {@code true} if this is Irix. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_IRIX = getOSMatchesName("Irix"); - - /** - *- * Is {@code true} if this is Linux. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_LINUX = getOSMatchesName("Linux") || getOSMatchesName("LINUX"); - - /** - *- * Is {@code true} if this is Mac. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_MAC = getOSMatchesName("Mac"); - - /** - *- * Is {@code true} if this is Mac. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_MAC_OSX = getOSMatchesName("Mac OS X"); - - /** - *- * Is {@code true} if this is FreeBSD. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 3.0.2 - */ - public static final boolean IS_OS_FREE_BSD = getOSMatchesName("FreeBSD"); - - /** - *- * Is {@code true} if this is OpenBSD. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 3.0.2 - */ - public static final boolean IS_OS_OPEN_BSD = getOSMatchesName("OpenBSD"); - - /** - *- * Is {@code true} if this is NetBSD. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 3.0.2 - */ - public static final boolean IS_OS_NET_BSD = getOSMatchesName("NetBSD"); - - /** - *- * Is {@code true} if this is OS/2. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_OS2 = getOSMatchesName("OS/2"); - - /** - *- * Is {@code true} if this is Solaris. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_SOLARIS = getOSMatchesName("Solaris"); - - /** - *- * Is {@code true} if this is SunOS. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_SUN_OS = getOSMatchesName("SunOS"); - - /** - *- * Is {@code true} if this is a UNIX like system, as in any of AIX, HP-UX, Irix, Linux, MacOSX, Solaris or SUN OS. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.1 - */ - public static final boolean IS_OS_UNIX = IS_OS_AIX || IS_OS_HP_UX || IS_OS_IRIX || IS_OS_LINUX || IS_OS_MAC_OSX - || IS_OS_SOLARIS || IS_OS_SUN_OS || IS_OS_FREE_BSD || IS_OS_OPEN_BSD || IS_OS_NET_BSD; - - /** - *- * Is {@code true} if this is Windows. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_WINDOWS = getOSMatchesName(OS_NAME_WINDOWS_PREFIX); - - /** - *- * Is {@code true} if this is Windows 2000. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_WINDOWS_2000 = getOSMatches(OS_NAME_WINDOWS_PREFIX, "5.0"); - - /** - *- * Is {@code true} if this is Windows 95. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_WINDOWS_95 = getOSMatches(OS_NAME_WINDOWS_PREFIX + " 9", "4.0"); - // Java 1.2 running on Windows98 returns 'Windows 95', hence the above - - /** - *- * Is {@code true} if this is Windows 98. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_WINDOWS_98 = getOSMatches(OS_NAME_WINDOWS_PREFIX + " 9", "4.1"); - // Java 1.2 running on Windows98 returns 'Windows 95', hence the above - - /** - *- * Is {@code true} if this is Windows ME. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_WINDOWS_ME = getOSMatches(OS_NAME_WINDOWS_PREFIX, "4.9"); - // Java 1.2 running on WindowsME may return 'Windows 95', hence the above - - /** - *- * Is {@code true} if this is Windows NT. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_WINDOWS_NT = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " NT"); - // Windows 2000 returns 'Windows 2000' but may suffer from same Java1.2 problem - - /** - *- * Is {@code true} if this is Windows XP. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.0 - */ - public static final boolean IS_OS_WINDOWS_XP = getOSMatches(OS_NAME_WINDOWS_PREFIX, "5.1"); - - // ----------------------------------------------------------------------- - /** - *- * Is {@code true} if this is Windows Vista. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 2.4 - */ - public static final boolean IS_OS_WINDOWS_VISTA = getOSMatches(OS_NAME_WINDOWS_PREFIX, "6.0"); - - /** - *- * Is {@code true} if this is Windows 7. - *
- *- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *
- * - * @since 3.0 - */ - public static final boolean IS_OS_WINDOWS_7 = getOSMatches(OS_NAME_WINDOWS_PREFIX, "6.1"); - - /** - *- * Gets the Java home directory as a {@code File}. - *
- * - * @return a directory - * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow - * access to the specified system property. - * @see System#getProperty(String) - * @since 2.1 - */ - public static File getJavaHome() { - return new File(System.getProperty(JAVA_HOME_KEY)); - } - - /** - *- * Gets the Java IO temporary directory as a {@code File}. - *
- * - * @return a directory - * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow - * access to the specified system property. - * @see System#getProperty(String) - * @since 2.1 - */ - public static File getJavaIoTmpDir() { - return new File(System.getProperty(JAVA_IO_TMPDIR_KEY)); - } - - /** - *- * Decides if the Java version matches. - *
- * - * @param versionPrefix the prefix for the java version - * @return true if matches, or false if not or can't determine - */ - private static boolean getJavaVersionMatches(String versionPrefix) { - return isJavaVersionMatch(JAVA_SPECIFICATION_VERSION, versionPrefix); - } - - /** - * Decides if the operating system matches. - * - * @param osNamePrefix the prefix for the os name - * @param osVersionPrefix the prefix for the version - * @return true if matches, or false if not or can't determine - */ - private static boolean getOSMatches(String osNamePrefix, String osVersionPrefix) { - return isOSMatch(OS_NAME, OS_VERSION, osNamePrefix, osVersionPrefix); - } - - /** - * Decides if the operating system matches. - * - * @param osNamePrefix the prefix for the os name - * @return true if matches, or false if not or can't determine - */ - private static boolean getOSMatchesName(String osNamePrefix) { - return isOSNameMatch(OS_NAME, osNamePrefix); - } - - // ----------------------------------------------------------------------- - /** - *- * Gets a System property, defaulting to {@code null} if the property cannot be read. - *
- *- * If a {@code SecurityException} is caught, the return value is {@code null} and a message is written to - * {@code System.err}. - *
- * - * @param property the system property name - * @return the system property value or {@code null} if a security problem occurs - */ - private static String getSystemProperty(String property) { - try { - return System.getProperty(property); - } catch (SecurityException ex) { - // we are not allowed to look at this property - System.err.println("Caught a SecurityException reading the system property '" + property - + "'; the SystemUtils property value will default to null."); - return null; - } - } - - /** - *- * Gets the user directory as a {@code File}. - *
- * - * @return a directory - * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow - * access to the specified system property. - * @see System#getProperty(String) - * @since 2.1 - */ - public static File getUserDir() { - return new File(System.getProperty(USER_DIR_KEY)); - } - - /** - *- * Gets the user home directory as a {@code File}. - *
- * - * @return a directory - * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow - * access to the specified system property. - * @see System#getProperty(String) - * @since 2.1 - */ - public static File getUserHome() { - return new File(System.getProperty(USER_HOME_KEY)); - } - - /** - * Returns whether the {@link #JAVA_AWT_HEADLESS} value is {@code true}. - * - * @return {@code true} if {@code JAVA_AWT_HEADLESS} is {@code "true"}, {@code false} otherwise. - * @see #JAVA_AWT_HEADLESS - * @since 2.1 - * @since Java 1.4 - */ - public static boolean isJavaAwtHeadless() { - return JAVA_AWT_HEADLESS != null ? JAVA_AWT_HEADLESS.equals(Boolean.TRUE.toString()) : false; - } - - /** - *- * Is the Java version at least the requested version. - *
- *- * Example input: - *
- *- * Decides if the Java version matches. - *
- *- * This method is package private instead of private to support unit test invocation. - *
- * - * @param version the actual Java version - * @param versionPrefix the prefix for the expected Java version - * @return true if matches, or false if not or can't determine - */ - static boolean isJavaVersionMatch(String version, String versionPrefix) { - if (version == null) { - return false; - } - return version.startsWith(versionPrefix); - } - - /** - * Decides if the operating system matches. - *- * This method is package private instead of private to support unit test invocation. - *
- * - * @param osName the actual OS name - * @param osVersion the actual OS version - * @param osNamePrefix the prefix for the expected OS name - * @param osVersionPrefix the prefix for the expected OS version - * @return true if matches, or false if not or can't determine - */ - static boolean isOSMatch(String osName, String osVersion, String osNamePrefix, String osVersionPrefix) { - if (osName == null || osVersion == null) { - return false; - } - return osName.startsWith(osNamePrefix) && osVersion.startsWith(osVersionPrefix); - } - - /** - * Decides if the operating system matches. - *- * This method is package private instead of private to support unit test invocation. - *
- * - * @param osName the actual OS name - * @param osNamePrefix the prefix for the expected OS name - * @return true if matches, or false if not or can't determine - */ - static boolean isOSNameMatch(String osName, String osNamePrefix) { - if (osName == null) { - return false; - } - return osName.startsWith(osNamePrefix); - } - - // ----------------------------------------------------------------------- - /** - *- * SystemUtils instances should NOT be constructed in standard programming. Instead, the class should be used as - * {@code SystemUtils.FILE_SEPARATOR}. - *
- *- * This constructor is public to permit tools that require a JavaBean instance to operate. - *
- */ - public SystemUtils() { - super(); - } - -} +/* + * 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.commons.lang3; + +import java.io.File; + +/** + *+ * Helpers for {@code java.lang.System}. + *
+ *+ * If a system property cannot be read due to security restrictions, the corresponding field in this class will be set + * to {@code null} and a message will be written to {@code System.err}. + *
+ *+ * #ThreadSafe# + *
+ * + * @since 1.0 + * @version $Id: SystemUtils.java 1160564 2011-08-23 06:56:42Z bayard $ + */ +public class SystemUtils { + + /** + * The prefix String for all Windows OS. + */ + private static final String OS_NAME_WINDOWS_PREFIX = "Windows"; + + // System property constants + // ----------------------------------------------------------------------- + // These MUST be declared first. Other constants depend on this. + + /** + * The System property key for the user home directory. + */ + private static final String USER_HOME_KEY = "user.home"; + + /** + * The System property key for the user directory. + */ + private static final String USER_DIR_KEY = "user.dir"; + + /** + * The System property key for the Java IO temporary directory. + */ + private static final String JAVA_IO_TMPDIR_KEY = "java.io.tmpdir"; + + /** + * The System property key for the Java home directory. + */ + private static final String JAVA_HOME_KEY = "java.home"; + + /** + *+ * The {@code awt.toolkit} System Property. + *
+ *+ * Holds a class name, on Windows XP this is {@code sun.awt.windows.WToolkit}. + *
+ *+ * On platforms without a GUI, this value is {@code null}. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since 2.1 + */ + public static final String AWT_TOOLKIT = getSystemProperty("awt.toolkit"); + + /** + *+ * The {@code file.encoding} System Property. + *
+ *+ * File encoding, such as {@code Cp1252}. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since 2.0 + * @since Java 1.2 + */ + public static final String FILE_ENCODING = getSystemProperty("file.encoding"); + + /** + *
+ * The {@code file.separator} System Property. File separator ("/" on UNIX).
+ *
+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.1 + */ + public static final String FILE_SEPARATOR = getSystemProperty("file.separator"); + + /** + *+ * The {@code java.awt.fonts} System Property. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since 2.1 + */ + public static final String JAVA_AWT_FONTS = getSystemProperty("java.awt.fonts"); + + /** + *+ * The {@code java.awt.graphicsenv} System Property. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since 2.1 + */ + public static final String JAVA_AWT_GRAPHICSENV = getSystemProperty("java.awt.graphicsenv"); + + /** + *+ * The {@code java.awt.headless} System Property. The value of this property is the String {@code "true"} or + * {@code "false"}. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @see #isJavaAwtHeadless() + * @since 2.1 + * @since Java 1.4 + */ + public static final String JAVA_AWT_HEADLESS = getSystemProperty("java.awt.headless"); + + /** + *+ * The {@code java.awt.printerjob} System Property. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since 2.1 + */ + public static final String JAVA_AWT_PRINTERJOB = getSystemProperty("java.awt.printerjob"); + + /** + *+ * The {@code java.class.path} System Property. Java class path. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.1 + */ + public static final String JAVA_CLASS_PATH = getSystemProperty("java.class.path"); + + /** + *+ * The {@code java.class.version} System Property. Java class format version number. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.1 + */ + public static final String JAVA_CLASS_VERSION = getSystemProperty("java.class.version"); + + /** + *+ * The {@code java.compiler} System Property. Name of JIT compiler to use. First in JDK version 1.2. Not used in Sun + * JDKs after 1.2. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.2. Not used in Sun versions after 1.2. + */ + public static final String JAVA_COMPILER = getSystemProperty("java.compiler"); + + /** + *+ * The {@code java.endorsed.dirs} System Property. Path of endorsed directory or directories. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.4 + */ + public static final String JAVA_ENDORSED_DIRS = getSystemProperty("java.endorsed.dirs"); + + /** + *+ * The {@code java.ext.dirs} System Property. Path of extension directory or directories. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.3 + */ + public static final String JAVA_EXT_DIRS = getSystemProperty("java.ext.dirs"); + + /** + *+ * The {@code java.home} System Property. Java installation directory. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.1 + */ + public static final String JAVA_HOME = getSystemProperty(JAVA_HOME_KEY); + + /** + *+ * The {@code java.io.tmpdir} System Property. Default temp file path. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.2 + */ + public static final String JAVA_IO_TMPDIR = getSystemProperty(JAVA_IO_TMPDIR_KEY); + + /** + *+ * The {@code java.library.path} System Property. List of paths to search when loading libraries. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.2 + */ + public static final String JAVA_LIBRARY_PATH = getSystemProperty("java.library.path"); + + /** + *+ * The {@code java.runtime.name} System Property. Java Runtime Environment name. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since 2.0 + * @since Java 1.3 + */ + public static final String JAVA_RUNTIME_NAME = getSystemProperty("java.runtime.name"); + + /** + *+ * The {@code java.runtime.version} System Property. Java Runtime Environment version. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since 2.0 + * @since Java 1.3 + */ + public static final String JAVA_RUNTIME_VERSION = getSystemProperty("java.runtime.version"); + + /** + *+ * The {@code java.specification.name} System Property. Java Runtime Environment specification name. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.2 + */ + public static final String JAVA_SPECIFICATION_NAME = getSystemProperty("java.specification.name"); + + /** + *+ * The {@code java.specification.vendor} System Property. Java Runtime Environment specification vendor. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.2 + */ + public static final String JAVA_SPECIFICATION_VENDOR = getSystemProperty("java.specification.vendor"); + + /** + *+ * The {@code java.specification.version} System Property. Java Runtime Environment specification version. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.3 + */ + public static final String JAVA_SPECIFICATION_VERSION = getSystemProperty("java.specification.version"); + private static final JavaVersion JAVA_SPECIFICATION_VERSION_AS_ENUM = JavaVersion.get(JAVA_SPECIFICATION_VERSION); + + /** + *+ * The {@code java.util.prefs.PreferencesFactory} System Property. A class name. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since 2.1 + * @since Java 1.4 + */ + public static final String JAVA_UTIL_PREFS_PREFERENCES_FACTORY = + getSystemProperty("java.util.prefs.PreferencesFactory"); + + /** + *+ * The {@code java.vendor} System Property. Java vendor-specific string. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.1 + */ + public static final String JAVA_VENDOR = getSystemProperty("java.vendor"); + + /** + *+ * The {@code java.vendor.url} System Property. Java vendor URL. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.1 + */ + public static final String JAVA_VENDOR_URL = getSystemProperty("java.vendor.url"); + + /** + *+ * The {@code java.version} System Property. Java version number. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.1 + */ + public static final String JAVA_VERSION = getSystemProperty("java.version"); + + /** + *+ * The {@code java.vm.info} System Property. Java Virtual Machine implementation info. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since 2.0 + * @since Java 1.2 + */ + public static final String JAVA_VM_INFO = getSystemProperty("java.vm.info"); + + /** + *+ * The {@code java.vm.name} System Property. Java Virtual Machine implementation name. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.2 + */ + public static final String JAVA_VM_NAME = getSystemProperty("java.vm.name"); + + /** + *+ * The {@code java.vm.specification.name} System Property. Java Virtual Machine specification name. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.2 + */ + public static final String JAVA_VM_SPECIFICATION_NAME = getSystemProperty("java.vm.specification.name"); + + /** + *+ * The {@code java.vm.specification.vendor} System Property. Java Virtual Machine specification vendor. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.2 + */ + public static final String JAVA_VM_SPECIFICATION_VENDOR = getSystemProperty("java.vm.specification.vendor"); + + /** + *+ * The {@code java.vm.specification.version} System Property. Java Virtual Machine specification version. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.2 + */ + public static final String JAVA_VM_SPECIFICATION_VERSION = getSystemProperty("java.vm.specification.version"); + + /** + *+ * The {@code java.vm.vendor} System Property. Java Virtual Machine implementation vendor. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.2 + */ + public static final String JAVA_VM_VENDOR = getSystemProperty("java.vm.vendor"); + + /** + *+ * The {@code java.vm.version} System Property. Java Virtual Machine implementation version. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.2 + */ + public static final String JAVA_VM_VERSION = getSystemProperty("java.vm.version"); + + /** + *
+ * The {@code line.separator} System Property. Line separator ("\n" on UNIX).
+ *
+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.1 + */ + public static final String LINE_SEPARATOR = getSystemProperty("line.separator"); + + /** + *+ * The {@code os.arch} System Property. Operating system architecture. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.1 + */ + public static final String OS_ARCH = getSystemProperty("os.arch"); + + /** + *+ * The {@code os.name} System Property. Operating system name. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.1 + */ + public static final String OS_NAME = getSystemProperty("os.name"); + + /** + *+ * The {@code os.version} System Property. Operating system version. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.1 + */ + public static final String OS_VERSION = getSystemProperty("os.version"); + + /** + *
+ * The {@code path.separator} System Property. Path separator (":" on UNIX).
+ *
+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.1 + */ + public static final String PATH_SEPARATOR = getSystemProperty("path.separator"); + + /** + *+ * The {@code user.country} or {@code user.region} System Property. User's country code, such as {@code GB}. First + * in Java version 1.2 as {@code user.region}. Renamed to {@code user.country} in 1.4 + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since 2.0 + * @since Java 1.2 + */ + public static final String USER_COUNTRY = getSystemProperty("user.country") == null ? + getSystemProperty("user.region") : getSystemProperty("user.country"); + + /** + *+ * The {@code user.dir} System Property. User's current working directory. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.1 + */ + public static final String USER_DIR = getSystemProperty(USER_DIR_KEY); + + /** + *+ * The {@code user.home} System Property. User's home directory. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.1 + */ + public static final String USER_HOME = getSystemProperty(USER_HOME_KEY); + + /** + *+ * The {@code user.language} System Property. User's language code, such as {@code "en"}. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since 2.0 + * @since Java 1.2 + */ + public static final String USER_LANGUAGE = getSystemProperty("user.language"); + + /** + *+ * The {@code user.name} System Property. User's account name. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since Java 1.1 + */ + public static final String USER_NAME = getSystemProperty("user.name"); + + /** + *+ * The {@code user.timezone} System Property. For example: {@code "America/Los_Angeles"}. + *
+ *+ * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *
+ *+ * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *
+ * + * @since 2.1 + */ + public static final String USER_TIMEZONE = getSystemProperty("user.timezone"); + + // Java version checks + // ----------------------------------------------------------------------- + // These MUST be declared after those above as they depend on the + // values being set up + + /** + *+ * Is {@code true} if this is Java version 1.1 (also 1.1.x versions). + *
+ *+ * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *
+ */ + public static final boolean IS_JAVA_1_1 = getJavaVersionMatches("1.1"); + + /** + *+ * Is {@code true} if this is Java version 1.2 (also 1.2.x versions). + *
+ *+ * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *
+ */ + public static final boolean IS_JAVA_1_2 = getJavaVersionMatches("1.2"); + + /** + *+ * Is {@code true} if this is Java version 1.3 (also 1.3.x versions). + *
+ *+ * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *
+ */ + public static final boolean IS_JAVA_1_3 = getJavaVersionMatches("1.3"); + + /** + *+ * Is {@code true} if this is Java version 1.4 (also 1.4.x versions). + *
+ *+ * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *
+ */ + public static final boolean IS_JAVA_1_4 = getJavaVersionMatches("1.4"); + + /** + *+ * Is {@code true} if this is Java version 1.5 (also 1.5.x versions). + *
+ *+ * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *
+ */ + public static final boolean IS_JAVA_1_5 = getJavaVersionMatches("1.5"); + + /** + *+ * Is {@code true} if this is Java version 1.6 (also 1.6.x versions). + *
+ *+ * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *
+ */ + public static final boolean IS_JAVA_1_6 = getJavaVersionMatches("1.6"); + + /** + *+ * Is {@code true} if this is Java version 1.7 (also 1.7.x versions). + *
+ *+ * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *
+ * + * @since 3.0 + */ + public static final boolean IS_JAVA_1_7 = getJavaVersionMatches("1.7"); + + // Operating system checks + // ----------------------------------------------------------------------- + // These MUST be declared after those above as they depend on the + // values being set up + // OS names from http://www.vamphq.com/os.html + // Selected ones included - please advise dev@commons.apache.org + // if you want another added or a mistake corrected + + /** + *+ * Is {@code true} if this is AIX. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_AIX = getOSMatchesName("AIX"); + + /** + *+ * Is {@code true} if this is HP-UX. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_HP_UX = getOSMatchesName("HP-UX"); + + /** + *+ * Is {@code true} if this is Irix. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_IRIX = getOSMatchesName("Irix"); + + /** + *+ * Is {@code true} if this is Linux. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_LINUX = getOSMatchesName("Linux") || getOSMatchesName("LINUX"); + + /** + *+ * Is {@code true} if this is Mac. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_MAC = getOSMatchesName("Mac"); + + /** + *+ * Is {@code true} if this is Mac. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_MAC_OSX = getOSMatchesName("Mac OS X"); + + /** + *+ * Is {@code true} if this is FreeBSD. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 3.0.2 + */ + public static final boolean IS_OS_FREE_BSD = getOSMatchesName("FreeBSD"); + + /** + *+ * Is {@code true} if this is OpenBSD. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 3.0.2 + */ + public static final boolean IS_OS_OPEN_BSD = getOSMatchesName("OpenBSD"); + + /** + *+ * Is {@code true} if this is NetBSD. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 3.0.2 + */ + public static final boolean IS_OS_NET_BSD = getOSMatchesName("NetBSD"); + + /** + *+ * Is {@code true} if this is OS/2. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_OS2 = getOSMatchesName("OS/2"); + + /** + *+ * Is {@code true} if this is Solaris. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_SOLARIS = getOSMatchesName("Solaris"); + + /** + *+ * Is {@code true} if this is SunOS. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_SUN_OS = getOSMatchesName("SunOS"); + + /** + *+ * Is {@code true} if this is a UNIX like system, as in any of AIX, HP-UX, Irix, Linux, MacOSX, Solaris or SUN OS. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.1 + */ + public static final boolean IS_OS_UNIX = IS_OS_AIX || IS_OS_HP_UX || IS_OS_IRIX || IS_OS_LINUX || IS_OS_MAC_OSX + || IS_OS_SOLARIS || IS_OS_SUN_OS || IS_OS_FREE_BSD || IS_OS_OPEN_BSD || IS_OS_NET_BSD; + + /** + *+ * Is {@code true} if this is Windows. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_WINDOWS = getOSMatchesName(OS_NAME_WINDOWS_PREFIX); + + /** + *+ * Is {@code true} if this is Windows 2000. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_WINDOWS_2000 = getOSMatches(OS_NAME_WINDOWS_PREFIX, "5.0"); + + /** + *+ * Is {@code true} if this is Windows 95. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_WINDOWS_95 = getOSMatches(OS_NAME_WINDOWS_PREFIX + " 9", "4.0"); + // Java 1.2 running on Windows98 returns 'Windows 95', hence the above + + /** + *+ * Is {@code true} if this is Windows 98. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_WINDOWS_98 = getOSMatches(OS_NAME_WINDOWS_PREFIX + " 9", "4.1"); + // Java 1.2 running on Windows98 returns 'Windows 95', hence the above + + /** + *+ * Is {@code true} if this is Windows ME. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_WINDOWS_ME = getOSMatches(OS_NAME_WINDOWS_PREFIX, "4.9"); + // Java 1.2 running on WindowsME may return 'Windows 95', hence the above + + /** + *+ * Is {@code true} if this is Windows NT. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_WINDOWS_NT = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " NT"); + // Windows 2000 returns 'Windows 2000' but may suffer from same Java1.2 problem + + /** + *+ * Is {@code true} if this is Windows XP. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.0 + */ + public static final boolean IS_OS_WINDOWS_XP = getOSMatches(OS_NAME_WINDOWS_PREFIX, "5.1"); + + // ----------------------------------------------------------------------- + /** + *+ * Is {@code true} if this is Windows Vista. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 2.4 + */ + public static final boolean IS_OS_WINDOWS_VISTA = getOSMatches(OS_NAME_WINDOWS_PREFIX, "6.0"); + + /** + *+ * Is {@code true} if this is Windows 7. + *
+ *+ * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *
+ * + * @since 3.0 + */ + public static final boolean IS_OS_WINDOWS_7 = getOSMatches(OS_NAME_WINDOWS_PREFIX, "6.1"); + + /** + *+ * Gets the Java home directory as a {@code File}. + *
+ * + * @return a directory + * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow + * access to the specified system property. + * @see System#getProperty(String) + * @since 2.1 + */ + public static File getJavaHome() { + return new File(System.getProperty(JAVA_HOME_KEY)); + } + + /** + *+ * Gets the Java IO temporary directory as a {@code File}. + *
+ * + * @return a directory + * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow + * access to the specified system property. + * @see System#getProperty(String) + * @since 2.1 + */ + public static File getJavaIoTmpDir() { + return new File(System.getProperty(JAVA_IO_TMPDIR_KEY)); + } + + /** + *+ * Decides if the Java version matches. + *
+ * + * @param versionPrefix the prefix for the java version + * @return true if matches, or false if not or can't determine + */ + private static boolean getJavaVersionMatches(String versionPrefix) { + return isJavaVersionMatch(JAVA_SPECIFICATION_VERSION, versionPrefix); + } + + /** + * Decides if the operating system matches. + * + * @param osNamePrefix the prefix for the os name + * @param osVersionPrefix the prefix for the version + * @return true if matches, or false if not or can't determine + */ + private static boolean getOSMatches(String osNamePrefix, String osVersionPrefix) { + return isOSMatch(OS_NAME, OS_VERSION, osNamePrefix, osVersionPrefix); + } + + /** + * Decides if the operating system matches. + * + * @param osNamePrefix the prefix for the os name + * @return true if matches, or false if not or can't determine + */ + private static boolean getOSMatchesName(String osNamePrefix) { + return isOSNameMatch(OS_NAME, osNamePrefix); + } + + // ----------------------------------------------------------------------- + /** + *+ * Gets a System property, defaulting to {@code null} if the property cannot be read. + *
+ *+ * If a {@code SecurityException} is caught, the return value is {@code null} and a message is written to + * {@code System.err}. + *
+ * + * @param property the system property name + * @return the system property value or {@code null} if a security problem occurs + */ + private static String getSystemProperty(String property) { + try { + return System.getProperty(property); + } catch (SecurityException ex) { + // we are not allowed to look at this property + System.err.println("Caught a SecurityException reading the system property '" + property + + "'; the SystemUtils property value will default to null."); + return null; + } + } + + /** + *+ * Gets the user directory as a {@code File}. + *
+ * + * @return a directory + * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow + * access to the specified system property. + * @see System#getProperty(String) + * @since 2.1 + */ + public static File getUserDir() { + return new File(System.getProperty(USER_DIR_KEY)); + } + + /** + *+ * Gets the user home directory as a {@code File}. + *
+ * + * @return a directory + * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow + * access to the specified system property. + * @see System#getProperty(String) + * @since 2.1 + */ + public static File getUserHome() { + return new File(System.getProperty(USER_HOME_KEY)); + } + + /** + * Returns whether the {@link #JAVA_AWT_HEADLESS} value is {@code true}. + * + * @return {@code true} if {@code JAVA_AWT_HEADLESS} is {@code "true"}, {@code false} otherwise. + * @see #JAVA_AWT_HEADLESS + * @since 2.1 + * @since Java 1.4 + */ + public static boolean isJavaAwtHeadless() { + return JAVA_AWT_HEADLESS != null ? JAVA_AWT_HEADLESS.equals(Boolean.TRUE.toString()) : false; + } + + /** + *+ * Is the Java version at least the requested version. + *
+ *+ * Example input: + *
+ *+ * Decides if the Java version matches. + *
+ *+ * This method is package private instead of private to support unit test invocation. + *
+ * + * @param version the actual Java version + * @param versionPrefix the prefix for the expected Java version + * @return true if matches, or false if not or can't determine + */ + static boolean isJavaVersionMatch(String version, String versionPrefix) { + if (version == null) { + return false; + } + return version.startsWith(versionPrefix); + } + + /** + * Decides if the operating system matches. + *+ * This method is package private instead of private to support unit test invocation. + *
+ * + * @param osName the actual OS name + * @param osVersion the actual OS version + * @param osNamePrefix the prefix for the expected OS name + * @param osVersionPrefix the prefix for the expected OS version + * @return true if matches, or false if not or can't determine + */ + static boolean isOSMatch(String osName, String osVersion, String osNamePrefix, String osVersionPrefix) { + if (osName == null || osVersion == null) { + return false; + } + return osName.startsWith(osNamePrefix) && osVersion.startsWith(osVersionPrefix); + } + + /** + * Decides if the operating system matches. + *+ * This method is package private instead of private to support unit test invocation. + *
+ * + * @param osName the actual OS name + * @param osNamePrefix the prefix for the expected OS name + * @return true if matches, or false if not or can't determine + */ + static boolean isOSNameMatch(String osName, String osNamePrefix) { + if (osName == null) { + return false; + } + return osName.startsWith(osNamePrefix); + } + + // ----------------------------------------------------------------------- + /** + *+ * SystemUtils instances should NOT be constructed in standard programming. Instead, the class should be used as + * {@code SystemUtils.FILE_SEPARATOR}. + *
+ *+ * This constructor is public to permit tools that require a JavaBean instance to operate. + *
+ */ + public SystemUtils() { + super(); + } + +} diff --git a/src/org/apache/commons/lang3/Validate.java b/src/org/apache/commons/lang3/Validate.java index 36716d6..4c1fd4f 100644 --- a/src/org/apache/commons/lang3/Validate.java +++ b/src/org/apache/commons/lang3/Validate.java @@ -1,1071 +1,1071 @@ -/* - * 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.commons.lang3; - -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.regex.Pattern; - -/** - *This class assists in validating arguments. The validation methods are - * based along the following principles: - *
All exceptions messages are - * format strings - * as defined by the Java platform. For example:
- * - *- * Validate.isTrue(i > 0, "The value must be greater than zero: %d", i); - * Validate.notNull(surname, "The surname must not be %s", null); - *- * - *
#ThreadSafe#
- * @version $Id: Validate.java 1153490 2011-08-03 13:53:35Z ggregory $ - * @see java.lang.String#format(String, Object...) - * @since 2.0 - */ -public class Validate { - - private static final String DEFAULT_EXCLUSIVE_BETWEEN_EX_MESSAGE = - "The value %s is not in the specified exclusive range of %s to %s"; - private static final String DEFAULT_INCLUSIVE_BETWEEN_EX_MESSAGE = - "The value %s is not in the specified inclusive range of %s to %s"; - private static final String DEFAULT_MATCHES_PATTERN_EX = "The string %s does not match the pattern %s"; - private static final String DEFAULT_IS_NULL_EX_MESSAGE = "The validated object is null"; - private static final String DEFAULT_IS_TRUE_EX_MESSAGE = "The validated expression is false"; - private static final String DEFAULT_NO_NULL_ELEMENTS_ARRAY_EX_MESSAGE = - "The validated array contains null element at index: %d"; - private static final String DEFAULT_NO_NULL_ELEMENTS_COLLECTION_EX_MESSAGE = - "The validated collection contains null element at index: %d"; - private static final String DEFAULT_NOT_BLANK_EX_MESSAGE = "The validated character sequence is blank"; - private static final String DEFAULT_NOT_EMPTY_ARRAY_EX_MESSAGE = "The validated array is empty"; - private static final String DEFAULT_NOT_EMPTY_CHAR_SEQUENCE_EX_MESSAGE = - "The validated character sequence is empty"; - private static final String DEFAULT_NOT_EMPTY_COLLECTION_EX_MESSAGE = "The validated collection is empty"; - private static final String DEFAULT_NOT_EMPTY_MAP_EX_MESSAGE = "The validated map is empty"; - private static final String DEFAULT_VALID_INDEX_ARRAY_EX_MESSAGE = "The validated array index is invalid: %d"; - private static final String DEFAULT_VALID_INDEX_CHAR_SEQUENCE_EX_MESSAGE = - "The validated character sequence index is invalid: %d"; - private static final String DEFAULT_VALID_INDEX_COLLECTION_EX_MESSAGE = - "The validated collection index is invalid: %d"; - private static final String DEFAULT_VALID_STATE_EX_MESSAGE = "The validated state is false"; - private static final String DEFAULT_IS_ASSIGNABLE_EX_MESSAGE = - "The validated class can not be converted to the %s class"; - private static final String DEFAULT_IS_INSTANCE_OF_EX_MESSAGE = "The validated object is not an instance of %s"; - - /** - * Constructor. This class should not normally be instantiated. - */ - public Validate() { - super(); - } - - // isTrue - //--------------------------------------------------------------------------------- - - /** - *Validate that the argument condition is {@code true}; otherwise - * throwing an exception with the specified message. This method is useful when - * validating according to an arbitrary boolean expression, such as validating a - * primitive number or using your own custom validation expression.
- * - *Validate.isTrue(i > 0.0, "The value must be greater than zero: %d", i);- * - *
For performance reasons, the long value is passed as a separate parameter and - * appended to the exception message only in the case of an error.
- * - * @param expression the boolean expression to check - * @param message the {@link String#format(String, Object...)} exception message if invalid, not null - * @param value the value to append to the message when invalid - * @throws IllegalArgumentException if expression is {@code false} - * @see #isTrue(boolean) - * @see #isTrue(boolean, String, double) - * @see #isTrue(boolean, String, Object...) - */ - public static void isTrue(boolean expression, String message, long value) { - if (expression == false) { - throw new IllegalArgumentException(String.format(message, Long.valueOf(value))); - } - } - - /** - *Validate that the argument condition is {@code true}; otherwise - * throwing an exception with the specified message. This method is useful when - * validating according to an arbitrary boolean expression, such as validating a - * primitive number or using your own custom validation expression.
- * - *Validate.isTrue(d > 0.0, "The value must be greater than zero: %s", d);- * - *
For performance reasons, the double value is passed as a separate parameter and - * appended to the exception message only in the case of an error.
- * - * @param expression the boolean expression to check - * @param message the {@link String#format(String, Object...)} exception message if invalid, not null - * @param value the value to append to the message when invalid - * @throws IllegalArgumentException if expression is {@code false} - * @see #isTrue(boolean) - * @see #isTrue(boolean, String, long) - * @see #isTrue(boolean, String, Object...) - */ - public static void isTrue(boolean expression, String message, double value) { - if (expression == false) { - throw new IllegalArgumentException(String.format(message, Double.valueOf(value))); - } - } - - /** - *Validate that the argument condition is {@code true}; otherwise - * throwing an exception with the specified message. This method is useful when - * validating according to an arbitrary boolean expression, such as validating a - * primitive number or using your own custom validation expression.
- * - *- * Validate.isTrue(i >= min && i <= max, "The value must be between %d and %d", min, max); - * Validate.isTrue(myObject.isOk(), "The object is not okay");- * - * @param expression the boolean expression to check - * @param message the {@link String#format(String, Object...)} exception message if invalid, not null - * @param values the optional values for the formatted exception message, null array not recommended - * @throws IllegalArgumentException if expression is {@code false} - * @see #isTrue(boolean) - * @see #isTrue(boolean, String, long) - * @see #isTrue(boolean, String, double) - */ - public static void isTrue(boolean expression, String message, Object... values) { - if (expression == false) { - throw new IllegalArgumentException(String.format(message, values)); - } - } - - /** - *
Validate that the argument condition is {@code true}; otherwise - * throwing an exception. This method is useful when validating according - * to an arbitrary boolean expression, such as validating a - * primitive number or using your own custom validation expression.
- * - *- * Validate.isTrue(i > 0); - * Validate.isTrue(myObject.isOk());- * - *
The message of the exception is "The validated expression is - * false".
- * - * @param expression the boolean expression to check - * @throws IllegalArgumentException if expression is {@code false} - * @see #isTrue(boolean, String, long) - * @see #isTrue(boolean, String, double) - * @see #isTrue(boolean, String, Object...) - */ - public static void isTrue(boolean expression) { - if (expression == false) { - throw new IllegalArgumentException(DEFAULT_IS_TRUE_EX_MESSAGE); - } - } - - // notNull - //--------------------------------------------------------------------------------- - - /** - *Validate that the specified argument is not {@code null}; - * otherwise throwing an exception. - * - *
Validate.notNull(myObject, "The object must not be null");- * - *
The message of the exception is "The validated object is - * null".
- * - * @paramValidate that the specified argument is not {@code null}; - * otherwise throwing an exception with the specified message. - * - *
Validate.notNull(myObject, "The object must not be null");- * - * @param
Validate that the specified argument array is neither {@code null} - * nor a length of zero (no elements); otherwise throwing an exception - * with the specified message. - * - *
Validate.notEmpty(myArray, "The array must not be empty");- * - * @param
Validate that the specified argument array is neither {@code null} - * nor a length of zero (no elements); otherwise throwing an exception. - * - *
Validate.notEmpty(myArray);- * - *
The message in the exception is "The validated array is
- * empty".
- *
- * @param Validate that the specified argument collection is neither {@code null}
- * nor a size of zero (no elements); otherwise throwing an exception
- * with the specified message.
- *
- * Validate that the specified argument collection is neither {@code null}
- * nor a size of zero (no elements); otherwise throwing an exception.
- *
- * The message in the exception is "The validated collection is
- * empty". Validate that the specified argument map is neither {@code null}
- * nor a size of zero (no elements); otherwise throwing an exception
- * with the specified message.
- *
- * Validate that the specified argument map is neither {@code null}
- * nor a size of zero (no elements); otherwise throwing an exception.
- *
- * The message in the exception is "The validated map is
- * empty". Validate that the specified argument character sequence is
- * neither {@code null} nor a length of zero (no characters);
- * otherwise throwing an exception with the specified message.
- *
- * Validate that the specified argument character sequence is
- * neither {@code null} nor a length of zero (no characters);
- * otherwise throwing an exception with the specified message.
- *
- * The message in the exception is "The validated
- * character sequence is empty". Validate that the specified argument character sequence is
- * neither {@code null}, a length of zero (no characters), empty
- * nor whitespace; otherwise throwing an exception with the specified
- * message.
- *
- * Validate that the specified argument character sequence is
- * neither {@code null}, a length of zero (no characters), empty
- * nor whitespace; otherwise throwing an exception.
- *
- * The message in the exception is "The validated character
- * sequence is blank". Validate that the specified argument array is neither
- * {@code null} nor contains any elements that are {@code null};
- * otherwise throwing an exception with the specified message.
- *
- * If the array is {@code null}, then the message in the exception
- * is "The validated object is null". If the array has a {@code null} element, then the iteration
- * index of the invalid element is appended to the {@code values}
- * argument. Validate that the specified argument array is neither
- * {@code null} nor contains any elements that are {@code null};
- * otherwise throwing an exception.
- *
- * If the array is {@code null}, then the message in the exception
- * is "The validated object is null". If the array has a {@code null} element, then the message in the
- * exception is "The validated array contains null element at index:
- * " followed by the index. Validate that the specified argument iterable is neither
- * {@code null} nor contains any elements that are {@code null};
- * otherwise throwing an exception with the specified message.
- *
- * If the iterable is {@code null}, then the message in the exception
- * is "The validated object is null". If the iterable has a {@code null} element, then the iteration
- * index of the invalid element is appended to the {@code values}
- * argument. Validate that the specified argument iterable is neither
- * {@code null} nor contains any elements that are {@code null};
- * otherwise throwing an exception.
- *
- * If the iterable is {@code null}, then the message in the exception
- * is "The validated object is null". If the array has a {@code null} element, then the message in the
- * exception is "The validated iterable contains null element at index:
- * " followed by the index. Validates that the index is within the bounds of the argument
- * array; otherwise throwing an exception with the specified message. If the array is {@code null}, then the message of the exception
- * is "The validated object is null". Validates that the index is within the bounds of the argument
- * array; otherwise throwing an exception. If the array is {@code null}, then the message of the exception
- * is "The validated object is null". If the index is invalid, then the message of the exception is
- * "The validated array index is invalid: " followed by the
- * index. Validates that the index is within the bounds of the argument
- * collection; otherwise throwing an exception with the specified message. If the collection is {@code null}, then the message of the
- * exception is "The validated object is null". Validates that the index is within the bounds of the argument
- * collection; otherwise throwing an exception. If the index is invalid, then the message of the exception
- * is "The validated collection index is invalid: "
- * followed by the index. Validates that the index is within the bounds of the argument
- * character sequence; otherwise throwing an exception with the
- * specified message. If the character sequence is {@code null}, then the message
- * of the exception is "The validated object is null". Validates that the index is within the bounds of the argument
- * character sequence; otherwise throwing an exception. If the character sequence is {@code null}, then the message
- * of the exception is "The validated object is
- * null". If the index is invalid, then the message of the exception
- * is "The validated character sequence index is invalid: "
- * followed by the index. Validate that the stateful condition is {@code true}; otherwise
- * throwing an exception. This method is useful when validating according
- * to an arbitrary boolean expression, such as validating a
- * primitive number or using your own custom validation expression. The message of the exception is "The validated state is
- * false". Validate that the stateful condition is {@code true}; otherwise
- * throwing an exception with the specified message. This method is useful when
- * validating according to an arbitrary boolean expression, such as validating a
- * primitive number or using your own custom validation expression. Validate that the specified argument character sequence matches the specified regular
- * expression pattern; otherwise throwing an exception. The syntax of the pattern is the one used in the {@link Pattern} class. Validate that the specified argument character sequence matches the specified regular
- * expression pattern; otherwise throwing an exception with the specified message. The syntax of the pattern is the one used in the {@link Pattern} class. Validate that the specified argument object fall between the two
- * inclusive values specified; otherwise, throws an exception. Validate that the specified argument object fall between the two
- * inclusive values specified; otherwise, throws an exception with the
- * specified message. Validate that the specified argument object fall between the two
- * exclusive values specified; otherwise, throws an exception. Validate that the specified argument object fall between the two
- * exclusive values specified; otherwise, throws an exception with the
- * specified message. Validate that the argument is an instance of the specified class; otherwise
- * throwing an exception. This method is useful when validating according to an arbitrary
- * class The message of the exception is "The validated object is not an instance of"
- * followed by the name of the class Validate that the argument is an instance of the specified class; otherwise
- * throwing an exception with the specified message. This method is useful when
- * validating according to an arbitrary class Validate that the argument can be converted to the specified class; otherwise
- * throwing an exception with the specified message. This method is useful when
- * validating if there will be no casting errors. The message of the exception is "The validated object can not be converted to the"
- * followed by the name of the class and "class" Validate that the argument can be converted to the specified class; otherwise
- * throwing an exception. This method is useful when validating if there will be no
- * casting errors. The message of the exception is "The validated object can not be converted to the"
- * followed by the name of the class and "class" This class assists in validating arguments. The validation methods are
+ * based along the following principles:
+ * All exceptions messages are
+ * format strings
+ * as defined by the Java platform. For example: #ThreadSafe# Validate that the argument condition is {@code true}; otherwise
+ * throwing an exception with the specified message. This method is useful when
+ * validating according to an arbitrary boolean expression, such as validating a
+ * primitive number or using your own custom validation expression. For performance reasons, the long value is passed as a separate parameter and
+ * appended to the exception message only in the case of an error. Validate that the argument condition is {@code true}; otherwise
+ * throwing an exception with the specified message. This method is useful when
+ * validating according to an arbitrary boolean expression, such as validating a
+ * primitive number or using your own custom validation expression. For performance reasons, the double value is passed as a separate parameter and
+ * appended to the exception message only in the case of an error. Validate that the argument condition is {@code true}; otherwise
+ * throwing an exception with the specified message. This method is useful when
+ * validating according to an arbitrary boolean expression, such as validating a
+ * primitive number or using your own custom validation expression. Validate that the argument condition is {@code true}; otherwise
+ * throwing an exception. This method is useful when validating according
+ * to an arbitrary boolean expression, such as validating a
+ * primitive number or using your own custom validation expression. The message of the exception is "The validated expression is
+ * false". Validate that the specified argument is not {@code null};
+ * otherwise throwing an exception.
+ *
+ * The message of the exception is "The validated object is
+ * null". Validate that the specified argument is not {@code null};
+ * otherwise throwing an exception with the specified message.
+ *
+ * Validate that the specified argument array is neither {@code null}
+ * nor a length of zero (no elements); otherwise throwing an exception
+ * with the specified message.
+ *
+ * Validate that the specified argument array is neither {@code null}
+ * nor a length of zero (no elements); otherwise throwing an exception.
+ *
+ * The message in the exception is "The validated array is
+ * empty".
+ *
+ * @param Validate that the specified argument collection is neither {@code null}
+ * nor a size of zero (no elements); otherwise throwing an exception
+ * with the specified message.
+ *
+ * Validate that the specified argument collection is neither {@code null}
+ * nor a size of zero (no elements); otherwise throwing an exception.
+ *
+ * The message in the exception is "The validated collection is
+ * empty". Validate that the specified argument map is neither {@code null}
+ * nor a size of zero (no elements); otherwise throwing an exception
+ * with the specified message.
+ *
+ * Validate that the specified argument map is neither {@code null}
+ * nor a size of zero (no elements); otherwise throwing an exception.
+ *
+ * The message in the exception is "The validated map is
+ * empty". Validate that the specified argument character sequence is
+ * neither {@code null} nor a length of zero (no characters);
+ * otherwise throwing an exception with the specified message.
+ *
+ * Validate that the specified argument character sequence is
+ * neither {@code null} nor a length of zero (no characters);
+ * otherwise throwing an exception with the specified message.
+ *
+ * The message in the exception is "The validated
+ * character sequence is empty". Validate that the specified argument character sequence is
+ * neither {@code null}, a length of zero (no characters), empty
+ * nor whitespace; otherwise throwing an exception with the specified
+ * message.
+ *
+ * Validate that the specified argument character sequence is
+ * neither {@code null}, a length of zero (no characters), empty
+ * nor whitespace; otherwise throwing an exception.
+ *
+ * The message in the exception is "The validated character
+ * sequence is blank". Validate that the specified argument array is neither
+ * {@code null} nor contains any elements that are {@code null};
+ * otherwise throwing an exception with the specified message.
+ *
+ * If the array is {@code null}, then the message in the exception
+ * is "The validated object is null". If the array has a {@code null} element, then the iteration
+ * index of the invalid element is appended to the {@code values}
+ * argument. Validate that the specified argument array is neither
+ * {@code null} nor contains any elements that are {@code null};
+ * otherwise throwing an exception.
+ *
+ * If the array is {@code null}, then the message in the exception
+ * is "The validated object is null". If the array has a {@code null} element, then the message in the
+ * exception is "The validated array contains null element at index:
+ * " followed by the index. Validate that the specified argument iterable is neither
+ * {@code null} nor contains any elements that are {@code null};
+ * otherwise throwing an exception with the specified message.
+ *
+ * If the iterable is {@code null}, then the message in the exception
+ * is "The validated object is null". If the iterable has a {@code null} element, then the iteration
+ * index of the invalid element is appended to the {@code values}
+ * argument. Validate that the specified argument iterable is neither
+ * {@code null} nor contains any elements that are {@code null};
+ * otherwise throwing an exception.
+ *
+ * If the iterable is {@code null}, then the message in the exception
+ * is "The validated object is null". If the array has a {@code null} element, then the message in the
+ * exception is "The validated iterable contains null element at index:
+ * " followed by the index. Validates that the index is within the bounds of the argument
+ * array; otherwise throwing an exception with the specified message. If the array is {@code null}, then the message of the exception
+ * is "The validated object is null". Validates that the index is within the bounds of the argument
+ * array; otherwise throwing an exception. If the array is {@code null}, then the message of the exception
+ * is "The validated object is null". If the index is invalid, then the message of the exception is
+ * "The validated array index is invalid: " followed by the
+ * index. Validates that the index is within the bounds of the argument
+ * collection; otherwise throwing an exception with the specified message. If the collection is {@code null}, then the message of the
+ * exception is "The validated object is null". Validates that the index is within the bounds of the argument
+ * collection; otherwise throwing an exception. If the index is invalid, then the message of the exception
+ * is "The validated collection index is invalid: "
+ * followed by the index. Validates that the index is within the bounds of the argument
+ * character sequence; otherwise throwing an exception with the
+ * specified message. If the character sequence is {@code null}, then the message
+ * of the exception is "The validated object is null". Validates that the index is within the bounds of the argument
+ * character sequence; otherwise throwing an exception. If the character sequence is {@code null}, then the message
+ * of the exception is "The validated object is
+ * null". If the index is invalid, then the message of the exception
+ * is "The validated character sequence index is invalid: "
+ * followed by the index. Validate that the stateful condition is {@code true}; otherwise
+ * throwing an exception. This method is useful when validating according
+ * to an arbitrary boolean expression, such as validating a
+ * primitive number or using your own custom validation expression. The message of the exception is "The validated state is
+ * false". Validate that the stateful condition is {@code true}; otherwise
+ * throwing an exception with the specified message. This method is useful when
+ * validating according to an arbitrary boolean expression, such as validating a
+ * primitive number or using your own custom validation expression. Validate that the specified argument character sequence matches the specified regular
+ * expression pattern; otherwise throwing an exception. The syntax of the pattern is the one used in the {@link Pattern} class. Validate that the specified argument character sequence matches the specified regular
+ * expression pattern; otherwise throwing an exception with the specified message. The syntax of the pattern is the one used in the {@link Pattern} class. Validate that the specified argument object fall between the two
+ * inclusive values specified; otherwise, throws an exception. Validate that the specified argument object fall between the two
+ * inclusive values specified; otherwise, throws an exception with the
+ * specified message. Validate that the specified argument object fall between the two
+ * exclusive values specified; otherwise, throws an exception. Validate that the specified argument object fall between the two
+ * exclusive values specified; otherwise, throws an exception with the
+ * specified message. Validate that the argument is an instance of the specified class; otherwise
+ * throwing an exception. This method is useful when validating according to an arbitrary
+ * class The message of the exception is "The validated object is not an instance of"
+ * followed by the name of the class Validate that the argument is an instance of the specified class; otherwise
+ * throwing an exception with the specified message. This method is useful when
+ * validating according to an arbitrary class Validate that the argument can be converted to the specified class; otherwise
+ * throwing an exception with the specified message. This method is useful when
+ * validating if there will be no casting errors. The message of the exception is "The validated object can not be converted to the"
+ * followed by the name of the class and "class" Validate that the argument can be converted to the specified class; otherwise
+ * throwing an exception. This method is useful when validating if there will be no
+ * casting errors. The message of the exception is "The validated object can not be converted to the"
+ * followed by the name of the class and "class"
- * The Builder interface is designed to designate a class as a builder
- * object in the Builder design pattern. Builders are capable of creating and
- * configuring objects or results that normally take multiple steps to construct
- * or are very complex to derive.
- *
- * The builder interface defines a single method, {@link #build()}, that
- * classes must implement. The result of this method should be the final
- * configured object or result after all building operations are performed.
- *
- * It is a recommended practice that the methods supplied to configure the
- * object or result being built return a reference to {@code this} so that
- * method calls can be chained together.
- *
- * Example Builder:
- *
+ * The Builder interface is designed to designate a class as a builder
+ * object in the Builder design pattern. Builders are capable of creating and
+ * configuring objects or results that normally take multiple steps to construct
+ * or are very complex to derive.
+ *
+ * The builder interface defines a single method, {@link #build()}, that
+ * classes must implement. The result of this method should be the final
+ * configured object or result after all building operations are performed.
+ *
+ * It is a recommended practice that the methods supplied to configure the
+ * object or result being built return a reference to {@code this} so that
+ * method calls can be chained together.
+ *
+ * Example Builder:
+ * Two Objects that compare equal using All relevant fields should be included in the calculation of the
- * comparison. Derived fields may be ignored. The same fields, in the same
- * order, should be used in both To use this class write code as follows: Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use
- * reflection to determine the fields to append. Because fields can be private,
- * A typical implementation of Constructor for CompareToBuilder. Starts off assuming that the objects are equal. Multiple calls are
- * then made to the various append methods, followed by a call to
- * {@link #toComparison} to get the result. Compares two Fields can be private, thus If both Compares two Fields can be private, thus If both Compares two Fields can be private, thus If both Compares two Fields can be private, thus If both Compares two Fields can be private, thus If both Appends to Appends to the Appends to the Appends to the If Appends to the This handles NaNs, Infinities, and It is compatible with the hash code generated by
- * Appends to the This handles NaNs, Infinities, and It is compatible with the hash code generated by
- * Appends to the This method will also will be called for the top level of multi-dimensional,
- * ragged, and multi-typed arrays. Appends to the This method will also will be called for the top level of multi-dimensional,
- * ragged, and multi-typed arrays. Appends to the Appends to the Appends to the Appends to the Appends to the Appends to the Appends to the Appends to the Validate.notEmpty(myCollection, "The collection must not be empty");
- *
- * @param Validate.notEmpty(myCollection);
- *
- * Validate.notEmpty(myMap, "The map must not be empty");
- *
- * @param Validate.notEmpty(myMap);
- *
- * Validate.notEmpty(myString, "The string must not be empty");
- *
- * @param Validate.notEmpty(myString);
- *
- * Validate.notBlank(myString, "The string must not be blank");
- *
- * @param Validate.notBlank(myString);
- *
- * Validate.noNullElements(myArray, "The array contain null at position %d");
- *
- * Validate.noNullElements(myArray);
- *
- * Validate.noNullElements(myCollection, "The collection contains null at position %d");
- *
- * Validate.noNullElements(myCollection);
- *
- * Validate.validIndex(myArray, 2, "The array index is invalid: ");
- *
- * Validate.validIndex(myArray, 2);
- *
- * Validate.validIndex(myCollection, 2, "The collection index is invalid: ");
- *
- * Validate.validIndex(myCollection, 2);
- *
- * Validate.validIndex(myStr, 2, "The string index is invalid: ");
- *
- * Validate.validIndex(myStr, 2);
- *
- *
- * Validate.validState(field > 0);
- * Validate.validState(this.isOk());
- *
- * Validate.validState(this.isOk(), "The state is not OK: %s", myObject);
- *
- * @param expression the boolean expression to check
- * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
- * @param values the optional values for the formatted exception message, null array not recommended
- * @throws IllegalStateException if expression is {@code false}
- * @see #validState(boolean)
- *
- * @since 3.0
- */
- public static void validState(boolean expression, String message, Object... values) {
- if (expression == false) {
- throw new IllegalStateException(String.format(message, values));
- }
- }
-
- // matchesPattern
- //---------------------------------------------------------------------------------
-
- /**
- * Validate.matchesPattern("hi", "[a-z]*");
- *
- * Validate.matchesPattern("hi", "[a-z]*", "%s does not match %s", "hi" "[a-z]*");
- *
- * Validate.inclusiveBetween(0, 2, 1);
- *
- * @param Validate.inclusiveBetween(0, 2, 1, "Not in boundaries");
- *
- * @param Validate.inclusiveBetween(0, 2, 1);
- *
- * @param Validate.inclusiveBetween(0, 2, 1, "Not in boundaries");
- *
- * @param Validate.isInstanceOf(OkClass.class, object);
- *
- * Validate.isInstanceOf(OkClass.classs, object, "Wrong class, object is of class %s",
- * object.getClass().getName());
- *
- * @param type the class the object must be validated against, not null
- * @param obj the object to check, null throws an exception
- * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
- * @param values the optional values for the formatted exception message, null array not recommended
- * @throws IllegalArgumentException if argument is not of specified class
- * @see #isInstanceOf(Class, Object)
- *
- * @since 3.0
- */
- public static void isInstanceOf(Class> type, Object obj, String message, Object... values) {
- if (type.isInstance(obj) == false) {
- throw new IllegalArgumentException(String.format(message, values));
- }
- }
-
- // isAssignableFrom
- //---------------------------------------------------------------------------------
-
- /**
- * Validate.isAssignableFrom(SuperClass.class, object.getClass());
- *
- * Validate.isAssignableFrom(SuperClass.class, object.getClass());
- *
- *
+ *
+ *
+ *
+ * Validate.isTrue(i > 0, "The value must be greater than zero: %d", i);
+ * Validate.notNull(surname, "The surname must not be %s", null);
+ *
+ *
+ * Validate.isTrue(i > 0.0, "The value must be greater than zero: %d", i);
+ *
+ * Validate.isTrue(d > 0.0, "The value must be greater than zero: %s", d);
+ *
+ *
+ * Validate.isTrue(i >= min && i <= max, "The value must be between %d and %d", min, max);
+ * Validate.isTrue(myObject.isOk(), "The object is not okay");
+ *
+ * @param expression the boolean expression to check
+ * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
+ * @param values the optional values for the formatted exception message, null array not recommended
+ * @throws IllegalArgumentException if expression is {@code false}
+ * @see #isTrue(boolean)
+ * @see #isTrue(boolean, String, long)
+ * @see #isTrue(boolean, String, double)
+ */
+ public static void isTrue(boolean expression, String message, Object... values) {
+ if (expression == false) {
+ throw new IllegalArgumentException(String.format(message, values));
+ }
+ }
+
+ /**
+ *
+ * Validate.isTrue(i > 0);
+ * Validate.isTrue(myObject.isOk());
+ *
+ * Validate.notNull(myObject, "The object must not be null");
+ *
+ * Validate.notNull(myObject, "The object must not be null");
+ *
+ * @param Validate.notEmpty(myArray, "The array must not be empty");
+ *
+ * @param Validate.notEmpty(myArray);
+ *
+ * Validate.notEmpty(myCollection, "The collection must not be empty");
+ *
+ * @param Validate.notEmpty(myCollection);
+ *
+ * Validate.notEmpty(myMap, "The map must not be empty");
+ *
+ * @param Validate.notEmpty(myMap);
+ *
+ * Validate.notEmpty(myString, "The string must not be empty");
+ *
+ * @param Validate.notEmpty(myString);
+ *
+ * Validate.notBlank(myString, "The string must not be blank");
+ *
+ * @param Validate.notBlank(myString);
+ *
+ * Validate.noNullElements(myArray, "The array contain null at position %d");
+ *
+ * Validate.noNullElements(myArray);
+ *
+ * Validate.noNullElements(myCollection, "The collection contains null at position %d");
+ *
+ * Validate.noNullElements(myCollection);
+ *
+ * Validate.validIndex(myArray, 2, "The array index is invalid: ");
+ *
+ * Validate.validIndex(myArray, 2);
+ *
+ * Validate.validIndex(myCollection, 2, "The collection index is invalid: ");
+ *
+ * Validate.validIndex(myCollection, 2);
+ *
+ * Validate.validIndex(myStr, 2, "The string index is invalid: ");
+ *
+ * Validate.validIndex(myStr, 2);
+ *
+ *
+ * Validate.validState(field > 0);
+ * Validate.validState(this.isOk());
+ *
+ * Validate.validState(this.isOk(), "The state is not OK: %s", myObject);
+ *
+ * @param expression the boolean expression to check
+ * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
+ * @param values the optional values for the formatted exception message, null array not recommended
+ * @throws IllegalStateException if expression is {@code false}
+ * @see #validState(boolean)
+ *
+ * @since 3.0
+ */
+ public static void validState(boolean expression, String message, Object... values) {
+ if (expression == false) {
+ throw new IllegalStateException(String.format(message, values));
+ }
+ }
+
+ // matchesPattern
+ //---------------------------------------------------------------------------------
+
+ /**
+ * Validate.matchesPattern("hi", "[a-z]*");
+ *
+ * Validate.matchesPattern("hi", "[a-z]*", "%s does not match %s", "hi" "[a-z]*");
+ *
+ * Validate.inclusiveBetween(0, 2, 1);
+ *
+ * @param Validate.inclusiveBetween(0, 2, 1, "Not in boundaries");
+ *
+ * @param Validate.inclusiveBetween(0, 2, 1);
+ *
+ * @param Validate.inclusiveBetween(0, 2, 1, "Not in boundaries");
+ *
+ * @param Validate.isInstanceOf(OkClass.class, object);
+ *
+ * Validate.isInstanceOf(OkClass.classs, object, "Wrong class, object is of class %s",
+ * object.getClass().getName());
+ *
+ * @param type the class the object must be validated against, not null
+ * @param obj the object to check, null throws an exception
+ * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
+ * @param values the optional values for the formatted exception message, null array not recommended
+ * @throws IllegalArgumentException if argument is not of specified class
+ * @see #isInstanceOf(Class, Object)
+ *
+ * @since 3.0
+ */
+ public static void isInstanceOf(Class> type, Object obj, String message, Object... values) {
+ if (type.isInstance(obj) == false) {
+ throw new IllegalArgumentException(String.format(message, values));
+ }
+ }
+
+ // isAssignableFrom
+ //---------------------------------------------------------------------------------
+
+ /**
+ * Validate.isAssignableFrom(SuperClass.class, object.getClass());
+ *
+ * Validate.isAssignableFrom(SuperClass.class, object.getClass());
+ *
+ *
- *
- * Example Builder Usage:
- *
- * class FontBuilder implements Builder<Font> {
- * private Font font;
- *
- * public FontBuilder(String fontName) {
- * this.font = new Font(fontName, Font.PLAIN, 12);
- * }
- *
- * public FontBuilder bold() {
- * this.font = this.font.deriveFont(Font.BOLD);
- * return this; // Reference returned so calls can be chained
- * }
- *
- * public FontBuilder size(float pointSize) {
- * this.font = this.font.deriveFont(pointSize);
- * return this; // Reference returned so calls can be chained
- * }
- *
- * // Other Font construction methods
- *
- * public Font build() {
- * return this.font;
- * }
- * }
- *
- *
- * Font bold14ptSansSerifFont = new FontBuilder(Font.SANS_SERIF).bold()
- * .size(14.0f)
- * .build();
- *
+ *
+ * Example Builder Usage:
+ *
+ * class FontBuilder implements Builder<Font> {
+ * private Font font;
+ *
+ * public FontBuilder(String fontName) {
+ * this.font = new Font(fontName, Font.PLAIN, 12);
+ * }
+ *
+ * public FontBuilder bold() {
+ * this.font = this.font.deriveFont(Font.BOLD);
+ * return this; // Reference returned so calls can be chained
+ * }
+ *
+ * public FontBuilder size(float pointSize) {
+ * this.font = this.font.deriveFont(pointSize);
+ * return this; // Reference returned so calls can be chained
+ * }
+ *
+ * // Other Font construction methods
+ *
+ * public Font build() {
+ * return this.font;
+ * }
+ * }
+ *
+ *
+ * Font bold14ptSansSerifFont = new FontBuilder(Font.SANS_SERIF).bold()
+ * .size(14.0f)
+ * .build();
+ *
equals(Object) and
- * hashcode() built with {@link EqualsBuilder} and
- * {@link HashCodeBuilder}.equals(Object) should normally
- * also compare equal using compareTo(Object).compareTo(Object) and
- * equals(Object).
- * public class MyClass {
- * String field1;
- * int field2;
- * boolean field3;
- *
- * ...
- *
- * public int compareTo(Object o) {
- * MyClass myClass = (MyClass) o;
- * return new CompareToBuilder()
- * .appendSuper(super.compareTo(o)
- * .append(this.field1, myClass.field1)
- * .append(this.field2, myClass.field2)
- * .append(this.field3, myClass.field3)
- * .toComparison();
- * }
- * }
- *
- *
- * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to
- * bypass normal access control checks. This will fail under a security manager,
- * unless the appropriate permissions are set up correctly. It is also
- * slower than appending explicitly.compareTo(Object) using
- * reflectionCompare looks like:
- * public int compareTo(Object o) {
- * return CompareToBuilder.reflectionCompare(this, o);
- * }
- *
- *
- * @see java.lang.Comparable
- * @see java.lang.Object#equals(Object)
- * @see java.lang.Object#hashCode()
- * @see EqualsBuilder
- * @see HashCodeBuilder
- * @since 1.0
- * @version $Id: CompareToBuilder.java 1090813 2011-04-10 15:03:23Z mbenson $
- */
-public class CompareToBuilder implements BuilderObjects via reflection.AccessibleObject.setAccessible
- * is used to bypass normal access control checks. This will fail under a
- * security manager unless the appropriate permissions are set.
- *
- *
- * lhs and rhs are null,
- * they are considered equal.lhs
- * is less than, equal to, or greater than rhs
- * @throws NullPointerException if either (but not both) parameters are
- * null
- * @throws ClassCastException if rhs is not assignment-compatible
- * with lhs
- */
- public static int reflectionCompare(Object lhs, Object rhs) {
- return reflectionCompare(lhs, rhs, false, null);
- }
-
- /**
- * Objects via reflection.AccessibleObject.setAccessible
- * is used to bypass normal access control checks. This will fail under a
- * security manager unless the appropriate permissions are set.
- *
- *
- * compareTransients is true,
- * compares transient members. Otherwise ignores them, as they
- * are likely derived fields.lhs and rhs are null,
- * they are considered equal.lhs
- * is less than, equal to, or greater than rhs
- * @throws NullPointerException if either lhs or rhs
- * (but not both) is null
- * @throws ClassCastException if rhs is not assignment-compatible
- * with lhs
- */
- public static int reflectionCompare(Object lhs, Object rhs, boolean compareTransients) {
- return reflectionCompare(lhs, rhs, compareTransients, null);
- }
-
- /**
- * Objects via reflection.AccessibleObject.setAccessible
- * is used to bypass normal access control checks. This will fail under a
- * security manager unless the appropriate permissions are set.
- *
- *
- * compareTransients is true,
- * compares transient members. Otherwise ignores them, as they
- * are likely derived fields.lhs and rhs are null,
- * they are considered equal.lhs
- * is less than, equal to, or greater than rhs
- * @throws NullPointerException if either lhs or rhs
- * (but not both) is null
- * @throws ClassCastException if rhs is not assignment-compatible
- * with lhs
- * @since 2.2
- */
- public static int reflectionCompare(Object lhs, Object rhs, CollectionObjects via reflection.AccessibleObject.setAccessible
- * is used to bypass normal access control checks. This will fail under a
- * security manager unless the appropriate permissions are set.
- *
- *
- * compareTransients is true,
- * compares transient members. Otherwise ignores them, as they
- * are likely derived fields.lhs and rhs are null,
- * they are considered equal.lhs
- * is less than, equal to, or greater than rhs
- * @throws NullPointerException if either lhs or rhs
- * (but not both) is null
- * @throws ClassCastException if rhs is not assignment-compatible
- * with lhs
- * @since 2.2
- */
- public static int reflectionCompare(Object lhs, Object rhs, String... excludeFields) {
- return reflectionCompare(lhs, rhs, false, null, excludeFields);
- }
-
- /**
- * Objects via reflection.AccessibleObject.setAccessible
- * is used to bypass normal access control checks. This will fail under a
- * security manager unless the appropriate permissions are set.
- *
- *
- * compareTransients is true,
- * compares transient members. Otherwise ignores them, as they
- * are likely derived fields.reflectUpToClass.
- * If reflectUpToClass is null, compares all superclass fields.lhs and rhs are null,
- * they are considered equal.lhs
- * is less than, equal to, or greater than rhs
- * @throws NullPointerException if either lhs or rhs
- * (but not both) is null
- * @throws ClassCastException if rhs is not assignment-compatible
- * with lhs
- * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class))
- */
- public static int reflectionCompare(
- Object lhs,
- Object rhs,
- boolean compareTransients,
- Class> reflectUpToClass,
- String... excludeFields) {
-
- if (lhs == rhs) {
- return 0;
- }
- if (lhs == null || rhs == null) {
- throw new NullPointerException();
- }
- Class> lhsClazz = lhs.getClass();
- if (!lhsClazz.isInstance(rhs)) {
- throw new ClassCastException();
- }
- CompareToBuilder compareToBuilder = new CompareToBuilder();
- reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields);
- while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) {
- lhsClazz = lhsClazz.getSuperclass();
- reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields);
- }
- return compareToBuilder.toComparison();
- }
-
- /**
- * builder the comparison of lhs
- * to rhs using the fields defined in clazz.Class that defines fields to be compared
- * @param builder CompareToBuilder to append to
- * @param useTransients whether to compare transient fields
- * @param excludeFields fields to exclude
- */
- private static void reflectionAppend(
- Object lhs,
- Object rhs,
- Class> clazz,
- CompareToBuilder builder,
- boolean useTransients,
- String[] excludeFields) {
-
- Field[] fields = clazz.getDeclaredFields();
- AccessibleObject.setAccessible(fields, true);
- for (int i = 0; i < fields.length && builder.comparison == 0; i++) {
- Field f = fields[i];
- if (!ArrayUtils.contains(excludeFields, f.getName())
- && (f.getName().indexOf('$') == -1)
- && (useTransients || !Modifier.isTransient(f.getModifiers()))
- && (!Modifier.isStatic(f.getModifiers()))) {
- try {
- builder.append(f.get(lhs), f.get(rhs));
- } catch (IllegalAccessException e) {
- // This can't happen. Would get a Security exception instead.
- // Throw a runtime exception in case the impossible happens.
- throw new InternalError("Unexpected IllegalAccessException");
- }
- }
- }
- }
-
- //-----------------------------------------------------------------------
- /**
- * builder the compareTo(Object)
- * result of the superclass.super.compareTo(Object)
- * @return this - used to chain append calls
- * @since 2.0
- */
- public CompareToBuilder appendSuper(int superCompareTo) {
- if (comparison != 0) {
- return this;
- }
- comparison = superCompareTo;
- return this;
- }
-
- //-----------------------------------------------------------------------
- /**
- * builder the comparison of
- * two Objects.
- *
- *
- * lhs == rhslhs or rhs is null,
- * a null object is less than a non-null objectlhs must either be an array or implement {@link Comparable}.rhs is not assignment-compatible
- * with lhs
- */
- public CompareToBuilder append(Object lhs, Object rhs) {
- return append(lhs, rhs, null);
- }
-
- /**
- * builder the comparison of
- * two Objects.
- *
- *
- * lhs == rhslhs or rhs is null,
- * a null object is less than a non-null objectlhs is an array, array comparison methods will be used.
- * Otherwise comparator will be used to compare the objects.
- * If comparator is null, lhs must
- * implement {@link Comparable} instead.Comparator used to compare the objects,
- * null means treat lhs as Comparable
- * @return this - used to chain append calls
- * @throws ClassCastException if rhs is not assignment-compatible
- * with lhs
- * @since 2.0
- */
- public CompareToBuilder append(Object lhs, Object rhs, Comparator> comparator) {
- if (comparison != 0) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null) {
- comparison = -1;
- return this;
- }
- if (rhs == null) {
- comparison = +1;
- return this;
- }
- if (lhs.getClass().isArray()) {
- // switch on type of array, to dispatch to the correct handler
- // handles multi dimensional arrays
- // throws a ClassCastException if rhs is not the correct array type
- if (lhs instanceof long[]) {
- append((long[]) lhs, (long[]) rhs);
- } else if (lhs instanceof int[]) {
- append((int[]) lhs, (int[]) rhs);
- } else if (lhs instanceof short[]) {
- append((short[]) lhs, (short[]) rhs);
- } else if (lhs instanceof char[]) {
- append((char[]) lhs, (char[]) rhs);
- } else if (lhs instanceof byte[]) {
- append((byte[]) lhs, (byte[]) rhs);
- } else if (lhs instanceof double[]) {
- append((double[]) lhs, (double[]) rhs);
- } else if (lhs instanceof float[]) {
- append((float[]) lhs, (float[]) rhs);
- } else if (lhs instanceof boolean[]) {
- append((boolean[]) lhs, (boolean[]) rhs);
- } else {
- // not an array of primitives
- // throws a ClassCastException if rhs is not an array
- append((Object[]) lhs, (Object[]) rhs, comparator);
- }
- } else {
- // the simple case, not an array, just test the element
- if (comparator == null) {
- @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc
- final Comparablebuilder the comparison of
- * two longs.
- *
- * @param lhs left-hand value
- * @param rhs right-hand value
- * @return this - used to chain append calls
- */
- public CompareToBuilder append(long lhs, long rhs) {
- if (comparison != 0) {
- return this;
- }
- comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
- return this;
- }
-
- /**
- * Appends to the builder the comparison of
- * two ints.
- *
- * @param lhs left-hand value
- * @param rhs right-hand value
- * @return this - used to chain append calls
- */
- public CompareToBuilder append(int lhs, int rhs) {
- if (comparison != 0) {
- return this;
- }
- comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
- return this;
- }
-
- /**
- * Appends to the builder the comparison of
- * two shorts.
- *
- * @param lhs left-hand value
- * @param rhs right-hand value
- * @return this - used to chain append calls
- */
- public CompareToBuilder append(short lhs, short rhs) {
- if (comparison != 0) {
- return this;
- }
- comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
- return this;
- }
-
- /**
- * Appends to the builder the comparison of
- * two chars.
- *
- * @param lhs left-hand value
- * @param rhs right-hand value
- * @return this - used to chain append calls
- */
- public CompareToBuilder append(char lhs, char rhs) {
- if (comparison != 0) {
- return this;
- }
- comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
- return this;
- }
-
- /**
- * Appends to the builder the comparison of
- * two bytes.
- *
- * @param lhs left-hand value
- * @param rhs right-hand value
- * @return this - used to chain append calls
- */
- public CompareToBuilder append(byte lhs, byte rhs) {
- if (comparison != 0) {
- return this;
- }
- comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
- return this;
- }
-
- /**
- * builder the comparison of
- * two doubles.-0.0.HashCodeBuilder.builder the comparison of
- * two floats.-0.0.HashCodeBuilder.builder the comparison of
- * two booleanss.
- *
- * @param lhs left-hand value
- * @param rhs right-hand value
- * @return this - used to chain append calls
- */
- public CompareToBuilder append(boolean lhs, boolean rhs) {
- if (comparison != 0) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == false) {
- comparison = -1;
- } else {
- comparison = +1;
- }
- return this;
- }
-
- //-----------------------------------------------------------------------
- /**
- * builder the deep comparison of
- * two Object arrays.
- *
- *
- * ==null, null is less than non-nullrhs is not assignment-compatible
- * with lhs
- */
- public CompareToBuilder append(Object[] lhs, Object[] rhs) {
- return append(lhs, rhs, null);
- }
-
- /**
- * builder the deep comparison of
- * two Object arrays.
- *
- *
- * ==null, null is less than non-nullComparator to use to compare the array elements,
- * null means to treat lhs elements as Comparable.
- * @return this - used to chain append calls
- * @throws ClassCastException if rhs is not assignment-compatible
- * with lhs
- * @since 2.0
- */
- public CompareToBuilder append(Object[] lhs, Object[] rhs, Comparator> comparator) {
- if (comparison != 0) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null) {
- comparison = -1;
- return this;
- }
- if (rhs == null) {
- comparison = +1;
- return this;
- }
- if (lhs.length != rhs.length) {
- comparison = (lhs.length < rhs.length) ? -1 : +1;
- return this;
- }
- for (int i = 0; i < lhs.length && comparison == 0; i++) {
- append(lhs[i], rhs[i], comparator);
- }
- return this;
- }
-
- /**
- * builder the deep comparison of
- * two long arrays.
- *
- *
- * @param lhs left-hand array
- * @param rhs right-hand array
- * @return this - used to chain append calls
- */
- public CompareToBuilder append(long[] lhs, long[] rhs) {
- if (comparison != 0) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null) {
- comparison = -1;
- return this;
- }
- if (rhs == null) {
- comparison = +1;
- return this;
- }
- if (lhs.length != rhs.length) {
- comparison = (lhs.length < rhs.length) ? -1 : +1;
- return this;
- }
- for (int i = 0; i < lhs.length && comparison == 0; i++) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * ==null, null is less than non-nullbuilder the deep comparison of
- * two int arrays.
- *
- *
- * @param lhs left-hand array
- * @param rhs right-hand array
- * @return this - used to chain append calls
- */
- public CompareToBuilder append(int[] lhs, int[] rhs) {
- if (comparison != 0) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null) {
- comparison = -1;
- return this;
- }
- if (rhs == null) {
- comparison = +1;
- return this;
- }
- if (lhs.length != rhs.length) {
- comparison = (lhs.length < rhs.length) ? -1 : +1;
- return this;
- }
- for (int i = 0; i < lhs.length && comparison == 0; i++) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * ==null, null is less than non-nullbuilder the deep comparison of
- * two short arrays.
- *
- *
- * @param lhs left-hand array
- * @param rhs right-hand array
- * @return this - used to chain append calls
- */
- public CompareToBuilder append(short[] lhs, short[] rhs) {
- if (comparison != 0) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null) {
- comparison = -1;
- return this;
- }
- if (rhs == null) {
- comparison = +1;
- return this;
- }
- if (lhs.length != rhs.length) {
- comparison = (lhs.length < rhs.length) ? -1 : +1;
- return this;
- }
- for (int i = 0; i < lhs.length && comparison == 0; i++) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * ==null, null is less than non-nullbuilder the deep comparison of
- * two char arrays.
- *
- *
- * @param lhs left-hand array
- * @param rhs right-hand array
- * @return this - used to chain append calls
- */
- public CompareToBuilder append(char[] lhs, char[] rhs) {
- if (comparison != 0) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null) {
- comparison = -1;
- return this;
- }
- if (rhs == null) {
- comparison = +1;
- return this;
- }
- if (lhs.length != rhs.length) {
- comparison = (lhs.length < rhs.length) ? -1 : +1;
- return this;
- }
- for (int i = 0; i < lhs.length && comparison == 0; i++) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * ==null, null is less than non-nullbuilder the deep comparison of
- * two byte arrays.
- *
- *
- * @param lhs left-hand array
- * @param rhs right-hand array
- * @return this - used to chain append calls
- */
- public CompareToBuilder append(byte[] lhs, byte[] rhs) {
- if (comparison != 0) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null) {
- comparison = -1;
- return this;
- }
- if (rhs == null) {
- comparison = +1;
- return this;
- }
- if (lhs.length != rhs.length) {
- comparison = (lhs.length < rhs.length) ? -1 : +1;
- return this;
- }
- for (int i = 0; i < lhs.length && comparison == 0; i++) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * ==null, null is less than non-nullbuilder the deep comparison of
- * two double arrays.
- *
- *
- * @param lhs left-hand array
- * @param rhs right-hand array
- * @return this - used to chain append calls
- */
- public CompareToBuilder append(double[] lhs, double[] rhs) {
- if (comparison != 0) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null) {
- comparison = -1;
- return this;
- }
- if (rhs == null) {
- comparison = +1;
- return this;
- }
- if (lhs.length != rhs.length) {
- comparison = (lhs.length < rhs.length) ? -1 : +1;
- return this;
- }
- for (int i = 0; i < lhs.length && comparison == 0; i++) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * ==null, null is less than non-nullbuilder the deep comparison of
- * two float arrays.
- *
- *
- * @param lhs left-hand array
- * @param rhs right-hand array
- * @return this - used to chain append calls
- */
- public CompareToBuilder append(float[] lhs, float[] rhs) {
- if (comparison != 0) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null) {
- comparison = -1;
- return this;
- }
- if (rhs == null) {
- comparison = +1;
- return this;
- }
- if (lhs.length != rhs.length) {
- comparison = (lhs.length < rhs.length) ? -1 : +1;
- return this;
- }
- for (int i = 0; i < lhs.length && comparison == 0; i++) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * ==null, null is less than non-nullbuilder the deep comparison of
- * two boolean arrays.
- *
- *
- * @param lhs left-hand array
- * @param rhs right-hand array
- * @return this - used to chain append calls
- */
- public CompareToBuilder append(boolean[] lhs, boolean[] rhs) {
- if (comparison != 0) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null) {
- comparison = -1;
- return this;
- }
- if (rhs == null) {
- comparison = +1;
- return this;
- }
- if (lhs.length != rhs.length) {
- comparison = (lhs.length < rhs.length) ? -1 : +1;
- return this;
- }
- for (int i = 0; i < lhs.length && comparison == 0; i++) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Returns a negative integer, a positive integer, or zero as
- * the ==null, null is less than non-nullbuilder has judged the "left-hand" side
- * as less than, greater than, or equal to the "right-hand"
- * side.
- *
- * @return final comparison result
- */
- public int toComparison() {
- return comparison;
- }
-
- /**
- * Returns a negative integer, a positive integer, or zero as
- * the builder has judged the "left-hand" side
- * as less than, greater than, or equal to the "right-hand"
- * side.
- *
- * @return final comparison result
- *
- * @since 3.0
- */
- public Integer build() {
- return Integer.valueOf(toComparison());
- }
-}
-
+/*
+ * 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.commons.lang3.builder;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.Comparator;
+
+import org.apache.commons.lang3.ArrayUtils;
+
+/**
+ * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods.
+ *
+ * It is consistent with equals(Object) and
+ * hashcode() built with {@link EqualsBuilder} and
+ * {@link HashCodeBuilder}.
Two Objects that compare equal using equals(Object) should normally
+ * also compare equal using compareTo(Object).
All relevant fields should be included in the calculation of the
+ * comparison. Derived fields may be ignored. The same fields, in the same
+ * order, should be used in both compareTo(Object) and
+ * equals(Object).
To use this class write code as follows:
+ * + *
+ * public class MyClass {
+ * String field1;
+ * int field2;
+ * boolean field3;
+ *
+ * ...
+ *
+ * public int compareTo(Object o) {
+ * MyClass myClass = (MyClass) o;
+ * return new CompareToBuilder()
+ * .appendSuper(super.compareTo(o)
+ * .append(this.field1, myClass.field1)
+ * .append(this.field2, myClass.field2)
+ * .append(this.field3, myClass.field3)
+ * .toComparison();
+ * }
+ * }
+ *
+ *
+ * Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use
+ * reflection to determine the fields to append. Because fields can be private,
+ * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to
+ * bypass normal access control checks. This will fail under a security manager,
+ * unless the appropriate permissions are set up correctly. It is also
+ * slower than appending explicitly.
A typical implementation of compareTo(Object) using
+ * reflectionCompare looks like:
+ * public int compareTo(Object o) {
+ * return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ *
+ *
+ * @see java.lang.Comparable
+ * @see java.lang.Object#equals(Object)
+ * @see java.lang.Object#hashCode()
+ * @see EqualsBuilder
+ * @see HashCodeBuilder
+ * @since 1.0
+ * @version $Id: CompareToBuilder.java 1090813 2011-04-10 15:03:23Z mbenson $
+ */
+public class CompareToBuilder implements BuilderConstructor for CompareToBuilder.
+ * + *Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.
+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *Compares two Objects via reflection.
Fields can be private, thus AccessibleObject.setAccessible
+ * is used to bypass normal access control checks. This will fail under a
+ * security manager unless the appropriate permissions are set.
If both lhs and rhs are null,
+ * they are considered equal.
lhs
+ * is less than, equal to, or greater than rhs
+ * @throws NullPointerException if either (but not both) parameters are
+ * null
+ * @throws ClassCastException if rhs is not assignment-compatible
+ * with lhs
+ */
+ public static int reflectionCompare(Object lhs, Object rhs) {
+ return reflectionCompare(lhs, rhs, false, null);
+ }
+
+ /**
+ * Compares two Objects via reflection.
Fields can be private, thus AccessibleObject.setAccessible
+ * is used to bypass normal access control checks. This will fail under a
+ * security manager unless the appropriate permissions are set.
compareTransients is true,
+ * compares transient members. Otherwise ignores them, as they
+ * are likely derived fields.If both lhs and rhs are null,
+ * they are considered equal.
lhs
+ * is less than, equal to, or greater than rhs
+ * @throws NullPointerException if either lhs or rhs
+ * (but not both) is null
+ * @throws ClassCastException if rhs is not assignment-compatible
+ * with lhs
+ */
+ public static int reflectionCompare(Object lhs, Object rhs, boolean compareTransients) {
+ return reflectionCompare(lhs, rhs, compareTransients, null);
+ }
+
+ /**
+ * Compares two Objects via reflection.
Fields can be private, thus AccessibleObject.setAccessible
+ * is used to bypass normal access control checks. This will fail under a
+ * security manager unless the appropriate permissions are set.
compareTransients is true,
+ * compares transient members. Otherwise ignores them, as they
+ * are likely derived fields.If both lhs and rhs are null,
+ * they are considered equal.
lhs
+ * is less than, equal to, or greater than rhs
+ * @throws NullPointerException if either lhs or rhs
+ * (but not both) is null
+ * @throws ClassCastException if rhs is not assignment-compatible
+ * with lhs
+ * @since 2.2
+ */
+ public static int reflectionCompare(Object lhs, Object rhs, CollectionCompares two Objects via reflection.
Fields can be private, thus AccessibleObject.setAccessible
+ * is used to bypass normal access control checks. This will fail under a
+ * security manager unless the appropriate permissions are set.
compareTransients is true,
+ * compares transient members. Otherwise ignores them, as they
+ * are likely derived fields.If both lhs and rhs are null,
+ * they are considered equal.
lhs
+ * is less than, equal to, or greater than rhs
+ * @throws NullPointerException if either lhs or rhs
+ * (but not both) is null
+ * @throws ClassCastException if rhs is not assignment-compatible
+ * with lhs
+ * @since 2.2
+ */
+ public static int reflectionCompare(Object lhs, Object rhs, String... excludeFields) {
+ return reflectionCompare(lhs, rhs, false, null, excludeFields);
+ }
+
+ /**
+ * Compares two Objects via reflection.
Fields can be private, thus AccessibleObject.setAccessible
+ * is used to bypass normal access control checks. This will fail under a
+ * security manager unless the appropriate permissions are set.
compareTransients is true,
+ * compares transient members. Otherwise ignores them, as they
+ * are likely derived fields.reflectUpToClass.
+ * If reflectUpToClass is null, compares all superclass fields.If both lhs and rhs are null,
+ * they are considered equal.
lhs
+ * is less than, equal to, or greater than rhs
+ * @throws NullPointerException if either lhs or rhs
+ * (but not both) is null
+ * @throws ClassCastException if rhs is not assignment-compatible
+ * with lhs
+ * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class))
+ */
+ public static int reflectionCompare(
+ Object lhs,
+ Object rhs,
+ boolean compareTransients,
+ Class> reflectUpToClass,
+ String... excludeFields) {
+
+ if (lhs == rhs) {
+ return 0;
+ }
+ if (lhs == null || rhs == null) {
+ throw new NullPointerException();
+ }
+ Class> lhsClazz = lhs.getClass();
+ if (!lhsClazz.isInstance(rhs)) {
+ throw new ClassCastException();
+ }
+ CompareToBuilder compareToBuilder = new CompareToBuilder();
+ reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields);
+ while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) {
+ lhsClazz = lhsClazz.getSuperclass();
+ reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields);
+ }
+ return compareToBuilder.toComparison();
+ }
+
+ /**
+ * Appends to builder the comparison of lhs
+ * to rhs using the fields defined in clazz.
Class that defines fields to be compared
+ * @param builder CompareToBuilder to append to
+ * @param useTransients whether to compare transient fields
+ * @param excludeFields fields to exclude
+ */
+ private static void reflectionAppend(
+ Object lhs,
+ Object rhs,
+ Class> clazz,
+ CompareToBuilder builder,
+ boolean useTransients,
+ String[] excludeFields) {
+
+ Field[] fields = clazz.getDeclaredFields();
+ AccessibleObject.setAccessible(fields, true);
+ for (int i = 0; i < fields.length && builder.comparison == 0; i++) {
+ Field f = fields[i];
+ if (!ArrayUtils.contains(excludeFields, f.getName())
+ && (f.getName().indexOf('$') == -1)
+ && (useTransients || !Modifier.isTransient(f.getModifiers()))
+ && (!Modifier.isStatic(f.getModifiers()))) {
+ try {
+ builder.append(f.get(lhs), f.get(rhs));
+ } catch (IllegalAccessException e) {
+ // This can't happen. Would get a Security exception instead.
+ // Throw a runtime exception in case the impossible happens.
+ throw new InternalError("Unexpected IllegalAccessException");
+ }
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Appends to the builder the compareTo(Object)
+ * result of the superclass.
super.compareTo(Object)
+ * @return this - used to chain append calls
+ * @since 2.0
+ */
+ public CompareToBuilder appendSuper(int superCompareTo) {
+ if (comparison != 0) {
+ return this;
+ }
+ comparison = superCompareTo;
+ return this;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Appends to the builder the comparison of
+ * two Objects.
lhs == rhslhs or rhs is null,
+ * a null object is less than a non-null objectlhs must either be an array or implement {@link Comparable}.
rhs is not assignment-compatible
+ * with lhs
+ */
+ public CompareToBuilder append(Object lhs, Object rhs) {
+ return append(lhs, rhs, null);
+ }
+
+ /**
+ * Appends to the builder the comparison of
+ * two Objects.
lhs == rhslhs or rhs is null,
+ * a null object is less than a non-null objectIf lhs is an array, array comparison methods will be used.
+ * Otherwise comparator will be used to compare the objects.
+ * If comparator is null, lhs must
+ * implement {@link Comparable} instead.
Comparator used to compare the objects,
+ * null means treat lhs as Comparable
+ * @return this - used to chain append calls
+ * @throws ClassCastException if rhs is not assignment-compatible
+ * with lhs
+ * @since 2.0
+ */
+ public CompareToBuilder append(Object lhs, Object rhs, Comparator> comparator) {
+ if (comparison != 0) {
+ return this;
+ }
+ if (lhs == rhs) {
+ return this;
+ }
+ if (lhs == null) {
+ comparison = -1;
+ return this;
+ }
+ if (rhs == null) {
+ comparison = +1;
+ return this;
+ }
+ if (lhs.getClass().isArray()) {
+ // switch on type of array, to dispatch to the correct handler
+ // handles multi dimensional arrays
+ // throws a ClassCastException if rhs is not the correct array type
+ if (lhs instanceof long[]) {
+ append((long[]) lhs, (long[]) rhs);
+ } else if (lhs instanceof int[]) {
+ append((int[]) lhs, (int[]) rhs);
+ } else if (lhs instanceof short[]) {
+ append((short[]) lhs, (short[]) rhs);
+ } else if (lhs instanceof char[]) {
+ append((char[]) lhs, (char[]) rhs);
+ } else if (lhs instanceof byte[]) {
+ append((byte[]) lhs, (byte[]) rhs);
+ } else if (lhs instanceof double[]) {
+ append((double[]) lhs, (double[]) rhs);
+ } else if (lhs instanceof float[]) {
+ append((float[]) lhs, (float[]) rhs);
+ } else if (lhs instanceof boolean[]) {
+ append((boolean[]) lhs, (boolean[]) rhs);
+ } else {
+ // not an array of primitives
+ // throws a ClassCastException if rhs is not an array
+ append((Object[]) lhs, (Object[]) rhs, comparator);
+ }
+ } else {
+ // the simple case, not an array, just test the element
+ if (comparator == null) {
+ @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc
+ final Comparablebuilder the comparison of
+ * two longs.
+ *
+ * @param lhs left-hand value
+ * @param rhs right-hand value
+ * @return this - used to chain append calls
+ */
+ public CompareToBuilder append(long lhs, long rhs) {
+ if (comparison != 0) {
+ return this;
+ }
+ comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
+ return this;
+ }
+
+ /**
+ * Appends to the builder the comparison of
+ * two ints.
+ *
+ * @param lhs left-hand value
+ * @param rhs right-hand value
+ * @return this - used to chain append calls
+ */
+ public CompareToBuilder append(int lhs, int rhs) {
+ if (comparison != 0) {
+ return this;
+ }
+ comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
+ return this;
+ }
+
+ /**
+ * Appends to the builder the comparison of
+ * two shorts.
+ *
+ * @param lhs left-hand value
+ * @param rhs right-hand value
+ * @return this - used to chain append calls
+ */
+ public CompareToBuilder append(short lhs, short rhs) {
+ if (comparison != 0) {
+ return this;
+ }
+ comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
+ return this;
+ }
+
+ /**
+ * Appends to the builder the comparison of
+ * two chars.
+ *
+ * @param lhs left-hand value
+ * @param rhs right-hand value
+ * @return this - used to chain append calls
+ */
+ public CompareToBuilder append(char lhs, char rhs) {
+ if (comparison != 0) {
+ return this;
+ }
+ comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
+ return this;
+ }
+
+ /**
+ * Appends to the builder the comparison of
+ * two bytes.
+ *
+ * @param lhs left-hand value
+ * @param rhs right-hand value
+ * @return this - used to chain append calls
+ */
+ public CompareToBuilder append(byte lhs, byte rhs) {
+ if (comparison != 0) {
+ return this;
+ }
+ comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
+ return this;
+ }
+
+ /**
+ * Appends to the builder the comparison of
+ * two doubles.
This handles NaNs, Infinities, and -0.0.
It is compatible with the hash code generated by
+ * HashCodeBuilder.
Appends to the builder the comparison of
+ * two floats.
This handles NaNs, Infinities, and -0.0.
It is compatible with the hash code generated by
+ * HashCodeBuilder.
builder the comparison of
+ * two booleanss.
+ *
+ * @param lhs left-hand value
+ * @param rhs right-hand value
+ * @return this - used to chain append calls
+ */
+ public CompareToBuilder append(boolean lhs, boolean rhs) {
+ if (comparison != 0) {
+ return this;
+ }
+ if (lhs == rhs) {
+ return this;
+ }
+ if (lhs == false) {
+ comparison = -1;
+ } else {
+ comparison = +1;
+ }
+ return this;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Appends to the builder the deep comparison of
+ * two Object arrays.
==null, null is less than non-nullThis method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException ifrhs is not assignment-compatible
+ * with lhs
+ */
+ public CompareToBuilder append(Object[] lhs, Object[] rhs) {
+ return append(lhs, rhs, null);
+ }
+
+ /**
+ * Appends to the builder the deep comparison of
+ * two Object arrays.
==null, null is less than non-nullThis method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparatorComparator to use to compare the array elements,
+ * null means to treat lhs elements as Comparable.
+ * @return this - used to chain append calls
+ * @throws ClassCastException if rhs is not assignment-compatible
+ * with lhs
+ * @since 2.0
+ */
+ public CompareToBuilder append(Object[] lhs, Object[] rhs, Comparator> comparator) {
+ if (comparison != 0) {
+ return this;
+ }
+ if (lhs == rhs) {
+ return this;
+ }
+ if (lhs == null) {
+ comparison = -1;
+ return this;
+ }
+ if (rhs == null) {
+ comparison = +1;
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ comparison = (lhs.length < rhs.length) ? -1 : +1;
+ return this;
+ }
+ for (int i = 0; i < lhs.length && comparison == 0; i++) {
+ append(lhs[i], rhs[i], comparator);
+ }
+ return this;
+ }
+
+ /**
+ * Appends to the builder the deep comparison of
+ * two long arrays.
==null, null is less than non-nullAppends to the builder the deep comparison of
+ * two int arrays.
==null, null is less than non-nullAppends to the builder the deep comparison of
+ * two short arrays.
==null, null is less than non-nullAppends to the builder the deep comparison of
+ * two char arrays.
==null, null is less than non-nullAppends to the builder the deep comparison of
+ * two byte arrays.
==null, null is less than non-nullAppends to the builder the deep comparison of
+ * two double arrays.
==null, null is less than non-nullAppends to the builder the deep comparison of
+ * two float arrays.
==null, null is less than non-nullAppends to the builder the deep comparison of
+ * two boolean arrays.
==null, null is less than non-nullbuilder has judged the "left-hand" side
+ * as less than, greater than, or equal to the "right-hand"
+ * side.
+ *
+ * @return final comparison result
+ */
+ public int toComparison() {
+ return comparison;
+ }
+
+ /**
+ * Returns a negative integer, a positive integer, or zero as
+ * the builder has judged the "left-hand" side
+ * as less than, greater than, or equal to the "right-hand"
+ * side.
+ *
+ * @return final comparison result
+ *
+ * @since 3.0
+ */
+ public Integer build() {
+ return Integer.valueOf(toComparison());
+ }
+}
+
diff --git a/src/org/apache/commons/lang3/builder/EqualsBuilder.java b/src/org/apache/commons/lang3/builder/EqualsBuilder.java
index d619495..2c8e5f9 100644
--- a/src/org/apache/commons/lang3/builder/EqualsBuilder.java
+++ b/src/org/apache/commons/lang3/builder/EqualsBuilder.java
@@ -1,944 +1,944 @@
-/*
- * 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.commons.lang3.builder;
-
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.commons.lang3.tuple.Pair;
-
-/**
- * Assists in implementing {@link Object#equals(Object)} methods.
- * - * This class provides methods to build a good equals method for any
- * class. It follows rules laid out in
- * Effective Java
- * , by Joshua Bloch. In particular the rule for comparing doubles,
- * floats, and arrays can be tricky. Also, making sure that
- * equals() and hashCode() are consistent can be
- * difficult.
Two Objects that compare as equals must generate the same hash code, - * but two Objects with the same hash code do not have to be equal.
- * - *All relevant fields should be included in the calculation of equals. - * Derived fields may be ignored. In particular, any field used in - * generating a hash code must be used in the equals method, and vice - * versa.
- * - *Typical use for the code is as follows:
- *
- * public boolean equals(Object obj) {
- * if (obj == null) { return false; }
- * if (obj == this) { return true; }
- * if (obj.getClass() != getClass()) {
- * return false;
- * }
- * MyClass rhs = (MyClass) obj;
- * return new EqualsBuilder()
- * .appendSuper(super.equals(obj))
- * .append(field1, rhs.field1)
- * .append(field2, rhs.field2)
- * .append(field3, rhs.field3)
- * .isEquals();
- * }
- *
- *
- * Alternatively, there is a method that uses reflection to determine
- * the fields to test. Because these fields are usually private, the method,
- * reflectionEquals, uses AccessibleObject.setAccessible to
- * change the visibility of the fields. This will fail under a security
- * manager, unless the appropriate permissions are set up correctly. It is
- * also slower than testing explicitly.
A typical invocation for this method would look like:
- *
- * public boolean equals(Object obj) {
- * return EqualsBuilder.reflectionEquals(this, obj);
- * }
- *
- *
- * @since 1.0
- * @version $Id: EqualsBuilder.java 1091531 2011-04-12 18:29:49Z ggregory $
- */
-public class EqualsBuilder implements Builder- * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops. - *
- * - * @since 3.0 - */ - private static final ThreadLocal- * Returns the registry of object pairs being traversed by the reflection - * methods in the current thread. - *
- * - * @return Set the registry of objects being traversed - * @since 3.0 - */ - static Set- * Converters value pair into a register pair. - *
- * - * @param lhsthis object
- * @param rhs the other object
- *
- * @return the pair
- */
- static Pair
- * Returns true if the registry contains the given object pair.
- * Used by the reflection methods to avoid infinite loops.
- * Objects might be swapped therefore a check is needed if the object pair
- * is registered in given or swapped order.
- *
this object to lookup in registry
- * @param rhs the other object to lookup on registry
- * @return boolean true if the registry contains the given object.
- * @since 3.0
- */
- static boolean isRegistered(Object lhs, Object rhs) {
- Set- * Registers the given object pair. - * Used by the reflection methods to avoid infinite loops. - *
- * - * @param lhsthis object to register
- * @param rhs the other object to register
- */
- static void register(Object lhs, Object rhs) {
- synchronized (EqualsBuilder.class) {
- if (getRegistry() == null) {
- REGISTRY.set(new HashSet- * Unregisters the given object pair. - *
- * - *
- * Used by the reflection methods to avoid infinite loops.
- *
- * @param lhs Constructor for EqualsBuilder. Starts off assuming that equals is This method uses reflection to determine if the two It uses Transient members will be not be tested, as they are likely derived
- * fields, and not part of the value of the Object. Static fields will not be tested. Superclass fields will be included. This method uses reflection to determine if the two It uses Transient members will be not be tested, as they are likely derived
- * fields, and not part of the value of the Object. Static fields will not be tested. Superclass fields will be included. This method uses reflection to determine if the two It uses If the TestTransients parameter is set to Static fields will not be tested. Superclass fields will be included. This method uses reflection to determine if the two It uses If the testTransients parameter is set to Static fields will not be included. Superclass fields will be appended
- * up to and including the specified superclass. A null superclass is treated
- * as java.lang.Object. Appends the fields and values defined by the given object of the
- * given Class. Adds the result of Test if two
- * Test if two Test if two Test if two Test if two Test if two Test if two This handles NaNs, Infinities, and It is compatible with the hash code generated by
- * Test if two This handles NaNs, Infinities, and It is compatible with the hash code generated by
- * Test if two Performs a deep comparison of two This also will be called for the top level of
- * multi-dimensional, ragged, and multi-typed arrays. Deep comparison of array of The method {@link #append(long, long)} is used. Deep comparison of array of The method {@link #append(int, int)} is used. Deep comparison of array of The method {@link #append(short, short)} is used. Deep comparison of array of The method {@link #append(char, char)} is used. Deep comparison of array of The method {@link #append(byte, byte)} is used. Deep comparison of array of The method {@link #append(double, double)} is used. Deep comparison of array of The method {@link #append(float, float)} is used. Deep comparison of array of The method {@link #append(boolean, boolean)} is used. Returns Returns Assists in implementing {@link Object#equals(Object)} methods. This class provides methods to build a good equals method for any
+ * class. It follows rules laid out in
+ * Effective Java
+ * , by Joshua Bloch. In particular the rule for comparing Two Objects that compare as equals must generate the same hash code,
+ * but two Objects with the same hash code do not have to be equal. All relevant fields should be included in the calculation of equals.
+ * Derived fields may be ignored. In particular, any field used in
+ * generating a hash code must be used in the equals method, and vice
+ * versa. Typical use for the code is as follows: Alternatively, there is a method that uses reflection to determine
+ * the fields to test. Because these fields are usually private, the method,
+ * A typical invocation for this method would look like:
+ * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops.
+ *
+ * Returns the registry of object pairs being traversed by the reflection
+ * methods in the current thread.
+ *
+ * Converters value pair into a register pair.
+ *
+ * Returns
+ * Registers the given object pair.
+ * Used by the reflection methods to avoid infinite loops.
+ *
+ * Unregisters the given object pair.
+ *
+ * Used by the reflection methods to avoid infinite loops.
+ *
+ * @param lhs Constructor for EqualsBuilder. Starts off assuming that equals is This method uses reflection to determine if the two It uses Transient members will be not be tested, as they are likely derived
+ * fields, and not part of the value of the Object. Static fields will not be tested. Superclass fields will be included. This method uses reflection to determine if the two It uses Transient members will be not be tested, as they are likely derived
+ * fields, and not part of the value of the Object. Static fields will not be tested. Superclass fields will be included. This method uses reflection to determine if the two It uses If the TestTransients parameter is set to Static fields will not be tested. Superclass fields will be included. This method uses reflection to determine if the two It uses If the testTransients parameter is set to Static fields will not be included. Superclass fields will be appended
+ * up to and including the specified superclass. A null superclass is treated
+ * as java.lang.Object. Appends the fields and values defined by the given object of the
+ * given Class. Adds the result of Test if two
+ * Test if two Test if two Test if two Test if two Test if two Test if two This handles NaNs, Infinities, and It is compatible with the hash code generated by
+ * Test if two This handles NaNs, Infinities, and It is compatible with the hash code generated by
+ * Test if two Performs a deep comparison of two This also will be called for the top level of
+ * multi-dimensional, ragged, and multi-typed arrays. Deep comparison of array of The method {@link #append(long, long)} is used. Deep comparison of array of The method {@link #append(int, int)} is used. Deep comparison of array of The method {@link #append(short, short)} is used. Deep comparison of array of The method {@link #append(char, char)} is used. Deep comparison of array of The method {@link #append(byte, byte)} is used. Deep comparison of array of The method {@link #append(double, double)} is used. Deep comparison of array of The method {@link #append(float, float)} is used. Deep comparison of array of The method {@link #append(boolean, boolean)} is used. Returns Returns
- * Assists in implementing {@link Object#hashCode()} methods.
- *
- * This class enables a good
- * The following is the approach taken. When appending a data field, the current total is multiplied by the
- * multiplier then a relevant value
- * for that data type is added. For example, if the current hashCode is 17, and the multiplier is 37, then
- * appending the integer 45 will create a hashcode of 674, namely 17 * 37 + 45.
- *
- * All relevant fields from the object should be included in the
- * To use this class write code as follows:
- *
- * If required, the superclass
- * Alternatively, there is a method that uses reflection to determine the fields to test. Because these fields are
- * usually private, the method,
- * A typical invocation for this method would look like:
- *
- * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops.
- *
- * Returns the registry of objects being traversed by the reflection methods in the current thread.
- *
- * Returns
- * Appends the fields and values defined by the given object of the given
- * This method uses reflection to build a valid hash code.
- *
- * It uses
- * Transient members will be not be used, as they are likely derived fields, and not part of the value of the
- *
- * Static fields will not be tested. Superclass fields will be included.
- *
- * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
- * however this is not vital. Prime numbers are preferred, especially for the multiplier.
- *
- * This method uses reflection to build a valid hash code.
- *
- * It uses
- * If the TestTransients parameter is set to
- * Static fields will not be tested. Superclass fields will be included.
- *
- * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
- * however this is not vital. Prime numbers are preferred, especially for the multiplier.
- *
- * This method uses reflection to build a valid hash code.
- *
- * It uses
- * If the TestTransients parameter is set to
- * Static fields will not be included. Superclass fields will be included up to and including the specified
- * superclass. A null superclass is treated as java.lang.Object.
- *
- * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
- * however this is not vital. Prime numbers are preferred, especially for the multiplier.
- *
- * This method uses reflection to build a valid hash code.
- *
- * This constructor uses two hard coded choices for the constants needed to build a hash code.
- *
- * It uses
- * If the TestTransients parameter is set to
- * Static fields will not be tested. Superclass fields will be included.
- *
- * This method uses reflection to build a valid hash code.
- *
- * This constructor uses two hard coded choices for the constants needed to build a hash code.
- *
- * It uses
- * Transient members will be not be used, as they are likely derived fields, and not part of the value of the
- *
- * Static fields will not be tested. Superclass fields will be included.
- *
- * This method uses reflection to build a valid hash code.
- *
- * This constructor uses two hard coded choices for the constants needed to build a hash code.
- *
- * It uses
- * Transient members will be not be used, as they are likely derived fields, and not part of the value of the
- *
- * Static fields will not be tested. Superclass fields will be included.
- *
- * Registers the given object. Used by the reflection methods to avoid infinite loops.
- *
- * Unregisters the given object.
- *
- * Used by the reflection methods to avoid infinite loops.
- *
- * @param value
- * The object to unregister.
- * @since 2.3
- */
- static void unregister(Object value) {
- Set
- * Uses two hard coded choices for the constants needed to build a
- * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
- * however this is not vital.
- *
- * Prime numbers are preferred, especially for the multiplier.
- *
- * Append a
- * This adds
- * This is in contrast to the standard
- * This is in accordance with the
- * Append a
- * Append a
- * Append a
- * Append a
- * Append a
- * Append a
- * Append a
- * Append a
- * Append a
- * Append a
- * Append a
- * Append a
- * Append a
- * Append a
- * Append a
- * Append a
- * Append a
- * Adds the result of super.hashCode() to this builder.
- *
- * Return the computed
- * The computed
+ * Assists in implementing {@link Object#hashCode()} methods.
+ *
+ * This class enables a good
+ * The following is the approach taken. When appending a data field, the current total is multiplied by the
+ * multiplier then a relevant value
+ * for that data type is added. For example, if the current hashCode is 17, and the multiplier is 37, then
+ * appending the integer 45 will create a hashcode of 674, namely 17 * 37 + 45.
+ *
+ * All relevant fields from the object should be included in the
+ * To use this class write code as follows:
+ *
+ * If required, the superclass
+ * Alternatively, there is a method that uses reflection to determine the fields to test. Because these fields are
+ * usually private, the method,
+ * A typical invocation for this method would look like:
+ *
+ * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops.
+ *
+ * Returns the registry of objects being traversed by the reflection methods in the current thread.
+ *
+ * Returns
+ * Appends the fields and values defined by the given object of the given
+ * This method uses reflection to build a valid hash code.
+ *
+ * It uses
+ * Transient members will be not be used, as they are likely derived fields, and not part of the value of the
+ *
+ * Static fields will not be tested. Superclass fields will be included.
+ *
+ * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
+ * however this is not vital. Prime numbers are preferred, especially for the multiplier.
+ *
+ * This method uses reflection to build a valid hash code.
+ *
+ * It uses
+ * If the TestTransients parameter is set to
+ * Static fields will not be tested. Superclass fields will be included.
+ *
+ * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
+ * however this is not vital. Prime numbers are preferred, especially for the multiplier.
+ *
+ * This method uses reflection to build a valid hash code.
+ *
+ * It uses
+ * If the TestTransients parameter is set to
+ * Static fields will not be included. Superclass fields will be included up to and including the specified
+ * superclass. A null superclass is treated as java.lang.Object.
+ *
+ * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
+ * however this is not vital. Prime numbers are preferred, especially for the multiplier.
+ *
+ * This method uses reflection to build a valid hash code.
+ *
+ * This constructor uses two hard coded choices for the constants needed to build a hash code.
+ *
+ * It uses
+ * If the TestTransients parameter is set to
+ * Static fields will not be tested. Superclass fields will be included.
+ *
+ * This method uses reflection to build a valid hash code.
+ *
+ * This constructor uses two hard coded choices for the constants needed to build a hash code.
+ *
+ * It uses
+ * Transient members will be not be used, as they are likely derived fields, and not part of the value of the
+ *
+ * Static fields will not be tested. Superclass fields will be included.
+ *
+ * This method uses reflection to build a valid hash code.
+ *
+ * This constructor uses two hard coded choices for the constants needed to build a hash code.
+ *
+ * It uses
+ * Transient members will be not be used, as they are likely derived fields, and not part of the value of the
+ *
+ * Static fields will not be tested. Superclass fields will be included.
+ *
+ * Registers the given object. Used by the reflection methods to avoid infinite loops.
+ *
+ * Unregisters the given object.
+ *
+ * Used by the reflection methods to avoid infinite loops.
+ *
+ * @param value
+ * The object to unregister.
+ * @since 2.3
+ */
+ static void unregister(Object value) {
+ Set
+ * Uses two hard coded choices for the constants needed to build a
+ * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
+ * however this is not vital.
+ *
+ * Prime numbers are preferred, especially for the multiplier.
+ *
+ * Append a
+ * This adds
+ * This is in contrast to the standard
+ * This is in accordance with the
+ * Append a
+ * Append a
+ * Append a
+ * Append a
+ * Append a
+ * Append a
+ * Append a
+ * Append a
+ * Append a
+ * Append a
+ * Append a
+ * Append a
+ * Append a
+ * Append a
+ * Append a
+ * Append a
+ * Append a
+ * Adds the result of super.hashCode() to this builder.
+ *
+ * Return the computed
+ * The computed
- * Assists in implementing {@link Object#toString()} methods using reflection.
- *
- * This class uses reflection to determine the fields to append. Because these fields are usually private, the class
- * uses {@link java.lang.reflect.AccessibleObject#setAccessible(java.lang.reflect.AccessibleObject[], boolean)} to
- * change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions are
- * set up correctly.
- *
- * A typical invocation for this method would look like:
- *
- * You can also use the builder to debug 3rd party objects:
- *
- * A subclass can control field output by overriding the methods:
- *
- * For example, this method does not include the
- * The exact format of the
- * Builds a
- * It uses
- * Transient members will be not be included, as they are likely derived. Static fields will not be included.
- * Superclass fields will be appended.
- *
- * Builds a
- * It uses
- * Transient members will be not be included, as they are likely derived. Static fields will not be included.
- * Superclass fields will be appended.
- *
- * If the style is
- * Builds a
- * It uses
- * If the
- * Static fields will not be included. Superclass fields will be appended.
- *
- * If the style is
- * Builds a
- * It uses
- * If the
- * If the
- * Static fields will not be included. Superclass fields will be appended.
- *
- * If the style is
- * Builds a
- * It uses
- * If the
- * If the
- * Superclass fields will be appended up to and including the specified superclass. A null superclass is treated as
- *
- * If the style is
- * Constructor.
- *
- * This constructor outputs using the default style set with
- * Constructor.
- *
- * If the style is
- * Constructor.
- *
- * If the style is
- * If the buffer is
- * Appends the fields and values defined by the given object of the given Class.
- *
- * If a cycle is detected as an object is "toString()'ed", such an object is rendered as if
- *
- * Gets the last super class to stop appending fields for.
- *
- * Calls
- * Gets whether or not to append static fields.
- *
- * Gets whether or not to append transient fields.
- *
- * Append to the
- * Sets whether or not to append static fields.
- *
- * Sets whether or not to append transient fields.
- *
- * Sets the last super class to stop appending fields for.
- *
- * Gets the String built by this builder.
- *
+ * Assists in implementing {@link Object#toString()} methods using reflection.
+ *
+ * This class uses reflection to determine the fields to append. Because these fields are usually private, the class
+ * uses {@link java.lang.reflect.AccessibleObject#setAccessible(java.lang.reflect.AccessibleObject[], boolean)} to
+ * change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions are
+ * set up correctly.
+ *
+ * A typical invocation for this method would look like:
+ *
+ * You can also use the builder to debug 3rd party objects:
+ *
+ * A subclass can control field output by overriding the methods:
+ *
+ * For example, this method does not include the
+ * The exact format of the
+ * Builds a
+ * It uses
+ * Transient members will be not be included, as they are likely derived. Static fields will not be included.
+ * Superclass fields will be appended.
+ *
+ * Builds a
+ * It uses
+ * Transient members will be not be included, as they are likely derived. Static fields will not be included.
+ * Superclass fields will be appended.
+ *
+ * If the style is
+ * Builds a
+ * It uses
+ * If the
+ * Static fields will not be included. Superclass fields will be appended.
+ *
+ * If the style is
+ * Builds a
+ * It uses
+ * If the
+ * If the
+ * Static fields will not be included. Superclass fields will be appended.
+ *
+ * If the style is
+ * Builds a
+ * It uses
+ * If the
+ * If the
+ * Superclass fields will be appended up to and including the specified superclass. A null superclass is treated as
+ *
+ * If the style is
+ * Constructor.
+ *
+ * This constructor outputs using the default style set with
+ * Constructor.
+ *
+ * If the style is
+ * Constructor.
+ *
+ * If the style is
+ * If the buffer is
+ * Appends the fields and values defined by the given object of the given Class.
+ *
+ * If a cycle is detected as an object is "toString()'ed", such an object is rendered as if
+ *
+ * Gets the last super class to stop appending fields for.
+ *
+ * Calls
+ * Gets whether or not to append static fields.
+ *
+ * Gets whether or not to append transient fields.
+ *
+ * Append to the
+ * Sets whether or not to append static fields.
+ *
+ * Sets whether or not to append transient fields.
+ *
+ * Sets the last super class to stop appending fields for.
+ *
+ * Gets the String built by this builder.
+ * Works with {@link ToStringBuilder} to create a This class is intended to be used as a singleton.
- * There is no need to instantiate a new style each time.
- * Simply instantiate the class once, customize the values as required, and
- * store the result in a public static final variable for the rest of the
- * program to access. Constructor. Gets whether to use the class name. Sets whether to use the class name. Gets whether to output short or long class names. Sets whether to output short or long class names. Gets whether to use the identity hash code. Sets whether to use the identity hash code. Gets whether to use the field names passed in. Sets whether to use the field names passed in. Gets whether to use full detail when the caller doesn't
- * specify. Sets whether to use full detail when the caller doesn't
- * specify. Gets whether to output array content detail. Sets whether to output array content detail. Gets the array start text. Sets the array start text. Gets the array end text. Sets the array end text. Gets the array separator text. Sets the array separator text. Gets the content start text. Sets the content start text. Gets the content end text. Sets the content end text. Gets the field name value separator text. Sets the field name value separator text. Gets the field separator text. Sets the field separator text. Gets whether the field separator should be added at the start
- * of each buffer. Sets whether the field separator should be added at the start
- * of each buffer. Gets whether the field separator should be added at the end
- * of each buffer. Sets whether the field separator should be added at the end
- * of each buffer. Gets the text to output when Sets the text to output when Gets the text to output when a This is output before the size value. Sets the start text to output when a This is output before the size value. This is output after the size value. Sets the end text to output when a This is output after the size value. Gets the start text to output when an This is output before the size value. Sets the start text to output when an This is output before the size value. Gets the end text to output when an This is output after the size value. Sets the end text to output when an This is output after the size value. Works with {@link ToStringBuilder} to create a This class is intended to be used as a singleton.
+ * There is no need to instantiate a new style each time.
+ * Simply instantiate the class once, customize the values as required, and
+ * store the result in a public static final variable for the rest of the
+ * program to access. Constructor. Gets whether to use the class name. Sets whether to use the class name. Gets whether to output short or long class names. Sets whether to output short or long class names. Gets whether to use the identity hash code. Sets whether to use the identity hash code. Gets whether to use the field names passed in. Sets whether to use the field names passed in. Gets whether to use full detail when the caller doesn't
+ * specify. Sets whether to use full detail when the caller doesn't
+ * specify. Gets whether to output array content detail. Sets whether to output array content detail. Gets the array start text. Sets the array start text. Gets the array end text. Sets the array end text. Gets the array separator text. Sets the array separator text. Gets the content start text. Sets the content start text. Gets the content end text. Sets the content end text. Gets the field name value separator text. Sets the field name value separator text. Gets the field separator text. Sets the field separator text. Gets whether the field separator should be added at the start
+ * of each buffer. Sets whether the field separator should be added at the start
+ * of each buffer. Gets whether the field separator should be added at the end
+ * of each buffer. Sets whether the field separator should be added at the end
+ * of each buffer. Gets the text to output when Sets the text to output when Gets the text to output when a This is output before the size value. Sets the start text to output when a This is output before the size value. this object to unregister
- * @param rhs the other object to unregister
- * @since 3.0
- */
- static void unregister(Object lhs, Object rhs) {
- Settrue.
- */
- private boolean isEquals = true;
-
- /**
- * true.Objects
- * are equal.AccessibleObject.setAccessible to gain access to private
- * fields. This means that it will throw a security exception if run under
- * a security manager, if the permissions are not set up correctly. It is also
- * not as efficient as testing explicitly.this object
- * @param rhs the other object
- * @param excludeFields Collection of String field names to exclude from testing
- * @return true if the two Objects have tested equals.
- */
- public static boolean reflectionEquals(Object lhs, Object rhs, CollectionObjects
- * are equal.AccessibleObject.setAccessible to gain access to private
- * fields. This means that it will throw a security exception if run under
- * a security manager, if the permissions are not set up correctly. It is also
- * not as efficient as testing explicitly.this object
- * @param rhs the other object
- * @param excludeFields array of field names to exclude from testing
- * @return true if the two Objects have tested equals.
- */
- public static boolean reflectionEquals(Object lhs, Object rhs, String... excludeFields) {
- return reflectionEquals(lhs, rhs, false, null, excludeFields);
- }
-
- /**
- * Objects
- * are equal.AccessibleObject.setAccessible to gain access to private
- * fields. This means that it will throw a security exception if run under
- * a security manager, if the permissions are not set up correctly. It is also
- * not as efficient as testing explicitly.true, transient
- * members will be tested, otherwise they are ignored, as they are likely
- * derived fields, and not part of the value of the Object.this object
- * @param rhs the other object
- * @param testTransients whether to include transient fields
- * @return true if the two Objects have tested equals.
- */
- public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients) {
- return reflectionEquals(lhs, rhs, testTransients, null);
- }
-
- /**
- * Objects
- * are equal.AccessibleObject.setAccessible to gain access to private
- * fields. This means that it will throw a security exception if run under
- * a security manager, if the permissions are not set up correctly. It is also
- * not as efficient as testing explicitly.true, transient
- * members will be tested, otherwise they are ignored, as they are likely
- * derived fields, and not part of the value of the Object.this object
- * @param rhs the other object
- * @param testTransients whether to include transient fields
- * @param reflectUpToClass the superclass to reflect up to (inclusive),
- * may be null
- * @param excludeFields array of field names to exclude from testing
- * @return true if the two Objects have tested equals.
- * @since 2.0
- */
- public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class> reflectUpToClass,
- String... excludeFields) {
- if (lhs == rhs) {
- return true;
- }
- if (lhs == null || rhs == null) {
- return false;
- }
- // Find the leaf class since there may be transients in the leaf
- // class or in classes between the leaf and root.
- // If we are not testing transients or a subclass has no ivars,
- // then a subclass can test equals to a superclass.
- Class> lhsClass = lhs.getClass();
- Class> rhsClass = rhs.getClass();
- Class> testClass;
- if (lhsClass.isInstance(rhs)) {
- testClass = lhsClass;
- if (!rhsClass.isInstance(lhs)) {
- // rhsClass is a subclass of lhsClass
- testClass = rhsClass;
- }
- } else if (rhsClass.isInstance(lhs)) {
- testClass = rhsClass;
- if (!lhsClass.isInstance(rhs)) {
- // lhsClass is a subclass of rhsClass
- testClass = lhsClass;
- }
- } else {
- // The two classes are not related.
- return false;
- }
- EqualsBuilder equalsBuilder = new EqualsBuilder();
- try {
- reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
- while (testClass.getSuperclass() != null && testClass != reflectUpToClass) {
- testClass = testClass.getSuperclass();
- reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
- }
- } catch (IllegalArgumentException e) {
- // In this case, we tried to test a subclass vs. a superclass and
- // the subclass has ivars or the ivars are transient and
- // we are testing transients.
- // If a subclass has ivars that we are trying to test them, we get an
- // exception and we know that the objects are not equal.
- return false;
- }
- return equalsBuilder.isEquals();
- }
-
- /**
- * super.equals() to this builder.super.equals()
- * @return EqualsBuilder - used to chain calls.
- * @since 2.0
- */
- public EqualsBuilder appendSuper(boolean superEquals) {
- if (isEquals == false) {
- return this;
- }
- isEquals = superEquals;
- return this;
- }
-
- //-------------------------------------------------------------------------
-
- /**
- * Objects are equal using their
- * equals method.long s are equal.
- * long
- * @param rhs
- * the right hand long
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(long lhs, long rhs) {
- if (isEquals == false) {
- return this;
- }
- isEquals = (lhs == rhs);
- return this;
- }
-
- /**
- * ints are equal.int
- * @param rhs the right hand int
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(int lhs, int rhs) {
- if (isEquals == false) {
- return this;
- }
- isEquals = (lhs == rhs);
- return this;
- }
-
- /**
- * shorts are equal.short
- * @param rhs the right hand short
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(short lhs, short rhs) {
- if (isEquals == false) {
- return this;
- }
- isEquals = (lhs == rhs);
- return this;
- }
-
- /**
- * chars are equal.char
- * @param rhs the right hand char
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(char lhs, char rhs) {
- if (isEquals == false) {
- return this;
- }
- isEquals = (lhs == rhs);
- return this;
- }
-
- /**
- * bytes are equal.byte
- * @param rhs the right hand byte
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(byte lhs, byte rhs) {
- if (isEquals == false) {
- return this;
- }
- isEquals = (lhs == rhs);
- return this;
- }
-
- /**
- * doubles are equal by testing that the
- * pattern of bits returned by doubleToLong are equal.-0.0.HashCodeBuilder.double
- * @param rhs the right hand double
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(double lhs, double rhs) {
- if (isEquals == false) {
- return this;
- }
- return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
- }
-
- /**
- * floats are equal byt testing that the
- * pattern of bits returned by doubleToLong are equal.-0.0.HashCodeBuilder.float
- * @param rhs the right hand float
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(float lhs, float rhs) {
- if (isEquals == false) {
- return this;
- }
- return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
- }
-
- /**
- * booleanss are equal.boolean
- * @param rhs the right hand boolean
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(boolean lhs, boolean rhs) {
- if (isEquals == false) {
- return this;
- }
- isEquals = (lhs == rhs);
- return this;
- }
-
- /**
- * Object arrays.Object[]
- * @param rhs the right hand Object[]
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(Object[] lhs, Object[] rhs) {
- if (isEquals == false) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null || rhs == null) {
- this.setEquals(false);
- return this;
- }
- if (lhs.length != rhs.length) {
- this.setEquals(false);
- return this;
- }
- for (int i = 0; i < lhs.length && isEquals; ++i) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * long. Length and all
- * values are compared.long[]
- * @param rhs the right hand long[]
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(long[] lhs, long[] rhs) {
- if (isEquals == false) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null || rhs == null) {
- this.setEquals(false);
- return this;
- }
- if (lhs.length != rhs.length) {
- this.setEquals(false);
- return this;
- }
- for (int i = 0; i < lhs.length && isEquals; ++i) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * int. Length and all
- * values are compared.int[]
- * @param rhs the right hand int[]
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(int[] lhs, int[] rhs) {
- if (isEquals == false) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null || rhs == null) {
- this.setEquals(false);
- return this;
- }
- if (lhs.length != rhs.length) {
- this.setEquals(false);
- return this;
- }
- for (int i = 0; i < lhs.length && isEquals; ++i) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * short. Length and all
- * values are compared.short[]
- * @param rhs the right hand short[]
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(short[] lhs, short[] rhs) {
- if (isEquals == false) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null || rhs == null) {
- this.setEquals(false);
- return this;
- }
- if (lhs.length != rhs.length) {
- this.setEquals(false);
- return this;
- }
- for (int i = 0; i < lhs.length && isEquals; ++i) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * char. Length and all
- * values are compared.char[]
- * @param rhs the right hand char[]
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(char[] lhs, char[] rhs) {
- if (isEquals == false) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null || rhs == null) {
- this.setEquals(false);
- return this;
- }
- if (lhs.length != rhs.length) {
- this.setEquals(false);
- return this;
- }
- for (int i = 0; i < lhs.length && isEquals; ++i) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * byte. Length and all
- * values are compared.byte[]
- * @param rhs the right hand byte[]
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(byte[] lhs, byte[] rhs) {
- if (isEquals == false) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null || rhs == null) {
- this.setEquals(false);
- return this;
- }
- if (lhs.length != rhs.length) {
- this.setEquals(false);
- return this;
- }
- for (int i = 0; i < lhs.length && isEquals; ++i) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * double. Length and all
- * values are compared.double[]
- * @param rhs the right hand double[]
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(double[] lhs, double[] rhs) {
- if (isEquals == false) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null || rhs == null) {
- this.setEquals(false);
- return this;
- }
- if (lhs.length != rhs.length) {
- this.setEquals(false);
- return this;
- }
- for (int i = 0; i < lhs.length && isEquals; ++i) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * float. Length and all
- * values are compared.float[]
- * @param rhs the right hand float[]
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(float[] lhs, float[] rhs) {
- if (isEquals == false) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null || rhs == null) {
- this.setEquals(false);
- return this;
- }
- if (lhs.length != rhs.length) {
- this.setEquals(false);
- return this;
- }
- for (int i = 0; i < lhs.length && isEquals; ++i) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * boolean. Length and all
- * values are compared.boolean[]
- * @param rhs the right hand boolean[]
- * @return EqualsBuilder - used to chain calls.
- */
- public EqualsBuilder append(boolean[] lhs, boolean[] rhs) {
- if (isEquals == false) {
- return this;
- }
- if (lhs == rhs) {
- return this;
- }
- if (lhs == null || rhs == null) {
- this.setEquals(false);
- return this;
- }
- if (lhs.length != rhs.length) {
- this.setEquals(false);
- return this;
- }
- for (int i = 0; i < lhs.length && isEquals; ++i) {
- append(lhs[i], rhs[i]);
- }
- return this;
- }
-
- /**
- * true if the fields that have been checked
- * are all equal.true if the fields that have been checked
- * are all equal.true if all of the fields that have been checked
- * are equal, false otherwise.
- *
- * @since 3.0
- */
- public Boolean build() {
- return Boolean.valueOf(isEquals());
- }
-
- /**
- * Sets the isEquals value.
- *
- * @param isEquals The value to set.
- * @since 2.1
- */
- protected void setEquals(boolean isEquals) {
- this.isEquals = isEquals;
- }
-
- /**
- * Reset the EqualsBuilder so you can use the same object again
- * @since 2.5
- */
- public void reset() {
- this.isEquals = true;
- }
-}
+/*
+ * 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.commons.lang3.builder;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.tuple.Pair;
+
+/**
+ * doubles,
+ * floats, and arrays can be tricky. Also, making sure that
+ * equals() and hashCode() are consistent can be
+ * difficult.
+ * public boolean equals(Object obj) {
+ * if (obj == null) { return false; }
+ * if (obj == this) { return true; }
+ * if (obj.getClass() != getClass()) {
+ * return false;
+ * }
+ * MyClass rhs = (MyClass) obj;
+ * return new EqualsBuilder()
+ * .appendSuper(super.equals(obj))
+ * .append(field1, rhs.field1)
+ * .append(field2, rhs.field2)
+ * .append(field3, rhs.field3)
+ * .isEquals();
+ * }
+ *
+ *
+ * reflectionEquals, uses AccessibleObject.setAccessible to
+ * change the visibility of the fields. This will fail under a security
+ * manager, unless the appropriate permissions are set up correctly. It is
+ * also slower than testing explicitly.
+ * public boolean equals(Object obj) {
+ * return EqualsBuilder.reflectionEquals(this, obj);
+ * }
+ *
+ *
+ * @since 1.0
+ * @version $Id: EqualsBuilder.java 1091531 2011-04-12 18:29:49Z ggregory $
+ */
+public class EqualsBuilder implements Builderthis object
+ * @param rhs the other object
+ *
+ * @return the pair
+ */
+ static Pairtrue if the registry contains the given object pair.
+ * Used by the reflection methods to avoid infinite loops.
+ * Objects might be swapped therefore a check is needed if the object pair
+ * is registered in given or swapped order.
+ * this object to lookup in registry
+ * @param rhs the other object to lookup on registry
+ * @return boolean true if the registry contains the given object.
+ * @since 3.0
+ */
+ static boolean isRegistered(Object lhs, Object rhs) {
+ Setthis object to register
+ * @param rhs the other object to register
+ */
+ static void register(Object lhs, Object rhs) {
+ synchronized (EqualsBuilder.class) {
+ if (getRegistry() == null) {
+ REGISTRY.set(new HashSetthis object to unregister
+ * @param rhs the other object to unregister
+ * @since 3.0
+ */
+ static void unregister(Object lhs, Object rhs) {
+ Settrue.
+ */
+ private boolean isEquals = true;
+
+ /**
+ * true.Objects
+ * are equal.AccessibleObject.setAccessible to gain access to private
+ * fields. This means that it will throw a security exception if run under
+ * a security manager, if the permissions are not set up correctly. It is also
+ * not as efficient as testing explicitly.this object
+ * @param rhs the other object
+ * @param excludeFields Collection of String field names to exclude from testing
+ * @return true if the two Objects have tested equals.
+ */
+ public static boolean reflectionEquals(Object lhs, Object rhs, CollectionObjects
+ * are equal.AccessibleObject.setAccessible to gain access to private
+ * fields. This means that it will throw a security exception if run under
+ * a security manager, if the permissions are not set up correctly. It is also
+ * not as efficient as testing explicitly.this object
+ * @param rhs the other object
+ * @param excludeFields array of field names to exclude from testing
+ * @return true if the two Objects have tested equals.
+ */
+ public static boolean reflectionEquals(Object lhs, Object rhs, String... excludeFields) {
+ return reflectionEquals(lhs, rhs, false, null, excludeFields);
+ }
+
+ /**
+ * Objects
+ * are equal.AccessibleObject.setAccessible to gain access to private
+ * fields. This means that it will throw a security exception if run under
+ * a security manager, if the permissions are not set up correctly. It is also
+ * not as efficient as testing explicitly.true, transient
+ * members will be tested, otherwise they are ignored, as they are likely
+ * derived fields, and not part of the value of the Object.this object
+ * @param rhs the other object
+ * @param testTransients whether to include transient fields
+ * @return true if the two Objects have tested equals.
+ */
+ public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients) {
+ return reflectionEquals(lhs, rhs, testTransients, null);
+ }
+
+ /**
+ * Objects
+ * are equal.AccessibleObject.setAccessible to gain access to private
+ * fields. This means that it will throw a security exception if run under
+ * a security manager, if the permissions are not set up correctly. It is also
+ * not as efficient as testing explicitly.true, transient
+ * members will be tested, otherwise they are ignored, as they are likely
+ * derived fields, and not part of the value of the Object.this object
+ * @param rhs the other object
+ * @param testTransients whether to include transient fields
+ * @param reflectUpToClass the superclass to reflect up to (inclusive),
+ * may be null
+ * @param excludeFields array of field names to exclude from testing
+ * @return true if the two Objects have tested equals.
+ * @since 2.0
+ */
+ public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class> reflectUpToClass,
+ String... excludeFields) {
+ if (lhs == rhs) {
+ return true;
+ }
+ if (lhs == null || rhs == null) {
+ return false;
+ }
+ // Find the leaf class since there may be transients in the leaf
+ // class or in classes between the leaf and root.
+ // If we are not testing transients or a subclass has no ivars,
+ // then a subclass can test equals to a superclass.
+ Class> lhsClass = lhs.getClass();
+ Class> rhsClass = rhs.getClass();
+ Class> testClass;
+ if (lhsClass.isInstance(rhs)) {
+ testClass = lhsClass;
+ if (!rhsClass.isInstance(lhs)) {
+ // rhsClass is a subclass of lhsClass
+ testClass = rhsClass;
+ }
+ } else if (rhsClass.isInstance(lhs)) {
+ testClass = rhsClass;
+ if (!lhsClass.isInstance(rhs)) {
+ // lhsClass is a subclass of rhsClass
+ testClass = lhsClass;
+ }
+ } else {
+ // The two classes are not related.
+ return false;
+ }
+ EqualsBuilder equalsBuilder = new EqualsBuilder();
+ try {
+ reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
+ while (testClass.getSuperclass() != null && testClass != reflectUpToClass) {
+ testClass = testClass.getSuperclass();
+ reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
+ }
+ } catch (IllegalArgumentException e) {
+ // In this case, we tried to test a subclass vs. a superclass and
+ // the subclass has ivars or the ivars are transient and
+ // we are testing transients.
+ // If a subclass has ivars that we are trying to test them, we get an
+ // exception and we know that the objects are not equal.
+ return false;
+ }
+ return equalsBuilder.isEquals();
+ }
+
+ /**
+ * super.equals() to this builder.super.equals()
+ * @return EqualsBuilder - used to chain calls.
+ * @since 2.0
+ */
+ public EqualsBuilder appendSuper(boolean superEquals) {
+ if (isEquals == false) {
+ return this;
+ }
+ isEquals = superEquals;
+ return this;
+ }
+
+ //-------------------------------------------------------------------------
+
+ /**
+ * Objects are equal using their
+ * equals method.long s are equal.
+ * long
+ * @param rhs
+ * the right hand long
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(long lhs, long rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ isEquals = (lhs == rhs);
+ return this;
+ }
+
+ /**
+ * ints are equal.int
+ * @param rhs the right hand int
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(int lhs, int rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ isEquals = (lhs == rhs);
+ return this;
+ }
+
+ /**
+ * shorts are equal.short
+ * @param rhs the right hand short
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(short lhs, short rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ isEquals = (lhs == rhs);
+ return this;
+ }
+
+ /**
+ * chars are equal.char
+ * @param rhs the right hand char
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(char lhs, char rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ isEquals = (lhs == rhs);
+ return this;
+ }
+
+ /**
+ * bytes are equal.byte
+ * @param rhs the right hand byte
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(byte lhs, byte rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ isEquals = (lhs == rhs);
+ return this;
+ }
+
+ /**
+ * doubles are equal by testing that the
+ * pattern of bits returned by doubleToLong are equal.-0.0.HashCodeBuilder.double
+ * @param rhs the right hand double
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(double lhs, double rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
+ }
+
+ /**
+ * floats are equal byt testing that the
+ * pattern of bits returned by doubleToLong are equal.-0.0.HashCodeBuilder.float
+ * @param rhs the right hand float
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(float lhs, float rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
+ }
+
+ /**
+ * booleanss are equal.boolean
+ * @param rhs the right hand boolean
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(boolean lhs, boolean rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ isEquals = (lhs == rhs);
+ return this;
+ }
+
+ /**
+ * Object arrays.Object[]
+ * @param rhs the right hand Object[]
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(Object[] lhs, Object[] rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ if (lhs == rhs) {
+ return this;
+ }
+ if (lhs == null || rhs == null) {
+ this.setEquals(false);
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ this.setEquals(false);
+ return this;
+ }
+ for (int i = 0; i < lhs.length && isEquals; ++i) {
+ append(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ /**
+ * long. Length and all
+ * values are compared.long[]
+ * @param rhs the right hand long[]
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(long[] lhs, long[] rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ if (lhs == rhs) {
+ return this;
+ }
+ if (lhs == null || rhs == null) {
+ this.setEquals(false);
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ this.setEquals(false);
+ return this;
+ }
+ for (int i = 0; i < lhs.length && isEquals; ++i) {
+ append(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ /**
+ * int. Length and all
+ * values are compared.int[]
+ * @param rhs the right hand int[]
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(int[] lhs, int[] rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ if (lhs == rhs) {
+ return this;
+ }
+ if (lhs == null || rhs == null) {
+ this.setEquals(false);
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ this.setEquals(false);
+ return this;
+ }
+ for (int i = 0; i < lhs.length && isEquals; ++i) {
+ append(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ /**
+ * short. Length and all
+ * values are compared.short[]
+ * @param rhs the right hand short[]
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(short[] lhs, short[] rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ if (lhs == rhs) {
+ return this;
+ }
+ if (lhs == null || rhs == null) {
+ this.setEquals(false);
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ this.setEquals(false);
+ return this;
+ }
+ for (int i = 0; i < lhs.length && isEquals; ++i) {
+ append(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ /**
+ * char. Length and all
+ * values are compared.char[]
+ * @param rhs the right hand char[]
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(char[] lhs, char[] rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ if (lhs == rhs) {
+ return this;
+ }
+ if (lhs == null || rhs == null) {
+ this.setEquals(false);
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ this.setEquals(false);
+ return this;
+ }
+ for (int i = 0; i < lhs.length && isEquals; ++i) {
+ append(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ /**
+ * byte. Length and all
+ * values are compared.byte[]
+ * @param rhs the right hand byte[]
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(byte[] lhs, byte[] rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ if (lhs == rhs) {
+ return this;
+ }
+ if (lhs == null || rhs == null) {
+ this.setEquals(false);
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ this.setEquals(false);
+ return this;
+ }
+ for (int i = 0; i < lhs.length && isEquals; ++i) {
+ append(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ /**
+ * double. Length and all
+ * values are compared.double[]
+ * @param rhs the right hand double[]
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(double[] lhs, double[] rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ if (lhs == rhs) {
+ return this;
+ }
+ if (lhs == null || rhs == null) {
+ this.setEquals(false);
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ this.setEquals(false);
+ return this;
+ }
+ for (int i = 0; i < lhs.length && isEquals; ++i) {
+ append(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ /**
+ * float. Length and all
+ * values are compared.float[]
+ * @param rhs the right hand float[]
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(float[] lhs, float[] rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ if (lhs == rhs) {
+ return this;
+ }
+ if (lhs == null || rhs == null) {
+ this.setEquals(false);
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ this.setEquals(false);
+ return this;
+ }
+ for (int i = 0; i < lhs.length && isEquals; ++i) {
+ append(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ /**
+ * boolean. Length and all
+ * values are compared.boolean[]
+ * @param rhs the right hand boolean[]
+ * @return EqualsBuilder - used to chain calls.
+ */
+ public EqualsBuilder append(boolean[] lhs, boolean[] rhs) {
+ if (isEquals == false) {
+ return this;
+ }
+ if (lhs == rhs) {
+ return this;
+ }
+ if (lhs == null || rhs == null) {
+ this.setEquals(false);
+ return this;
+ }
+ if (lhs.length != rhs.length) {
+ this.setEquals(false);
+ return this;
+ }
+ for (int i = 0; i < lhs.length && isEquals; ++i) {
+ append(lhs[i], rhs[i]);
+ }
+ return this;
+ }
+
+ /**
+ * true if the fields that have been checked
+ * are all equal.true if the fields that have been checked
+ * are all equal.true if all of the fields that have been checked
+ * are equal, false otherwise.
+ *
+ * @since 3.0
+ */
+ public Boolean build() {
+ return Boolean.valueOf(isEquals());
+ }
+
+ /**
+ * Sets the isEquals value.
+ *
+ * @param isEquals The value to set.
+ * @since 2.1
+ */
+ protected void setEquals(boolean isEquals) {
+ this.isEquals = isEquals;
+ }
+
+ /**
+ * Reset the EqualsBuilder so you can use the same object again
+ * @since 2.5
+ */
+ public void reset() {
+ this.isEquals = true;
+ }
+}
diff --git a/src/org/apache/commons/lang3/builder/HashCodeBuilder.java b/src/org/apache/commons/lang3/builder/HashCodeBuilder.java
index 9ae2bd5..2afa483 100644
--- a/src/org/apache/commons/lang3/builder/HashCodeBuilder.java
+++ b/src/org/apache/commons/lang3/builder/HashCodeBuilder.java
@@ -1,961 +1,961 @@
-/*
- * 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.commons.lang3.builder;
-
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.apache.commons.lang3.ArrayUtils;
-
-/**
- * hashCode method to be built for any class. It follows the rules laid out in
- * the book Effective Java by Joshua Bloch. Writing a
- * good hashCode method is actually quite difficult. This class aims to simplify the process.
- * hashCode method. Derived fields may be
- * excluded. In general, any field used in the equals method must be used in the hashCode
- * method.
- *
- * public class Person {
- * String name;
- * int age;
- * boolean smoker;
- * ...
- *
- * public int hashCode() {
- * // you pick a hard-coded, randomly chosen, non-zero, odd number
- * // ideally different for each class
- * return new HashCodeBuilder(17, 37).
- * append(name).
- * append(age).
- * append(smoker).
- * toHashCode();
- * }
- * }
- *
- *
- * hashCode() can be added using {@link #appendSuper}.
- * reflectionHashCode, uses AccessibleObject.setAccessible
- * to change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions
- * are set up correctly. It is also slower than testing explicitly.
- *
- * public int hashCode() {
- * return HashCodeBuilder.reflectionHashCode(this);
- * }
- *
- *
- * @since 1.0
- * @version $Id: HashCodeBuilder.java 1144929 2011-07-10 18:26:16Z ggregory $
- */
-public class HashCodeBuilder implements Buildertrue if the registry contains the given object. Used by the reflection methods to avoid
- * infinite loops.
- * true if the registry contains the given object.
- * @since 2.3
- */
- static boolean isRegistered(Object value) {
- SetClass.
- * AccessibleObject.setAccessible to gain access to private fields. This means that it will
- * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
- * also not as efficient as testing explicitly.
- * Object.
- * hashCode for
- * @return int hash code
- * @throws IllegalArgumentException
- * if the Object is null
- * @throws IllegalArgumentException
- * if the number is zero or even
- */
- public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object) {
- return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, false, null);
- }
-
- /**
- * AccessibleObject.setAccessible to gain access to private fields. This means that it will
- * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
- * also not as efficient as testing explicitly.
- * true, transient members will be tested, otherwise they
- * are ignored, as they are likely derived fields, and not part of the value of the Object.
- * hashCode for
- * @param testTransients
- * whether to include transient fields
- * @return int hash code
- * @throws IllegalArgumentException
- * if the Object is null
- * @throws IllegalArgumentException
- * if the number is zero or even
- */
- public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object,
- boolean testTransients) {
- return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, null);
- }
-
- /**
- * AccessibleObject.setAccessible to gain access to private fields. This means that it will
- * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
- * also not as efficient as testing explicitly.
- * true, transient members will be tested, otherwise they
- * are ignored, as they are likely derived fields, and not part of the value of the Object.
- * hashCode for
- * @param testTransients
- * whether to include transient fields
- * @param reflectUpToClass
- * the superclass to reflect up to (inclusive), may be null
- * @param excludeFields
- * array of field names to exclude from use in calculation of hash code
- * @return int hash code
- * @throws IllegalArgumentException
- * if the Object is null
- * @throws IllegalArgumentException
- * if the number is zero or even
- * @since 2.0
- */
- public static AccessibleObject.setAccessible to gain access to private fields. This means that it will
- * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
- * also not as efficient as testing explicitly.
- * true, transient members will be tested, otherwise they
- * are ignored, as they are likely derived fields, and not part of the value of the Object.
- * hashCode for
- * @param testTransients
- * whether to include transient fields
- * @return int hash code
- * @throws IllegalArgumentException
- * if the object is null
- */
- public static int reflectionHashCode(Object object, boolean testTransients) {
- return reflectionHashCode(17, 37, object, testTransients, null);
- }
-
- /**
- * AccessibleObject.setAccessible to gain access to private fields. This means that it will
- * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
- * also not as efficient as testing explicitly.
- * Object.
- * hashCode for
- * @param excludeFields
- * Collection of String field names to exclude from use in calculation of hash code
- * @return int hash code
- * @throws IllegalArgumentException
- * if the object is null
- */
- public static int reflectionHashCode(Object object, CollectionAccessibleObject.setAccessible to gain access to private fields. This means that it will
- * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
- * also not as efficient as testing explicitly.
- * Object.
- * hashCode for
- * @param excludeFields
- * array of field names to exclude from use in calculation of hash code
- * @return int hash code
- * @throws IllegalArgumentException
- * if the object is null
- */
- public static int reflectionHashCode(Object object, String... excludeFields) {
- return reflectionHashCode(17, 37, object, false, null, excludeFields);
- }
-
- /**
- * hashCode.
- * hashCode for a boolean.
- * 1 when true, and 0 when false to the hashCode.
- * java.lang.Boolean.hashCode handling, which computes
- * a hashCode value of 1231 for java.lang.Boolean instances
- * that represent true or 1237 for java.lang.Boolean instances
- * that represent false.
- * Effective Java
design.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(boolean value) {
- iTotal = iTotal * iConstant + (value ? 0 : 1);
- return this;
- }
-
- /**
- * hashCode for a boolean array.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(boolean[] array) {
- if (array == null) {
- iTotal = iTotal * iConstant;
- } else {
- for (boolean element : array) {
- append(element);
- }
- }
- return this;
- }
-
- // -------------------------------------------------------------------------
-
- /**
- * hashCode for a byte.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(byte value) {
- iTotal = iTotal * iConstant + value;
- return this;
- }
-
- // -------------------------------------------------------------------------
-
- /**
- * hashCode for a byte array.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(byte[] array) {
- if (array == null) {
- iTotal = iTotal * iConstant;
- } else {
- for (byte element : array) {
- append(element);
- }
- }
- return this;
- }
-
- /**
- * hashCode for a char.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(char value) {
- iTotal = iTotal * iConstant + value;
- return this;
- }
-
- /**
- * hashCode for a char array.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(char[] array) {
- if (array == null) {
- iTotal = iTotal * iConstant;
- } else {
- for (char element : array) {
- append(element);
- }
- }
- return this;
- }
-
- /**
- * hashCode for a double.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(double value) {
- return append(Double.doubleToLongBits(value));
- }
-
- /**
- * hashCode for a double array.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(double[] array) {
- if (array == null) {
- iTotal = iTotal * iConstant;
- } else {
- for (double element : array) {
- append(element);
- }
- }
- return this;
- }
-
- /**
- * hashCode for a float.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(float value) {
- iTotal = iTotal * iConstant + Float.floatToIntBits(value);
- return this;
- }
-
- /**
- * hashCode for a float array.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(float[] array) {
- if (array == null) {
- iTotal = iTotal * iConstant;
- } else {
- for (float element : array) {
- append(element);
- }
- }
- return this;
- }
-
- /**
- * hashCode for an int.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(int value) {
- iTotal = iTotal * iConstant + value;
- return this;
- }
-
- /**
- * hashCode for an int array.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(int[] array) {
- if (array == null) {
- iTotal = iTotal * iConstant;
- } else {
- for (int element : array) {
- append(element);
- }
- }
- return this;
- }
-
- /**
- * hashCode for a long.
- * hashCode
- * @return this
- */
- // NOTE: This method uses >> and not >>> as Effective Java and
- // Long.hashCode do. Ideally we should switch to >>> at
- // some stage. There are backwards compat issues, so
- // that will have to wait for the time being. cf LANG-342.
- public HashCodeBuilder append(long value) {
- iTotal = iTotal * iConstant + ((int) (value ^ (value >> 32)));
- return this;
- }
-
- /**
- * hashCode for a long array.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(long[] array) {
- if (array == null) {
- iTotal = iTotal * iConstant;
- } else {
- for (long element : array) {
- append(element);
- }
- }
- return this;
- }
-
- /**
- * hashCode for an Object.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(Object object) {
- if (object == null) {
- iTotal = iTotal * iConstant;
-
- } else {
- if(object.getClass().isArray()) {
- // 'Switch' on type of array, to dispatch to the correct handler
- // This handles multi dimensional arrays
- if (object instanceof long[]) {
- append((long[]) object);
- } else if (object instanceof int[]) {
- append((int[]) object);
- } else if (object instanceof short[]) {
- append((short[]) object);
- } else if (object instanceof char[]) {
- append((char[]) object);
- } else if (object instanceof byte[]) {
- append((byte[]) object);
- } else if (object instanceof double[]) {
- append((double[]) object);
- } else if (object instanceof float[]) {
- append((float[]) object);
- } else if (object instanceof boolean[]) {
- append((boolean[]) object);
- } else {
- // Not an array of primitives
- append((Object[]) object);
- }
- } else {
- iTotal = iTotal * iConstant + object.hashCode();
- }
- }
- return this;
- }
-
- /**
- * hashCode for an Object array.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(Object[] array) {
- if (array == null) {
- iTotal = iTotal * iConstant;
- } else {
- for (Object element : array) {
- append(element);
- }
- }
- return this;
- }
-
- /**
- * hashCode for a short.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(short value) {
- iTotal = iTotal * iConstant + value;
- return this;
- }
-
- /**
- * hashCode for a short array.
- * hashCode
- * @return this
- */
- public HashCodeBuilder append(short[] array) {
- if (array == null) {
- iTotal = iTotal * iConstant;
- } else {
- for (short element : array) {
- append(element);
- }
- }
- return this;
- }
-
- /**
- * super.hashCode()
- * @return this HashCodeBuilder, used to chain calls.
- * @since 2.0
- */
- public HashCodeBuilder appendSuper(int superHashCode) {
- iTotal = iTotal * iConstant + superHashCode;
- return this;
- }
-
- /**
- * hashCode.
- * hashCode based on the fields appended
- */
- public int toHashCode() {
- return iTotal;
- }
-
- /**
- * Returns the computed hashCode.
- *
- * @return hashCode based on the fields appended
- *
- * @since 3.0
- */
- public Integer build() {
- return Integer.valueOf(toHashCode());
- }
-
- /**
- * hashCode from toHashCode() is returned due to the likelihood
- * of bugs in mis-calling toHashCode() and the unlikeliness of it mattering what the hashCode for
- * HashCodeBuilder itself is.hashCode based on the fields appended
- * @since 2.5
- */
- @Override
- public int hashCode() {
- return toHashCode();
- }
-
-}
+/*
+ * 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.commons.lang3.builder;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.commons.lang3.ArrayUtils;
+
+/**
+ * hashCode method to be built for any class. It follows the rules laid out in
+ * the book Effective Java by Joshua Bloch. Writing a
+ * good hashCode method is actually quite difficult. This class aims to simplify the process.
+ * hashCode method. Derived fields may be
+ * excluded. In general, any field used in the equals method must be used in the hashCode
+ * method.
+ *
+ * public class Person {
+ * String name;
+ * int age;
+ * boolean smoker;
+ * ...
+ *
+ * public int hashCode() {
+ * // you pick a hard-coded, randomly chosen, non-zero, odd number
+ * // ideally different for each class
+ * return new HashCodeBuilder(17, 37).
+ * append(name).
+ * append(age).
+ * append(smoker).
+ * toHashCode();
+ * }
+ * }
+ *
+ *
+ * hashCode() can be added using {@link #appendSuper}.
+ * reflectionHashCode, uses AccessibleObject.setAccessible
+ * to change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions
+ * are set up correctly. It is also slower than testing explicitly.
+ *
+ * public int hashCode() {
+ * return HashCodeBuilder.reflectionHashCode(this);
+ * }
+ *
+ *
+ * @since 1.0
+ * @version $Id: HashCodeBuilder.java 1144929 2011-07-10 18:26:16Z ggregory $
+ */
+public class HashCodeBuilder implements Buildertrue if the registry contains the given object. Used by the reflection methods to avoid
+ * infinite loops.
+ * true if the registry contains the given object.
+ * @since 2.3
+ */
+ static boolean isRegistered(Object value) {
+ SetClass.
+ * AccessibleObject.setAccessible to gain access to private fields. This means that it will
+ * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
+ * also not as efficient as testing explicitly.
+ * Object.
+ * hashCode for
+ * @return int hash code
+ * @throws IllegalArgumentException
+ * if the Object is null
+ * @throws IllegalArgumentException
+ * if the number is zero or even
+ */
+ public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object) {
+ return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, false, null);
+ }
+
+ /**
+ * AccessibleObject.setAccessible to gain access to private fields. This means that it will
+ * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
+ * also not as efficient as testing explicitly.
+ * true, transient members will be tested, otherwise they
+ * are ignored, as they are likely derived fields, and not part of the value of the Object.
+ * hashCode for
+ * @param testTransients
+ * whether to include transient fields
+ * @return int hash code
+ * @throws IllegalArgumentException
+ * if the Object is null
+ * @throws IllegalArgumentException
+ * if the number is zero or even
+ */
+ public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object,
+ boolean testTransients) {
+ return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, null);
+ }
+
+ /**
+ * AccessibleObject.setAccessible to gain access to private fields. This means that it will
+ * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
+ * also not as efficient as testing explicitly.
+ * true, transient members will be tested, otherwise they
+ * are ignored, as they are likely derived fields, and not part of the value of the Object.
+ * hashCode for
+ * @param testTransients
+ * whether to include transient fields
+ * @param reflectUpToClass
+ * the superclass to reflect up to (inclusive), may be null
+ * @param excludeFields
+ * array of field names to exclude from use in calculation of hash code
+ * @return int hash code
+ * @throws IllegalArgumentException
+ * if the Object is null
+ * @throws IllegalArgumentException
+ * if the number is zero or even
+ * @since 2.0
+ */
+ public static AccessibleObject.setAccessible to gain access to private fields. This means that it will
+ * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
+ * also not as efficient as testing explicitly.
+ * true, transient members will be tested, otherwise they
+ * are ignored, as they are likely derived fields, and not part of the value of the Object.
+ * hashCode for
+ * @param testTransients
+ * whether to include transient fields
+ * @return int hash code
+ * @throws IllegalArgumentException
+ * if the object is null
+ */
+ public static int reflectionHashCode(Object object, boolean testTransients) {
+ return reflectionHashCode(17, 37, object, testTransients, null);
+ }
+
+ /**
+ * AccessibleObject.setAccessible to gain access to private fields. This means that it will
+ * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
+ * also not as efficient as testing explicitly.
+ * Object.
+ * hashCode for
+ * @param excludeFields
+ * Collection of String field names to exclude from use in calculation of hash code
+ * @return int hash code
+ * @throws IllegalArgumentException
+ * if the object is null
+ */
+ public static int reflectionHashCode(Object object, CollectionAccessibleObject.setAccessible to gain access to private fields. This means that it will
+ * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
+ * also not as efficient as testing explicitly.
+ * Object.
+ * hashCode for
+ * @param excludeFields
+ * array of field names to exclude from use in calculation of hash code
+ * @return int hash code
+ * @throws IllegalArgumentException
+ * if the object is null
+ */
+ public static int reflectionHashCode(Object object, String... excludeFields) {
+ return reflectionHashCode(17, 37, object, false, null, excludeFields);
+ }
+
+ /**
+ * hashCode.
+ * hashCode for a boolean.
+ * 1 when true, and 0 when false to the hashCode.
+ * java.lang.Boolean.hashCode handling, which computes
+ * a hashCode value of 1231 for java.lang.Boolean instances
+ * that represent true or 1237 for java.lang.Boolean instances
+ * that represent false.
+ * Effective Java
design.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(boolean value) {
+ iTotal = iTotal * iConstant + (value ? 0 : 1);
+ return this;
+ }
+
+ /**
+ * hashCode for a boolean array.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(boolean[] array) {
+ if (array == null) {
+ iTotal = iTotal * iConstant;
+ } else {
+ for (boolean element : array) {
+ append(element);
+ }
+ }
+ return this;
+ }
+
+ // -------------------------------------------------------------------------
+
+ /**
+ * hashCode for a byte.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(byte value) {
+ iTotal = iTotal * iConstant + value;
+ return this;
+ }
+
+ // -------------------------------------------------------------------------
+
+ /**
+ * hashCode for a byte array.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(byte[] array) {
+ if (array == null) {
+ iTotal = iTotal * iConstant;
+ } else {
+ for (byte element : array) {
+ append(element);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * hashCode for a char.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(char value) {
+ iTotal = iTotal * iConstant + value;
+ return this;
+ }
+
+ /**
+ * hashCode for a char array.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(char[] array) {
+ if (array == null) {
+ iTotal = iTotal * iConstant;
+ } else {
+ for (char element : array) {
+ append(element);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * hashCode for a double.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(double value) {
+ return append(Double.doubleToLongBits(value));
+ }
+
+ /**
+ * hashCode for a double array.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(double[] array) {
+ if (array == null) {
+ iTotal = iTotal * iConstant;
+ } else {
+ for (double element : array) {
+ append(element);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * hashCode for a float.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(float value) {
+ iTotal = iTotal * iConstant + Float.floatToIntBits(value);
+ return this;
+ }
+
+ /**
+ * hashCode for a float array.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(float[] array) {
+ if (array == null) {
+ iTotal = iTotal * iConstant;
+ } else {
+ for (float element : array) {
+ append(element);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * hashCode for an int.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(int value) {
+ iTotal = iTotal * iConstant + value;
+ return this;
+ }
+
+ /**
+ * hashCode for an int array.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(int[] array) {
+ if (array == null) {
+ iTotal = iTotal * iConstant;
+ } else {
+ for (int element : array) {
+ append(element);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * hashCode for a long.
+ * hashCode
+ * @return this
+ */
+ // NOTE: This method uses >> and not >>> as Effective Java and
+ // Long.hashCode do. Ideally we should switch to >>> at
+ // some stage. There are backwards compat issues, so
+ // that will have to wait for the time being. cf LANG-342.
+ public HashCodeBuilder append(long value) {
+ iTotal = iTotal * iConstant + ((int) (value ^ (value >> 32)));
+ return this;
+ }
+
+ /**
+ * hashCode for a long array.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(long[] array) {
+ if (array == null) {
+ iTotal = iTotal * iConstant;
+ } else {
+ for (long element : array) {
+ append(element);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * hashCode for an Object.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(Object object) {
+ if (object == null) {
+ iTotal = iTotal * iConstant;
+
+ } else {
+ if(object.getClass().isArray()) {
+ // 'Switch' on type of array, to dispatch to the correct handler
+ // This handles multi dimensional arrays
+ if (object instanceof long[]) {
+ append((long[]) object);
+ } else if (object instanceof int[]) {
+ append((int[]) object);
+ } else if (object instanceof short[]) {
+ append((short[]) object);
+ } else if (object instanceof char[]) {
+ append((char[]) object);
+ } else if (object instanceof byte[]) {
+ append((byte[]) object);
+ } else if (object instanceof double[]) {
+ append((double[]) object);
+ } else if (object instanceof float[]) {
+ append((float[]) object);
+ } else if (object instanceof boolean[]) {
+ append((boolean[]) object);
+ } else {
+ // Not an array of primitives
+ append((Object[]) object);
+ }
+ } else {
+ iTotal = iTotal * iConstant + object.hashCode();
+ }
+ }
+ return this;
+ }
+
+ /**
+ * hashCode for an Object array.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(Object[] array) {
+ if (array == null) {
+ iTotal = iTotal * iConstant;
+ } else {
+ for (Object element : array) {
+ append(element);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * hashCode for a short.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(short value) {
+ iTotal = iTotal * iConstant + value;
+ return this;
+ }
+
+ /**
+ * hashCode for a short array.
+ * hashCode
+ * @return this
+ */
+ public HashCodeBuilder append(short[] array) {
+ if (array == null) {
+ iTotal = iTotal * iConstant;
+ } else {
+ for (short element : array) {
+ append(element);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * super.hashCode()
+ * @return this HashCodeBuilder, used to chain calls.
+ * @since 2.0
+ */
+ public HashCodeBuilder appendSuper(int superHashCode) {
+ iTotal = iTotal * iConstant + superHashCode;
+ return this;
+ }
+
+ /**
+ * hashCode.
+ * hashCode based on the fields appended
+ */
+ public int toHashCode() {
+ return iTotal;
+ }
+
+ /**
+ * Returns the computed hashCode.
+ *
+ * @return hashCode based on the fields appended
+ *
+ * @since 3.0
+ */
+ public Integer build() {
+ return Integer.valueOf(toHashCode());
+ }
+
+ /**
+ * hashCode from toHashCode() is returned due to the likelihood
+ * of bugs in mis-calling toHashCode() and the unlikeliness of it mattering what the hashCode for
+ * HashCodeBuilder itself is.hashCode based on the fields appended
+ * @since 2.5
+ */
+ @Override
+ public int hashCode() {
+ return toHashCode();
+ }
+
+}
diff --git a/src/org/apache/commons/lang3/builder/IDKey.java b/src/org/apache/commons/lang3/builder/IDKey.java
index 68414c0..6b1d4ee 100644
--- a/src/org/apache/commons/lang3/builder/IDKey.java
+++ b/src/org/apache/commons/lang3/builder/IDKey.java
@@ -1,74 +1,74 @@
-/*
- * 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.commons.lang3.builder;
-
-// adapted from org.apache.axis.utils.IDKey
-
-/**
- * Wrap an identity key (System.identityHashCode())
- * so that an object can only be equal() to itself.
- *
- * This is necessary to disambiguate the occasional duplicate
- * identityHashCodes that can occur.
- *
- */
-final class IDKey {
- private final Object value;
- private final int id;
-
- /**
- * Constructor for IDKey
- * @param _value The value
- */
- public IDKey(Object _value) {
- // This is the Object hashcode
- id = System.identityHashCode(_value);
- // There have been some cases (LANG-459) that return the
- // same identity hash code for different objects. So
- // the value is also added to disambiguate these cases.
- value = _value;
- }
-
- /**
- * returns hashcode - i.e. the system identity hashcode.
- * @return the hashcode
- */
- @Override
- public int hashCode() {
- return id;
- }
-
- /**
- * checks if instances are equal
- * @param other The other object to compare to
- * @return if the instances are for the same object
- */
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof IDKey)) {
- return false;
- }
- IDKey idKey = (IDKey) other;
- if (id != idKey.id) {
- return false;
- }
- // Note that identity equals is used.
- return value == idKey.value;
- }
-}
+/*
+ * 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.commons.lang3.builder;
+
+// adapted from org.apache.axis.utils.IDKey
+
+/**
+ * Wrap an identity key (System.identityHashCode())
+ * so that an object can only be equal() to itself.
+ *
+ * This is necessary to disambiguate the occasional duplicate
+ * identityHashCodes that can occur.
+ *
+ */
+final class IDKey {
+ private final Object value;
+ private final int id;
+
+ /**
+ * Constructor for IDKey
+ * @param _value The value
+ */
+ public IDKey(Object _value) {
+ // This is the Object hashcode
+ id = System.identityHashCode(_value);
+ // There have been some cases (LANG-459) that return the
+ // same identity hash code for different objects. So
+ // the value is also added to disambiguate these cases.
+ value = _value;
+ }
+
+ /**
+ * returns hashcode - i.e. the system identity hashcode.
+ * @return the hashcode
+ */
+ @Override
+ public int hashCode() {
+ return id;
+ }
+
+ /**
+ * checks if instances are equal
+ * @param other The other object to compare to
+ * @return if the instances are for the same object
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof IDKey)) {
+ return false;
+ }
+ IDKey idKey = (IDKey) other;
+ if (id != idKey.id) {
+ return false;
+ }
+ // Note that identity equals is used.
+ return value == idKey.value;
+ }
+}
diff --git a/src/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java b/src/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java
index df85657..a7ecbac 100644
--- a/src/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java
+++ b/src/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java
@@ -1,697 +1,697 @@
-/*
- * 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.commons.lang3.builder;
-
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.commons.lang3.ClassUtils;
-
-/**
- *
- * public String toString() {
- * return ReflectionToStringBuilder.toString(this);
- * }
- *
- *
- *
- *
- * System.out.println("An object: " + ReflectionToStringBuilder.toString(anObject));
- *
- *
- *
- *
- *
- * password field in the returned
- * String:
- *
- * public String toString() {
- * return (new ReflectionToStringBuilder(this) {
- * protected boolean accept(Field f) {
- * return super.accept(f) && !f.getName().equals("password");
- * }
- * }).toString();
- * }
- *
- *
- *
- * toString is determined by the {@link ToStringStyle} passed into the
- * constructor.
- * toString value using the default ToStringStyle through reflection.
- * AccessibleObject.setAccessible to gain access to private fields. This means that it will
- * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
- * also not as efficient as testing explicitly.
- * null
- */
- public static String toString(Object object) {
- return toString(object, null, false, false, null);
- }
-
- /**
- * toString value through reflection.
- * AccessibleObject.setAccessible to gain access to private fields. This means that it will
- * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
- * also not as efficient as testing explicitly.
- * null, the default ToStringStyle is used.
- * toString to create, may be null
- * @return the String result
- * @throws IllegalArgumentException
- * if the Object or ToStringStyle is null
- */
- public static String toString(Object object, ToStringStyle style) {
- return toString(object, style, false, false, null);
- }
-
- /**
- * toString value through reflection.
- * AccessibleObject.setAccessible to gain access to private fields. This means that it will
- * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
- * also not as efficient as testing explicitly.
- * outputTransients is true, transient members will be output, otherwise they
- * are ignored, as they are likely derived fields, and not part of the value of the Object.
- * null, the default ToStringStyle is used.
- * toString to create, may be null
- * @param outputTransients
- * whether to include transient fields
- * @return the String result
- * @throws IllegalArgumentException
- * if the Object is null
- */
- public static String toString(Object object, ToStringStyle style, boolean outputTransients) {
- return toString(object, style, outputTransients, false, null);
- }
-
- /**
- * toString value through reflection.
- * AccessibleObject.setAccessible to gain access to private fields. This means that it will
- * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
- * also not as efficient as testing explicitly.
- * outputTransients is true, transient fields will be output, otherwise they
- * are ignored, as they are likely derived fields, and not part of the value of the Object.
- * outputStatics is true, static fields will be output, otherwise they are
- * ignored.
- * null, the default ToStringStyle is used.
- * toString to create, may be null
- * @param outputTransients
- * whether to include transient fields
- * @param outputStatics
- * whether to include transient fields
- * @return the String result
- * @throws IllegalArgumentException
- * if the Object is null
- * @since 2.1
- */
- public static String toString(Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics) {
- return toString(object, style, outputTransients, outputStatics, null);
- }
-
- /**
- * toString value through reflection.
- * AccessibleObject.setAccessible to gain access to private fields. This means that it will
- * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
- * also not as efficient as testing explicitly.
- * outputTransients is true, transient fields will be output, otherwise they
- * are ignored, as they are likely derived fields, and not part of the value of the Object.
- * outputStatics is true, static fields will be output, otherwise they are
- * ignored.
- * java.lang.Object.
- * null, the default ToStringStyle is used.
- * toString to create, may be null
- * @param outputTransients
- * whether to include transient fields
- * @param outputStatics
- * whether to include static fields
- * @param reflectUpToClass
- * the superclass to reflect up to (inclusive), may be null
- * @return the String result
- * @throws IllegalArgumentException
- * if the Object is null
- * @since 2.1
- */
- public static null
- * entries. Note that {@link Arrays#sort(Object[])} will throw an {@link NullPointerException} if an array element
- * is null.
- *
- * @param collection
- * The collection to convert
- * @return A new array of Strings.
- */
- static String[] toNoNullStringArray(Collectionnull.
- *
- * @param array
- * The array to check
- * @return The given array or a new array without null.
- */
- static String[] toNoNullStringArray(Object[] array) {
- List"password".
- *
- * @since 3.0 this is protected instead of private
- */
- protected String[] excludeFieldNames;
-
- /**
- * The last super class to stop appending fields for.
- */
- private Class> upToClass = null;
-
- /**
- * setDefaultStyle.
- * toString for, must not be null
- * @throws IllegalArgumentException
- * if the Object passed in is null
- */
- public ReflectionToStringBuilder(Object object) {
- super(object);
- }
-
- /**
- * null, the default style is used.
- * toString for, must not be null
- * @param style
- * the style of the toString to create, may be null
- * @throws IllegalArgumentException
- * if the Object passed in is null
- */
- public ReflectionToStringBuilder(Object object, ToStringStyle style) {
- super(object, style);
- }
-
- /**
- * null, the default style is used.
- * null, a new one is created.
- * toString for
- * @param style
- * the style of the toString to create, may be null
- * @param buffer
- * the StringBuffer to populate, may be null
- * @throws IllegalArgumentException
- * if the Object passed in is null
- */
- public ReflectionToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer) {
- super(object, style, buffer);
- }
-
- /**
- * Constructor.
- *
- * @param toString for
- * @param style
- * the style of the toString to create, may be null
- * @param buffer
- * the StringBuffer to populate, may be null
- * @param reflectUpToClass
- * the superclass to reflect up to (inclusive), may be null
- * @param outputTransients
- * whether to include transient fields
- * @param outputStatics
- * whether to include static fields
- * @since 2.1
- */
- public Field.
- *
- *
- *
- * @param field
- * The Field to test.
- * @return Whether or not to append the given true.
- * true.
- * Field.
- */
- protected boolean accept(Field field) {
- if (field.getName().indexOf(ClassUtils.INNER_CLASS_SEPARATOR_CHAR) != -1) {
- // Reject field from inner class.
- return false;
- }
- if (Modifier.isTransient(field.getModifiers()) && !this.isAppendTransients()) {
- // Reject transient fields.
- return false;
- }
- if (Modifier.isStatic(field.getModifiers()) && !this.isAppendStatics()) {
- // Reject static fields.
- return false;
- }
- if (this.excludeFieldNames != null
- && Arrays.binarySearch(this.excludeFieldNames, field.getName()) >= 0) {
- // Reject fields from the getExcludeFieldNames list.
- return false;
- }
- return true;
- }
-
- /**
- * Object.toString() had been called and not implemented by the object.
- * java.lang.reflect.Field.get(Object).
- * toString an Object array.
- * toString
- * @return this
- */
- public ReflectionToStringBuilder reflectionAppendArray(Object array) {
- this.getStyle().reflectionAppendArrayDetail(this.getStringBuffer(), null, array);
- return this;
- }
-
- /**
- * null.
- * @return this
- */
- public ReflectionToStringBuilder setExcludeFieldNames(String... excludeFieldNamesParam) {
- if (excludeFieldNamesParam == null) {
- this.excludeFieldNames = null;
- } else {
- //clone and remove nulls
- this.excludeFieldNames = toNoNullStringArray(excludeFieldNamesParam);
- Arrays.sort(this.excludeFieldNames);
- }
- return this;
- }
-
- /**
- *
+ * public String toString() {
+ * return ReflectionToStringBuilder.toString(this);
+ * }
+ *
+ *
+ *
+ *
+ * System.out.println("An object: " + ReflectionToStringBuilder.toString(anObject));
+ *
+ *
+ *
+ *
+ *
+ * password field in the returned
+ * String:
+ *
+ * public String toString() {
+ * return (new ReflectionToStringBuilder(this) {
+ * protected boolean accept(Field f) {
+ * return super.accept(f) && !f.getName().equals("password");
+ * }
+ * }).toString();
+ * }
+ *
+ *
+ *
+ * toString is determined by the {@link ToStringStyle} passed into the
+ * constructor.
+ * toString value using the default ToStringStyle through reflection.
+ * AccessibleObject.setAccessible to gain access to private fields. This means that it will
+ * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
+ * also not as efficient as testing explicitly.
+ * null
+ */
+ public static String toString(Object object) {
+ return toString(object, null, false, false, null);
+ }
+
+ /**
+ * toString value through reflection.
+ * AccessibleObject.setAccessible to gain access to private fields. This means that it will
+ * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
+ * also not as efficient as testing explicitly.
+ * null, the default ToStringStyle is used.
+ * toString to create, may be null
+ * @return the String result
+ * @throws IllegalArgumentException
+ * if the Object or ToStringStyle is null
+ */
+ public static String toString(Object object, ToStringStyle style) {
+ return toString(object, style, false, false, null);
+ }
+
+ /**
+ * toString value through reflection.
+ * AccessibleObject.setAccessible to gain access to private fields. This means that it will
+ * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
+ * also not as efficient as testing explicitly.
+ * outputTransients is true, transient members will be output, otherwise they
+ * are ignored, as they are likely derived fields, and not part of the value of the Object.
+ * null, the default ToStringStyle is used.
+ * toString to create, may be null
+ * @param outputTransients
+ * whether to include transient fields
+ * @return the String result
+ * @throws IllegalArgumentException
+ * if the Object is null
+ */
+ public static String toString(Object object, ToStringStyle style, boolean outputTransients) {
+ return toString(object, style, outputTransients, false, null);
+ }
+
+ /**
+ * toString value through reflection.
+ * AccessibleObject.setAccessible to gain access to private fields. This means that it will
+ * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
+ * also not as efficient as testing explicitly.
+ * outputTransients is true, transient fields will be output, otherwise they
+ * are ignored, as they are likely derived fields, and not part of the value of the Object.
+ * outputStatics is true, static fields will be output, otherwise they are
+ * ignored.
+ * null, the default ToStringStyle is used.
+ * toString to create, may be null
+ * @param outputTransients
+ * whether to include transient fields
+ * @param outputStatics
+ * whether to include transient fields
+ * @return the String result
+ * @throws IllegalArgumentException
+ * if the Object is null
+ * @since 2.1
+ */
+ public static String toString(Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics) {
+ return toString(object, style, outputTransients, outputStatics, null);
+ }
+
+ /**
+ * toString value through reflection.
+ * AccessibleObject.setAccessible to gain access to private fields. This means that it will
+ * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
+ * also not as efficient as testing explicitly.
+ * outputTransients is true, transient fields will be output, otherwise they
+ * are ignored, as they are likely derived fields, and not part of the value of the Object.
+ * outputStatics is true, static fields will be output, otherwise they are
+ * ignored.
+ * java.lang.Object.
+ * null, the default ToStringStyle is used.
+ * toString to create, may be null
+ * @param outputTransients
+ * whether to include transient fields
+ * @param outputStatics
+ * whether to include static fields
+ * @param reflectUpToClass
+ * the superclass to reflect up to (inclusive), may be null
+ * @return the String result
+ * @throws IllegalArgumentException
+ * if the Object is null
+ * @since 2.1
+ */
+ public static null
+ * entries. Note that {@link Arrays#sort(Object[])} will throw an {@link NullPointerException} if an array element
+ * is null.
+ *
+ * @param collection
+ * The collection to convert
+ * @return A new array of Strings.
+ */
+ static String[] toNoNullStringArray(Collectionnull.
+ *
+ * @param array
+ * The array to check
+ * @return The given array or a new array without null.
+ */
+ static String[] toNoNullStringArray(Object[] array) {
+ List"password".
+ *
+ * @since 3.0 this is protected instead of private
+ */
+ protected String[] excludeFieldNames;
+
+ /**
+ * The last super class to stop appending fields for.
+ */
+ private Class> upToClass = null;
+
+ /**
+ * setDefaultStyle.
+ * toString for, must not be null
+ * @throws IllegalArgumentException
+ * if the Object passed in is null
+ */
+ public ReflectionToStringBuilder(Object object) {
+ super(object);
+ }
+
+ /**
+ * null, the default style is used.
+ * toString for, must not be null
+ * @param style
+ * the style of the toString to create, may be null
+ * @throws IllegalArgumentException
+ * if the Object passed in is null
+ */
+ public ReflectionToStringBuilder(Object object, ToStringStyle style) {
+ super(object, style);
+ }
+
+ /**
+ * null, the default style is used.
+ * null, a new one is created.
+ * toString for
+ * @param style
+ * the style of the toString to create, may be null
+ * @param buffer
+ * the StringBuffer to populate, may be null
+ * @throws IllegalArgumentException
+ * if the Object passed in is null
+ */
+ public ReflectionToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer) {
+ super(object, style, buffer);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param toString for
+ * @param style
+ * the style of the toString to create, may be null
+ * @param buffer
+ * the StringBuffer to populate, may be null
+ * @param reflectUpToClass
+ * the superclass to reflect up to (inclusive), may be null
+ * @param outputTransients
+ * whether to include transient fields
+ * @param outputStatics
+ * whether to include static fields
+ * @since 2.1
+ */
+ public Field.
+ *
+ *
+ *
+ * @param field
+ * The Field to test.
+ * @return Whether or not to append the given true.
+ * true.
+ * Field.
+ */
+ protected boolean accept(Field field) {
+ if (field.getName().indexOf(ClassUtils.INNER_CLASS_SEPARATOR_CHAR) != -1) {
+ // Reject field from inner class.
+ return false;
+ }
+ if (Modifier.isTransient(field.getModifiers()) && !this.isAppendTransients()) {
+ // Reject transient fields.
+ return false;
+ }
+ if (Modifier.isStatic(field.getModifiers()) && !this.isAppendStatics()) {
+ // Reject static fields.
+ return false;
+ }
+ if (this.excludeFieldNames != null
+ && Arrays.binarySearch(this.excludeFieldNames, field.getName()) >= 0) {
+ // Reject fields from the getExcludeFieldNames list.
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Object.toString() had been called and not implemented by the object.
+ * java.lang.reflect.Field.get(Object).
+ * toString an Object array.
+ * toString
+ * @return this
+ */
+ public ReflectionToStringBuilder reflectionAppendArray(Object array) {
+ this.getStyle().reflectionAppendArrayDetail(this.getStringBuffer(), null, array);
+ return this;
+ }
+
+ /**
+ * null.
+ * @return this
+ */
+ public ReflectionToStringBuilder setExcludeFieldNames(String... excludeFieldNamesParam) {
+ if (excludeFieldNamesParam == null) {
+ this.excludeFieldNames = null;
+ } else {
+ //clone and remove nulls
+ this.excludeFieldNames = toNoNullStringArray(excludeFieldNamesParam);
+ Arrays.sort(this.excludeFieldNames);
+ }
+ return this;
+ }
+
+ /**
+ * toString.null is accepted, but will be converted
- * to an empty String.null is accepted, but will be converted
- * to an empty String.null is accepted, but will be converted
- * to an empty String.null is accepted, but will be converted
- * to an empty String.null is accepted, but will be converted
- * to an empty String.null is accepted, but will be converted
- * to an empty String.null is accepted, but will be converted
- * to an empty String.null found.null found
- */
- @Override
- public String getNullText() { // NOPMD as this is implementing the abstract class
- return super.getNullText();
- }
-
- /**
- * null found.null is accepted, but will be converted
- * to an empty String.null found
- */
- @Override
- public void setNullText(String nullText) { // NOPMD as this is implementing the abstract class
- super.setNullText(nullText);
- }
-
- //---------------------------------------------------------------------
-
- /**
- * Collection,
- * Map or Array size is output.Collection,
- * Map or Array size is output.null is accepted, but will be converted to
- * an empty String.Collection,
- * Map or Array size is output.Collection,
- * Map or Array size is output.null is accepted, but will be converted
- * to an empty String.Object is
- * output in summary mode.Object is
- * output in summary mode.null is accepted, but will be converted to
- * an empty String.Object is
- * output in summary mode.Object is
- * output in summary mode.null is accepted, but will be converted to
- * an empty String.toString.null is accepted, but will be converted
+ * to an empty String.null is accepted, but will be converted
+ * to an empty String.null is accepted, but will be converted
+ * to an empty String.null is accepted, but will be converted
+ * to an empty String.null is accepted, but will be converted
+ * to an empty String.null is accepted, but will be converted
+ * to an empty String.null is accepted, but will be converted
+ * to an empty String.null found.null found
+ */
+ @Override
+ public String getNullText() { // NOPMD as this is implementing the abstract class
+ return super.getNullText();
+ }
+
+ /**
+ * null found.null is accepted, but will be converted
+ * to an empty String.null found
+ */
+ @Override
+ public void setNullText(String nullText) { // NOPMD as this is implementing the abstract class
+ super.setNullText(nullText);
+ }
+
+ //---------------------------------------------------------------------
+
+ /**
+ * Collection,
+ * Map or Array size is output.Collection,
+ * Map or Array size is output.null is accepted, but will be converted to
+ * an empty String.Collection,
+ * Map or Array size is output.
This is output after the size value.
+ * + * @return the current end of size text + */ + @Override + public String getSizeEndText() { // NOPMD as this is implementing the abstract class + return super.getSizeEndText(); + } + + /** + *Sets the end text to output when a Collection,
+ * Map or Array size is output.
This is output after the size value.
+ * + *null is accepted, but will be converted
+ * to an empty String.
Gets the start text to output when an Object is
+ * output in summary mode.
This is output before the size value.
+ * + * @return the current start of summary text + */ + @Override + public String getSummaryObjectStartText() { // NOPMD as this is implementing the abstract class + return super.getSummaryObjectStartText(); + } + + /** + *Sets the start text to output when an Object is
+ * output in summary mode.
This is output before the size value.
+ * + *null is accepted, but will be converted to
+ * an empty String.
Gets the end text to output when an Object is
+ * output in summary mode.
This is output after the size value.
+ * + * @return the current end of summary text + */ + @Override + public String getSummaryObjectEndText() { // NOPMD as this is implementing the abstract class + return super.getSummaryObjectEndText(); + } + + /** + *Sets the end text to output when an Object is
+ * output in summary mode.
This is output after the size value.
+ * + *null is accepted, but will be converted to
+ * an empty String.
Assists in implementing {@link Object#toString()} methods.
- * - *This class enables a good and consistent toString() to be built for any
- * class or object. This class aims to simplify the process by:
To use this class write code as follows:
- * - *
- * public class Person {
- * String name;
- * int age;
- * boolean smoker;
- *
- * ...
- *
- * public String toString() {
- * return new ToStringBuilder(this).
- * append("name", name).
- * append("age", age).
- * append("smoker", smoker).
- * toString();
- * }
- * }
- *
- *
- * This will produce a toString of the format:
- * Person@7f54[name=Stephen,age=29,smoker=false]
To add the superclass toString, use {@link #appendSuper}.
- * To append the toString from an object that is delegated
- * to (or any other object), use {@link #appendToString}.
Alternatively, there is a method that uses reflection to determine
- * the fields to test. Because these fields are usually private, the method,
- * reflectionToString, uses AccessibleObject.setAccessible to
- * change the visibility of the fields. This will fail under a security manager,
- * unless the appropriate permissions are set up correctly. It is also
- * slower than testing explicitly.
A typical invocation for this method would look like:
- * - *
- * public String toString() {
- * return ToStringBuilder.reflectionToString(this);
- * }
- *
- *
- * You can also use the builder to debug 3rd party objects:
- * - *
- * System.out.println("An object: " + ToStringBuilder.reflectionToString(anObject));
- *
- *
- * The exact format of the toString is determined by
- * the {@link ToStringStyle} passed into the constructor.
Gets the default ToStringStyle to use.
This method gets a singleton default value, typically for the whole JVM.
- * Changing this default should generally only be done during application startup.
- * It is recommended to pass a ToStringStyle to the constructor instead
- * of using this global default.
This method can be used from multiple threads.
- * Internally, a volatile variable is used to provide the guarantee
- * that the latest value set using {@link #setDefaultStyle} is the value returned.
- * It is strongly recommended that the default style is only changed during application startup.
One reason for changing the default could be to have a verbose style during - * development and a compact style in production.
- * - * @return the defaultToStringStyle, never null
- */
- public static ToStringStyle getDefaultStyle() {
- return defaultStyle;
- }
-
- /**
- * Sets the default ToStringStyle to use.
This method sets a singleton default value, typically for the whole JVM.
- * Changing this default should generally only be done during application startup.
- * It is recommended to pass a ToStringStyle to the constructor instead
- * of changing this global default.
This method is not intended for use from multiple threads.
- * Internally, a volatile variable is used to provide the guarantee
- * that the latest value set is the value returned from {@link #getDefaultStyle}.
ToStringStyle
- * @throws IllegalArgumentException if the style is null
- */
- public static void setDefaultStyle(ToStringStyle style) {
- if (style == null) {
- throw new IllegalArgumentException("The style must not be null");
- }
- defaultStyle = style;
- }
-
- //----------------------------------------------------------------------------
- /**
- * Uses ReflectionToStringBuilder to generate a
- * toString for the specified object.
Uses ReflectionToStringBuilder to generate a
- * toString for the specified object.
toString to create, may be null
- * @return the String result
- * @see ReflectionToStringBuilder#toString(Object,ToStringStyle)
- */
- public static String reflectionToString(Object object, ToStringStyle style) {
- return ReflectionToStringBuilder.toString(object, style);
- }
-
- /**
- * Uses ReflectionToStringBuilder to generate a
- * toString for the specified object.
toString to create, may be null
- * @param outputTransients whether to include transient fields
- * @return the String result
- * @see ReflectionToStringBuilder#toString(Object,ToStringStyle,boolean)
- */
- public static String reflectionToString(Object object, ToStringStyle style, boolean outputTransients) {
- return ReflectionToStringBuilder.toString(object, style, outputTransients, false, null);
- }
-
- /**
- * Uses ReflectionToStringBuilder to generate a
- * toString for the specified object.
toString to create, may be null
- * @param outputTransients whether to include transient fields
- * @param reflectUpToClass the superclass to reflect up to (inclusive), may be null
- * @return the String result
- * @see ReflectionToStringBuilder#toString(Object,ToStringStyle,boolean,boolean,Class)
- * @since 2.0
- */
- public static Constructs a builder for the specified object using the default output style.
- * - *This default style is obtained from {@link #getDefaultStyle()}.
- * - * @param object the Object to build atoString for, not recommended to be null
- */
- public ToStringBuilder(Object object) {
- this(object, null, null);
- }
-
- /**
- * Constructs a builder for the specified object using the a defined output style.
- * - *If the style is null, the default style is used.
toString for, not recommended to be null
- * @param style the style of the toString to create, null uses the default style
- */
- public ToStringBuilder(Object object, ToStringStyle style) {
- this(object, style, null);
- }
-
- /**
- * Constructs a builder for the specified object.
- * - *If the style is null, the default style is used.
If the buffer is null, a new one is created.
toString for, not recommended to be null
- * @param style the style of the toString to create, null uses the default style
- * @param buffer the StringBuffer to populate, may be null
- */
- public ToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer) {
- if (style == null) {
- style = getDefaultStyle();
- }
- if (buffer == null) {
- buffer = new StringBuffer(512);
- }
- this.buffer = buffer;
- this.style = style;
- this.object = object;
-
- style.appendStart(buffer, object);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a boolean
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(boolean value) {
- style.append(buffer, null, value);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a boolean
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(boolean[] array) {
- style.append(buffer, null, array, null);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a byte
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(byte value) {
- style.append(buffer, null, value);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a byte
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(byte[] array) {
- style.append(buffer, null, array, null);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a char
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(char value) {
- style.append(buffer, null, value);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a char
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(char[] array) {
- style.append(buffer, null, array, null);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a double
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(double value) {
- style.append(buffer, null, value);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a double
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(double[] array) {
- style.append(buffer, null, array, null);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a float
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(float value) {
- style.append(buffer, null, value);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a float
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(float[] array) {
- style.append(buffer, null, array, null);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString an int
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(int value) {
- style.append(buffer, null, value);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString an int
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(int[] array) {
- style.append(buffer, null, array, null);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a long
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(long value) {
- style.append(buffer, null, value);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a long
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(long[] array) {
- style.append(buffer, null, array, null);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString an Object
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(Object obj) {
- style.append(buffer, null, obj, null);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString an Object
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(Object[] array) {
- style.append(buffer, null, array, null);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a short
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(short value) {
- style.append(buffer, null, value);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a short
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(short[] array) {
- style.append(buffer, null, array, null);
- return this;
- }
-
- /**
- * Append to the toString a boolean
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, boolean value) {
- style.append(buffer, fieldName, value);
- return this;
- }
-
- /**
- * Append to the toString a boolean
- * array.
hashCode
- * @return this
- */
- public ToStringBuilder append(String fieldName, boolean[] array) {
- style.append(buffer, fieldName, array, null);
- return this;
- }
-
- /**
- * Append to the toString a boolean
- * array.
A boolean parameter controls the level of detail to show.
- * Setting true will output the array in full. Setting
- * false will output a summary, typically the size of
- * the array.
toString
- * @param fullDetail true for detail, false
- * for summary info
- * @return this
- */
- public ToStringBuilder append(String fieldName, boolean[] array, boolean fullDetail) {
- style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
- return this;
- }
-
- /**
- * Append to the toString an byte
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, byte value) {
- style.append(buffer, fieldName, value);
- return this;
- }
-
- /**
- * Append to the toString a byte array.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, byte[] array) {
- style.append(buffer, fieldName, array, null);
- return this;
- }
-
- /**
- * Append to the toString a byte
- * array.
A boolean parameter controls the level of detail to show.
- * Setting true will output the array in full. Setting
- * false will output a summary, typically the size of
- * the array.
- *
- * @param fieldName the field name
- * @param array the array to add to the toString
- * @param fullDetail true for detail, false
- * for summary info
- * @return this
- */
- public ToStringBuilder append(String fieldName, byte[] array, boolean fullDetail) {
- style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
- return this;
- }
-
- /**
- *
Append to the toString a char
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, char value) {
- style.append(buffer, fieldName, value);
- return this;
- }
-
- /**
- * Append to the toString a char
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, char[] array) {
- style.append(buffer, fieldName, array, null);
- return this;
- }
-
- /**
- * Append to the toString a char
- * array.
A boolean parameter controls the level of detail to show.
- * Setting true will output the array in full. Setting
- * false will output a summary, typically the size of
- * the array.
toString
- * @param fullDetail true for detail, false
- * for summary info
- * @return this
- */
- public ToStringBuilder append(String fieldName, char[] array, boolean fullDetail) {
- style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
- return this;
- }
-
- /**
- * Append to the toString a double
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, double value) {
- style.append(buffer, fieldName, value);
- return this;
- }
-
- /**
- * Append to the toString a double
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, double[] array) {
- style.append(buffer, fieldName, array, null);
- return this;
- }
-
- /**
- * Append to the toString a double
- * array.
A boolean parameter controls the level of detail to show.
- * Setting true will output the array in full. Setting
- * false will output a summary, typically the size of
- * the array.
toString
- * @param fullDetail true for detail, false
- * for summary info
- * @return this
- */
- public ToStringBuilder append(String fieldName, double[] array, boolean fullDetail) {
- style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
- return this;
- }
-
- /**
- * Append to the toString an float
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, float value) {
- style.append(buffer, fieldName, value);
- return this;
- }
-
- /**
- * Append to the toString a float
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, float[] array) {
- style.append(buffer, fieldName, array, null);
- return this;
- }
-
- /**
- * Append to the toString a float
- * array.
A boolean parameter controls the level of detail to show.
- * Setting true will output the array in full. Setting
- * false will output a summary, typically the size of
- * the array.
toString
- * @param fullDetail true for detail, false
- * for summary info
- * @return this
- */
- public ToStringBuilder append(String fieldName, float[] array, boolean fullDetail) {
- style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
- return this;
- }
-
- /**
- * Append to the toString an int
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, int value) {
- style.append(buffer, fieldName, value);
- return this;
- }
-
- /**
- * Append to the toString an int
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, int[] array) {
- style.append(buffer, fieldName, array, null);
- return this;
- }
-
- /**
- * Append to the toString an int
- * array.
A boolean parameter controls the level of detail to show.
- * Setting true will output the array in full. Setting
- * false will output a summary, typically the size of
- * the array.
toString
- * @param fullDetail true for detail, false
- * for summary info
- * @return this
- */
- public ToStringBuilder append(String fieldName, int[] array, boolean fullDetail) {
- style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
- return this;
- }
-
- /**
- * Append to the toString a long
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, long value) {
- style.append(buffer, fieldName, value);
- return this;
- }
-
- /**
- * Append to the toString a long
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, long[] array) {
- style.append(buffer, fieldName, array, null);
- return this;
- }
-
- /**
- * Append to the toString a long
- * array.
A boolean parameter controls the level of detail to show.
- * Setting true will output the array in full. Setting
- * false will output a summary, typically the size of
- * the array.
toString
- * @param fullDetail true for detail, false
- * for summary info
- * @return this
- */
- public ToStringBuilder append(String fieldName, long[] array, boolean fullDetail) {
- style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
- return this;
- }
-
- /**
- * Append to the toString an Object
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, Object obj) {
- style.append(buffer, fieldName, obj, null);
- return this;
- }
-
- /**
- * Append to the toString an Object
- * value.
toString
- * @param fullDetail true for detail,
- * false for summary info
- * @return this
- */
- public ToStringBuilder append(String fieldName, Object obj, boolean fullDetail) {
- style.append(buffer, fieldName, obj, Boolean.valueOf(fullDetail));
- return this;
- }
-
- /**
- * Append to the toString an Object
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, Object[] array) {
- style.append(buffer, fieldName, array, null);
- return this;
- }
-
- /**
- * Append to the toString an Object
- * array.
A boolean parameter controls the level of detail to show.
- * Setting true will output the array in full. Setting
- * false will output a summary, typically the size of
- * the array.
toString
- * @param fullDetail true for detail, false
- * for summary info
- * @return this
- */
- public ToStringBuilder append(String fieldName, Object[] array, boolean fullDetail) {
- style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
- return this;
- }
-
- /**
- * Append to the toString an short
- * value.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, short value) {
- style.append(buffer, fieldName, value);
- return this;
- }
-
- /**
- * Append to the toString a short
- * array.
toString
- * @return this
- */
- public ToStringBuilder append(String fieldName, short[] array) {
- style.append(buffer, fieldName, array, null);
- return this;
- }
-
- /**
- * Append to the toString a short
- * array.
A boolean parameter controls the level of detail to show.
- * Setting true will output the array in full. Setting
- * false will output a summary, typically the size of
- * the array.
- *
- * @param fieldName the field name
- * @param array the array to add to the toString
- * @param fullDetail true for detail, false
- * for summary info
- * @return this
- */
- public ToStringBuilder append(String fieldName, short[] array, boolean fullDetail) {
- style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
- return this;
- }
-
- /**
- *
Appends with the same format as the default Object toString()
- * method. Appends the class name followed by
- * {@link System#identityHashCode(java.lang.Object)}.
Object whose class name and id to output
- * @return this
- * @since 2.0
- */
- public ToStringBuilder appendAsObjectToString(Object object) {
- ObjectUtils.identityToString(this.getStringBuffer(), object);
- return this;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append the toString from the superclass.
This method assumes that the superclass uses the same ToStringStyle
- * as this one.
If superToString is null, no change is made.
super.toString()
- * @return this
- * @since 2.0
- */
- public ToStringBuilder appendSuper(String superToString) {
- if (superToString != null) {
- style.appendSuper(buffer, superToString);
- }
- return this;
- }
-
- /**
- * Append the toString from another object.
This method is useful where a class delegates most of the implementation of
- * its properties to another class. You can then call toString() on
- * the other class and pass the result into this method.
- * private AnotherObject delegate;
- * private String fieldInThisClass;
- *
- * public String toString() {
- * return new ToStringBuilder(this).
- * appendToString(delegate.toString()).
- * append(fieldInThisClass).
- * toString();
- * }
- *
- * This method assumes that the other object uses the same ToStringStyle
- * as this one.
If the toString is null, no change is made.
toString() on another object
- * @return this
- * @since 2.0
- */
- public ToStringBuilder appendToString(String toString) {
- if (toString != null) {
- style.appendToString(buffer, toString);
- }
- return this;
- }
-
- /**
- * Returns the Object being output.
Gets the StringBuffer being populated.
StringBuffer being populated
- */
- public StringBuffer getStringBuffer() {
- return buffer;
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Gets the ToStringStyle being used.
ToStringStyle being used
- * @since 2.0
- */
- public ToStringStyle getStyle() {
- return style;
- }
-
- /**
- * Returns the built toString.
This method appends the end of data indicator, and can only be called once. - * Use {@link #getStringBuffer} to get the current string state.
- * - *If the object is null, return the style's nullText
toString
- */
- @Override
- public String toString() {
- if (this.getObject() == null) {
- this.getStringBuffer().append(this.getStyle().getNullText());
- } else {
- style.appendEnd(this.getStringBuffer(), this.getObject());
- }
- return this.getStringBuffer().toString();
- }
-
- /**
- * Returns the String that was build as an object representation. The
- * default implementation utilizes the {@link #toString()} implementation.
- *
- * @return the String toString
- *
- * @see #toString()
- *
- * @since 3.0
- */
- public String build() {
- return toString();
- }
-}
+/*
+ * 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.commons.lang3.builder;
+
+import org.apache.commons.lang3.ObjectUtils;
+
+/**
+ * Assists in implementing {@link Object#toString()} methods.
+ * + *This class enables a good and consistent toString() to be built for any
+ * class or object. This class aims to simplify the process by:
To use this class write code as follows:
+ * + *
+ * public class Person {
+ * String name;
+ * int age;
+ * boolean smoker;
+ *
+ * ...
+ *
+ * public String toString() {
+ * return new ToStringBuilder(this).
+ * append("name", name).
+ * append("age", age).
+ * append("smoker", smoker).
+ * toString();
+ * }
+ * }
+ *
+ *
+ * This will produce a toString of the format:
+ * Person@7f54[name=Stephen,age=29,smoker=false]
To add the superclass toString, use {@link #appendSuper}.
+ * To append the toString from an object that is delegated
+ * to (or any other object), use {@link #appendToString}.
Alternatively, there is a method that uses reflection to determine
+ * the fields to test. Because these fields are usually private, the method,
+ * reflectionToString, uses AccessibleObject.setAccessible to
+ * change the visibility of the fields. This will fail under a security manager,
+ * unless the appropriate permissions are set up correctly. It is also
+ * slower than testing explicitly.
A typical invocation for this method would look like:
+ * + *
+ * public String toString() {
+ * return ToStringBuilder.reflectionToString(this);
+ * }
+ *
+ *
+ * You can also use the builder to debug 3rd party objects:
+ * + *
+ * System.out.println("An object: " + ToStringBuilder.reflectionToString(anObject));
+ *
+ *
+ * The exact format of the toString is determined by
+ * the {@link ToStringStyle} passed into the constructor.
Gets the default ToStringStyle to use.
This method gets a singleton default value, typically for the whole JVM.
+ * Changing this default should generally only be done during application startup.
+ * It is recommended to pass a ToStringStyle to the constructor instead
+ * of using this global default.
This method can be used from multiple threads.
+ * Internally, a volatile variable is used to provide the guarantee
+ * that the latest value set using {@link #setDefaultStyle} is the value returned.
+ * It is strongly recommended that the default style is only changed during application startup.
One reason for changing the default could be to have a verbose style during + * development and a compact style in production.
+ * + * @return the defaultToStringStyle, never null
+ */
+ public static ToStringStyle getDefaultStyle() {
+ return defaultStyle;
+ }
+
+ /**
+ * Sets the default ToStringStyle to use.
This method sets a singleton default value, typically for the whole JVM.
+ * Changing this default should generally only be done during application startup.
+ * It is recommended to pass a ToStringStyle to the constructor instead
+ * of changing this global default.
This method is not intended for use from multiple threads.
+ * Internally, a volatile variable is used to provide the guarantee
+ * that the latest value set is the value returned from {@link #getDefaultStyle}.
ToStringStyle
+ * @throws IllegalArgumentException if the style is null
+ */
+ public static void setDefaultStyle(ToStringStyle style) {
+ if (style == null) {
+ throw new IllegalArgumentException("The style must not be null");
+ }
+ defaultStyle = style;
+ }
+
+ //----------------------------------------------------------------------------
+ /**
+ * Uses ReflectionToStringBuilder to generate a
+ * toString for the specified object.
Uses ReflectionToStringBuilder to generate a
+ * toString for the specified object.
toString to create, may be null
+ * @return the String result
+ * @see ReflectionToStringBuilder#toString(Object,ToStringStyle)
+ */
+ public static String reflectionToString(Object object, ToStringStyle style) {
+ return ReflectionToStringBuilder.toString(object, style);
+ }
+
+ /**
+ * Uses ReflectionToStringBuilder to generate a
+ * toString for the specified object.
toString to create, may be null
+ * @param outputTransients whether to include transient fields
+ * @return the String result
+ * @see ReflectionToStringBuilder#toString(Object,ToStringStyle,boolean)
+ */
+ public static String reflectionToString(Object object, ToStringStyle style, boolean outputTransients) {
+ return ReflectionToStringBuilder.toString(object, style, outputTransients, false, null);
+ }
+
+ /**
+ * Uses ReflectionToStringBuilder to generate a
+ * toString for the specified object.
toString to create, may be null
+ * @param outputTransients whether to include transient fields
+ * @param reflectUpToClass the superclass to reflect up to (inclusive), may be null
+ * @return the String result
+ * @see ReflectionToStringBuilder#toString(Object,ToStringStyle,boolean,boolean,Class)
+ * @since 2.0
+ */
+ public static Constructs a builder for the specified object using the default output style.
+ * + *This default style is obtained from {@link #getDefaultStyle()}.
+ * + * @param object the Object to build atoString for, not recommended to be null
+ */
+ public ToStringBuilder(Object object) {
+ this(object, null, null);
+ }
+
+ /**
+ * Constructs a builder for the specified object using the a defined output style.
+ * + *If the style is null, the default style is used.
toString for, not recommended to be null
+ * @param style the style of the toString to create, null uses the default style
+ */
+ public ToStringBuilder(Object object, ToStringStyle style) {
+ this(object, style, null);
+ }
+
+ /**
+ * Constructs a builder for the specified object.
+ * + *If the style is null, the default style is used.
If the buffer is null, a new one is created.
toString for, not recommended to be null
+ * @param style the style of the toString to create, null uses the default style
+ * @param buffer the StringBuffer to populate, may be null
+ */
+ public ToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer) {
+ if (style == null) {
+ style = getDefaultStyle();
+ }
+ if (buffer == null) {
+ buffer = new StringBuffer(512);
+ }
+ this.buffer = buffer;
+ this.style = style;
+ this.object = object;
+
+ style.appendStart(buffer, object);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a boolean
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(boolean value) {
+ style.append(buffer, null, value);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a boolean
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(boolean[] array) {
+ style.append(buffer, null, array, null);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a byte
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(byte value) {
+ style.append(buffer, null, value);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a byte
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(byte[] array) {
+ style.append(buffer, null, array, null);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a char
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(char value) {
+ style.append(buffer, null, value);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a char
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(char[] array) {
+ style.append(buffer, null, array, null);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a double
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(double value) {
+ style.append(buffer, null, value);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a double
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(double[] array) {
+ style.append(buffer, null, array, null);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a float
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(float value) {
+ style.append(buffer, null, value);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a float
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(float[] array) {
+ style.append(buffer, null, array, null);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString an int
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(int value) {
+ style.append(buffer, null, value);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString an int
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(int[] array) {
+ style.append(buffer, null, array, null);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a long
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(long value) {
+ style.append(buffer, null, value);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a long
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(long[] array) {
+ style.append(buffer, null, array, null);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString an Object
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(Object obj) {
+ style.append(buffer, null, obj, null);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString an Object
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(Object[] array) {
+ style.append(buffer, null, array, null);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a short
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(short value) {
+ style.append(buffer, null, value);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a short
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(short[] array) {
+ style.append(buffer, null, array, null);
+ return this;
+ }
+
+ /**
+ * Append to the toString a boolean
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, boolean value) {
+ style.append(buffer, fieldName, value);
+ return this;
+ }
+
+ /**
+ * Append to the toString a boolean
+ * array.
hashCode
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, boolean[] array) {
+ style.append(buffer, fieldName, array, null);
+ return this;
+ }
+
+ /**
+ * Append to the toString a boolean
+ * array.
A boolean parameter controls the level of detail to show.
+ * Setting true will output the array in full. Setting
+ * false will output a summary, typically the size of
+ * the array.
toString
+ * @param fullDetail true for detail, false
+ * for summary info
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, boolean[] array, boolean fullDetail) {
+ style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
+ return this;
+ }
+
+ /**
+ * Append to the toString an byte
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, byte value) {
+ style.append(buffer, fieldName, value);
+ return this;
+ }
+
+ /**
+ * Append to the toString a byte array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, byte[] array) {
+ style.append(buffer, fieldName, array, null);
+ return this;
+ }
+
+ /**
+ * Append to the toString a byte
+ * array.
A boolean parameter controls the level of detail to show.
+ * Setting true will output the array in full. Setting
+ * false will output a summary, typically the size of
+ * the array.
+ *
+ * @param fieldName the field name
+ * @param array the array to add to the toString
+ * @param fullDetail true for detail, false
+ * for summary info
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, byte[] array, boolean fullDetail) {
+ style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
+ return this;
+ }
+
+ /**
+ *
Append to the toString a char
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, char value) {
+ style.append(buffer, fieldName, value);
+ return this;
+ }
+
+ /**
+ * Append to the toString a char
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, char[] array) {
+ style.append(buffer, fieldName, array, null);
+ return this;
+ }
+
+ /**
+ * Append to the toString a char
+ * array.
A boolean parameter controls the level of detail to show.
+ * Setting true will output the array in full. Setting
+ * false will output a summary, typically the size of
+ * the array.
toString
+ * @param fullDetail true for detail, false
+ * for summary info
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, char[] array, boolean fullDetail) {
+ style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
+ return this;
+ }
+
+ /**
+ * Append to the toString a double
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, double value) {
+ style.append(buffer, fieldName, value);
+ return this;
+ }
+
+ /**
+ * Append to the toString a double
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, double[] array) {
+ style.append(buffer, fieldName, array, null);
+ return this;
+ }
+
+ /**
+ * Append to the toString a double
+ * array.
A boolean parameter controls the level of detail to show.
+ * Setting true will output the array in full. Setting
+ * false will output a summary, typically the size of
+ * the array.
toString
+ * @param fullDetail true for detail, false
+ * for summary info
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, double[] array, boolean fullDetail) {
+ style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
+ return this;
+ }
+
+ /**
+ * Append to the toString an float
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, float value) {
+ style.append(buffer, fieldName, value);
+ return this;
+ }
+
+ /**
+ * Append to the toString a float
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, float[] array) {
+ style.append(buffer, fieldName, array, null);
+ return this;
+ }
+
+ /**
+ * Append to the toString a float
+ * array.
A boolean parameter controls the level of detail to show.
+ * Setting true will output the array in full. Setting
+ * false will output a summary, typically the size of
+ * the array.
toString
+ * @param fullDetail true for detail, false
+ * for summary info
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, float[] array, boolean fullDetail) {
+ style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
+ return this;
+ }
+
+ /**
+ * Append to the toString an int
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, int value) {
+ style.append(buffer, fieldName, value);
+ return this;
+ }
+
+ /**
+ * Append to the toString an int
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, int[] array) {
+ style.append(buffer, fieldName, array, null);
+ return this;
+ }
+
+ /**
+ * Append to the toString an int
+ * array.
A boolean parameter controls the level of detail to show.
+ * Setting true will output the array in full. Setting
+ * false will output a summary, typically the size of
+ * the array.
toString
+ * @param fullDetail true for detail, false
+ * for summary info
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, int[] array, boolean fullDetail) {
+ style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
+ return this;
+ }
+
+ /**
+ * Append to the toString a long
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, long value) {
+ style.append(buffer, fieldName, value);
+ return this;
+ }
+
+ /**
+ * Append to the toString a long
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, long[] array) {
+ style.append(buffer, fieldName, array, null);
+ return this;
+ }
+
+ /**
+ * Append to the toString a long
+ * array.
A boolean parameter controls the level of detail to show.
+ * Setting true will output the array in full. Setting
+ * false will output a summary, typically the size of
+ * the array.
toString
+ * @param fullDetail true for detail, false
+ * for summary info
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, long[] array, boolean fullDetail) {
+ style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
+ return this;
+ }
+
+ /**
+ * Append to the toString an Object
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, Object obj) {
+ style.append(buffer, fieldName, obj, null);
+ return this;
+ }
+
+ /**
+ * Append to the toString an Object
+ * value.
toString
+ * @param fullDetail true for detail,
+ * false for summary info
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, Object obj, boolean fullDetail) {
+ style.append(buffer, fieldName, obj, Boolean.valueOf(fullDetail));
+ return this;
+ }
+
+ /**
+ * Append to the toString an Object
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, Object[] array) {
+ style.append(buffer, fieldName, array, null);
+ return this;
+ }
+
+ /**
+ * Append to the toString an Object
+ * array.
A boolean parameter controls the level of detail to show.
+ * Setting true will output the array in full. Setting
+ * false will output a summary, typically the size of
+ * the array.
toString
+ * @param fullDetail true for detail, false
+ * for summary info
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, Object[] array, boolean fullDetail) {
+ style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
+ return this;
+ }
+
+ /**
+ * Append to the toString an short
+ * value.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, short value) {
+ style.append(buffer, fieldName, value);
+ return this;
+ }
+
+ /**
+ * Append to the toString a short
+ * array.
toString
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, short[] array) {
+ style.append(buffer, fieldName, array, null);
+ return this;
+ }
+
+ /**
+ * Append to the toString a short
+ * array.
A boolean parameter controls the level of detail to show.
+ * Setting true will output the array in full. Setting
+ * false will output a summary, typically the size of
+ * the array.
+ *
+ * @param fieldName the field name
+ * @param array the array to add to the toString
+ * @param fullDetail true for detail, false
+ * for summary info
+ * @return this
+ */
+ public ToStringBuilder append(String fieldName, short[] array, boolean fullDetail) {
+ style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
+ return this;
+ }
+
+ /**
+ *
Appends with the same format as the default Object toString()
+ * method. Appends the class name followed by
+ * {@link System#identityHashCode(java.lang.Object)}.
Object whose class name and id to output
+ * @return this
+ * @since 2.0
+ */
+ public ToStringBuilder appendAsObjectToString(Object object) {
+ ObjectUtils.identityToString(this.getStringBuffer(), object);
+ return this;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append the toString from the superclass.
This method assumes that the superclass uses the same ToStringStyle
+ * as this one.
If superToString is null, no change is made.
super.toString()
+ * @return this
+ * @since 2.0
+ */
+ public ToStringBuilder appendSuper(String superToString) {
+ if (superToString != null) {
+ style.appendSuper(buffer, superToString);
+ }
+ return this;
+ }
+
+ /**
+ * Append the toString from another object.
This method is useful where a class delegates most of the implementation of
+ * its properties to another class. You can then call toString() on
+ * the other class and pass the result into this method.
+ * private AnotherObject delegate;
+ * private String fieldInThisClass;
+ *
+ * public String toString() {
+ * return new ToStringBuilder(this).
+ * appendToString(delegate.toString()).
+ * append(fieldInThisClass).
+ * toString();
+ * }
+ *
+ * This method assumes that the other object uses the same ToStringStyle
+ * as this one.
If the toString is null, no change is made.
toString() on another object
+ * @return this
+ * @since 2.0
+ */
+ public ToStringBuilder appendToString(String toString) {
+ if (toString != null) {
+ style.appendToString(buffer, toString);
+ }
+ return this;
+ }
+
+ /**
+ * Returns the Object being output.
Gets the StringBuffer being populated.
StringBuffer being populated
+ */
+ public StringBuffer getStringBuffer() {
+ return buffer;
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Gets the ToStringStyle being used.
ToStringStyle being used
+ * @since 2.0
+ */
+ public ToStringStyle getStyle() {
+ return style;
+ }
+
+ /**
+ * Returns the built toString.
This method appends the end of data indicator, and can only be called once. + * Use {@link #getStringBuffer} to get the current string state.
+ * + *If the object is null, return the style's nullText
toString
+ */
+ @Override
+ public String toString() {
+ if (this.getObject() == null) {
+ this.getStringBuffer().append(this.getStyle().getNullText());
+ } else {
+ style.appendEnd(this.getStringBuffer(), this.getObject());
+ }
+ return this.getStringBuffer().toString();
+ }
+
+ /**
+ * Returns the String that was build as an object representation. The
+ * default implementation utilizes the {@link #toString()} implementation.
+ *
+ * @return the String toString
+ *
+ * @see #toString()
+ *
+ * @since 3.0
+ */
+ public String build() {
+ return toString();
+ }
+}
diff --git a/src/org/apache/commons/lang3/builder/ToStringStyle.java b/src/org/apache/commons/lang3/builder/ToStringStyle.java
index d9ee587..109fefd 100644
--- a/src/org/apache/commons/lang3/builder/ToStringStyle.java
+++ b/src/org/apache/commons/lang3/builder/ToStringStyle.java
@@ -1,2271 +1,2271 @@
-/*
- * 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.commons.lang3.builder;
-
-import java.io.Serializable;
-import java.lang.reflect.Array;
-import java.util.Collection;
-import java.util.Map;
-import java.util.WeakHashMap;
-
-import org.apache.commons.lang3.ClassUtils;
-import org.apache.commons.lang3.ObjectUtils;
-import org.apache.commons.lang3.SystemUtils;
-
-/**
- * Controls String formatting for {@link ToStringBuilder}.
- * The main public interface is always via ToStringBuilder.
These classes are intended to be used as Singletons.
- * There is no need to instantiate a new style each time. A program
- * will generally use one of the predefined constants on this class.
- * Alternatively, the {@link StandardToStringStyle} class can be used
- * to set the individual settings. Thus most styles can be achieved
- * without subclassing.
If required, a subclass can override as many or as few of the
- * methods as it requires. Each object type (from boolean
- * to long to Object to int[]) has
- * its own methods to output it. Most have two versions, detail and summary.
- *
- *
For example, the detail version of the array based methods will - * output the whole array, whereas the summary method will just output - * the array length.
- * - *If you want to format the output of certain objects, such as dates, you - * must create a subclass and override a method. - *
- * public class MyStyle extends ToStringStyle {
- * protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
- * if (value instanceof Date) {
- * value = new SimpleDateFormat("yyyy-MM-dd").format(value);
- * }
- * buffer.append(value);
- * }
- * }
- *
- *
- *
- * @since 1.0
- * @version $Id: ToStringStyle.java 1091066 2011-04-11 13:30:11Z mbenson $
- */
-public abstract class ToStringStyle implements Serializable {
-
- /**
- * Serialization version ID.
- */
- private static final long serialVersionUID = -2587890625525655916L;
-
- /**
- * The default toString style. Using the Using the Person
- * example from {@link ToStringBuilder}, the output would look like this:
- *
- * - * Person@182f0db[name=John Doe,age=33,smoker=false] - *- */ - public static final ToStringStyle DEFAULT_STYLE = new DefaultToStringStyle(); - - /** - * The multi line toString style. Using the Using the
Person
- * example from {@link ToStringBuilder}, the output would look like this:
- *
- * - * Person@182f0db[ - * name=John Doe - * age=33 - * smoker=false - * ] - *- */ - public static final ToStringStyle MULTI_LINE_STYLE = new MultiLineToStringStyle(); - - /** - * The no field names toString style. Using the Using the - *
Person example from {@link ToStringBuilder}, the output
- * would look like this:
- *
- * - * Person@182f0db[John Doe,33,false] - *- */ - public static final ToStringStyle NO_FIELD_NAMES_STYLE = new NoFieldNameToStringStyle(); - - /** - * The short prefix toString style. Using the
Person example
- * from {@link ToStringBuilder}, the output would look like this:
- *
- * - * Person[name=John Doe,age=33,smoker=false] - *- * - * @since 2.1 - */ - public static final ToStringStyle SHORT_PREFIX_STYLE = new ShortPrefixToStringStyle(); - - /** - * The simple toString style. Using the Using the
Person
- * example from {@link ToStringBuilder}, the output would look like this:
- *
- * - * John Doe,33,false - *- */ - public static final ToStringStyle SIMPLE_STYLE = new SimpleToStringStyle(); - - /** - *
- * A registry of objects used by reflectionToString methods
- * to detect cyclical object references and avoid infinite loops.
- *
- * Returns the registry of objects being traversed by the reflectionToString
- * methods in the current thread.
- *
- * Returns true if the registry contains the given object.
- * Used by the reflection methods to avoid infinite loops.
- *
true if the registry contains the given
- * object.
- */
- static boolean isRegistered(Object value) {
- Map- * Registers the given object. Used by the reflection methods to avoid - * infinite loops. - *
- * - * @param value - * The object to register. - */ - static void register(Object value) { - if (value != null) { - Map- * Unregisters the given object. - *
- * - *- * Used by the reflection methods to avoid infinite loops. - *
- * - * @param value - * The object to unregister. - */ - static void unregister(Object value) { - if (value != null) { - Maptrue.
- */
- private boolean useFieldNames = true;
-
- /**
- * Whether to use the class name, the default is true.
- */
- private boolean useClassName = true;
-
- /**
- * Whether to use short class names, the default is false.
- */
- private boolean useShortClassName = false;
-
- /**
- * Whether to use the identity hash code, the default is true.
- */
- private boolean useIdentityHashCode = true;
-
- /**
- * The content start '['.
- */
- private String contentStart = "[";
-
- /**
- * The content end ']'.
- */
- private String contentEnd = "]";
-
- /**
- * The field name value separator '='.
- */
- private String fieldNameValueSeparator = "=";
-
- /**
- * Whether the field separator should be added before any other fields.
- */
- private boolean fieldSeparatorAtStart = false;
-
- /**
- * Whether the field separator should be added after any other fields.
- */
- private boolean fieldSeparatorAtEnd = false;
-
- /**
- * The field separator ','.
- */
- private String fieldSeparator = ",";
-
- /**
- * The array start '{'.
- */
- private String arrayStart = "{";
-
- /**
- * The array separator ','.
- */
- private String arraySeparator = ",";
-
- /**
- * The detail for array content.
- */
- private boolean arrayContentDetail = true;
-
- /**
- * The array end '}'.
- */
- private String arrayEnd = "}";
-
- /**
- * The value to use when fullDetail is null,
- * the default value is true.
- */
- private boolean defaultFullDetail = true;
-
- /**
- * The null text '<null>'.
- */
- private String nullText = "'.
- */
- private String sizeStartText = "'>' .
- */
- private String sizeEndText = ">";
-
- /**
- * The summary object text start '<'.
- */
- private String summaryObjectStartText = "<";
-
- /**
- * The summary object text start '>'.
- */
- private String summaryObjectEndText = ">";
-
- //----------------------------------------------------------------------------
-
- /**
- * Constructor.
- */ - protected ToStringStyle() { - super(); - } - - //---------------------------------------------------------------------------- - - /** - *Append to the toString the superclass toString.
NOTE: It assumes that the toString has been created from the same ToStringStyle.
- * - *A null superToString is ignored.
StringBuffer to populate
- * @param superToString the super.toString()
- * @since 2.0
- */
- public void appendSuper(StringBuffer buffer, String superToString) {
- appendToString(buffer, superToString);
- }
-
- /**
- * Append to the toString another toString.
NOTE: It assumes that the toString has been created from the same ToStringStyle.
- * - *A null toString is ignored.
StringBuffer to populate
- * @param toString the additional toString
- * @since 2.0
- */
- public void appendToString(StringBuffer buffer, String toString) {
- if (toString != null) {
- int pos1 = toString.indexOf(contentStart) + contentStart.length();
- int pos2 = toString.lastIndexOf(contentEnd);
- if (pos1 != pos2 && pos1 >= 0 && pos2 >= 0) {
- String data = toString.substring(pos1, pos2);
- if (fieldSeparatorAtStart) {
- removeLastFieldSeparator(buffer);
- }
- buffer.append(data);
- appendFieldSeparator(buffer);
- }
- }
- }
-
- /**
- * Append to the toString the start of data indicator.
StringBuffer to populate
- * @param object the Object to build a toString for
- */
- public void appendStart(StringBuffer buffer, Object object) {
- if (object != null) {
- appendClassName(buffer, object);
- appendIdentityHashCode(buffer, object);
- appendContentStart(buffer);
- if (fieldSeparatorAtStart) {
- appendFieldSeparator(buffer);
- }
- }
- }
-
- /**
- * Append to the toString the end of data indicator.
StringBuffer to populate
- * @param object the Object to build a
- * toString for.
- */
- public void appendEnd(StringBuffer buffer, Object object) {
- if (this.fieldSeparatorAtEnd == false) {
- removeLastFieldSeparator(buffer);
- }
- appendContentEnd(buffer);
- unregister(object);
- }
-
- /**
- * Remove the last field separator from the buffer.
- * - * @param buffer theStringBuffer to populate
- * @since 2.0
- */
- protected void removeLastFieldSeparator(StringBuffer buffer) {
- int len = buffer.length();
- int sepLen = fieldSeparator.length();
- if (len > 0 && sepLen > 0 && len >= sepLen) {
- boolean match = true;
- for (int i = 0; i < sepLen; i++) {
- if (buffer.charAt(len - 1 - i) != fieldSeparator.charAt(sepLen - 1 - i)) {
- match = false;
- break;
- }
- }
- if (match) {
- buffer.setLength(len - sepLen);
- }
- }
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString an Object
- * value, printing the full toString of the
- * Object passed in.
StringBuffer to populate
- * @param fieldName the field name
- * @param value the value to add to the toString
- * @param fullDetail true for detail, false
- * for summary info, null for style decides
- */
- public void append(StringBuffer buffer, String fieldName, Object value, Boolean fullDetail) {
- appendFieldStart(buffer, fieldName);
-
- if (value == null) {
- appendNullText(buffer, fieldName);
-
- } else {
- appendInternal(buffer, fieldName, value, isFullDetail(fullDetail));
- }
-
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString an Object,
- * correctly interpreting its type.
This method performs the main lookup by Class type to correctly
- * route arrays, Collections, Maps and
- * Objects to the appropriate method.
Either detail or summary views can be specified.
- * - *If a cycle is detected, an object will be appended with the
- * Object.toString() format.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param value the value to add to the toString,
- * not null
- * @param detail output detail or not
- */
- protected void appendInternal(StringBuffer buffer, String fieldName, Object value, boolean detail) {
- if (isRegistered(value)
- && !(value instanceof Number || value instanceof Boolean || value instanceof Character)) {
- appendCyclicObject(buffer, fieldName, value);
- return;
- }
-
- register(value);
-
- try {
- if (value instanceof Collection>) {
- if (detail) {
- appendDetail(buffer, fieldName, (Collection>) value);
- } else {
- appendSummarySize(buffer, fieldName, ((Collection>) value).size());
- }
-
- } else if (value instanceof Map, ?>) {
- if (detail) {
- appendDetail(buffer, fieldName, (Map, ?>) value);
- } else {
- appendSummarySize(buffer, fieldName, ((Map, ?>) value).size());
- }
-
- } else if (value instanceof long[]) {
- if (detail) {
- appendDetail(buffer, fieldName, (long[]) value);
- } else {
- appendSummary(buffer, fieldName, (long[]) value);
- }
-
- } else if (value instanceof int[]) {
- if (detail) {
- appendDetail(buffer, fieldName, (int[]) value);
- } else {
- appendSummary(buffer, fieldName, (int[]) value);
- }
-
- } else if (value instanceof short[]) {
- if (detail) {
- appendDetail(buffer, fieldName, (short[]) value);
- } else {
- appendSummary(buffer, fieldName, (short[]) value);
- }
-
- } else if (value instanceof byte[]) {
- if (detail) {
- appendDetail(buffer, fieldName, (byte[]) value);
- } else {
- appendSummary(buffer, fieldName, (byte[]) value);
- }
-
- } else if (value instanceof char[]) {
- if (detail) {
- appendDetail(buffer, fieldName, (char[]) value);
- } else {
- appendSummary(buffer, fieldName, (char[]) value);
- }
-
- } else if (value instanceof double[]) {
- if (detail) {
- appendDetail(buffer, fieldName, (double[]) value);
- } else {
- appendSummary(buffer, fieldName, (double[]) value);
- }
-
- } else if (value instanceof float[]) {
- if (detail) {
- appendDetail(buffer, fieldName, (float[]) value);
- } else {
- appendSummary(buffer, fieldName, (float[]) value);
- }
-
- } else if (value instanceof boolean[]) {
- if (detail) {
- appendDetail(buffer, fieldName, (boolean[]) value);
- } else {
- appendSummary(buffer, fieldName, (boolean[]) value);
- }
-
- } else if (value.getClass().isArray()) {
- if (detail) {
- appendDetail(buffer, fieldName, (Object[]) value);
- } else {
- appendSummary(buffer, fieldName, (Object[]) value);
- }
-
- } else {
- if (detail) {
- appendDetail(buffer, fieldName, value);
- } else {
- appendSummary(buffer, fieldName, value);
- }
- }
- } finally {
- unregister(value);
- }
- }
-
- /**
- * Append to the toString an Object
- * value that has been detected to participate in a cycle. This
- * implementation will print the standard string value of the value.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param value the value to add to the toString,
- * not null
- *
- * @since 2.2
- */
- protected void appendCyclicObject(StringBuffer buffer, String fieldName, Object value) {
- ObjectUtils.identityToString(buffer, value);
- }
-
- /**
- * Append to the toString an Object
- * value, printing the full detail of the Object.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param value the value to add to the toString,
- * not null
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
- buffer.append(value);
- }
-
- /**
- * Append to the toString a Collection.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param coll the Collection to add to the
- * toString, not null
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, Collection> coll) {
- buffer.append(coll);
- }
-
- /**
- * Append to the toString a Map.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param map the Map to add to the toString,
- * not null
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, Map, ?> map) {
- buffer.append(map);
- }
-
- /**
- * Append to the toString an Object
- * value, printing a summary of the Object.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param value the value to add to the toString,
- * not null
- */
- protected void appendSummary(StringBuffer buffer, String fieldName, Object value) {
- buffer.append(summaryObjectStartText);
- buffer.append(getShortClassName(value.getClass()));
- buffer.append(summaryObjectEndText);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a long
- * value.
StringBuffer to populate
- * @param fieldName the field name
- * @param value the value to add to the toString
- */
- public void append(StringBuffer buffer, String fieldName, long value) {
- appendFieldStart(buffer, fieldName);
- appendDetail(buffer, fieldName, value);
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString a long
- * value.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param value the value to add to the toString
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, long value) {
- buffer.append(value);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString an int
- * value.
StringBuffer to populate
- * @param fieldName the field name
- * @param value the value to add to the toString
- */
- public void append(StringBuffer buffer, String fieldName, int value) {
- appendFieldStart(buffer, fieldName);
- appendDetail(buffer, fieldName, value);
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString an int
- * value.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param value the value to add to the toString
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, int value) {
- buffer.append(value);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a short
- * value.
StringBuffer to populate
- * @param fieldName the field name
- * @param value the value to add to the toString
- */
- public void append(StringBuffer buffer, String fieldName, short value) {
- appendFieldStart(buffer, fieldName);
- appendDetail(buffer, fieldName, value);
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString a short
- * value.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param value the value to add to the toString
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, short value) {
- buffer.append(value);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a byte
- * value.
StringBuffer to populate
- * @param fieldName the field name
- * @param value the value to add to the toString
- */
- public void append(StringBuffer buffer, String fieldName, byte value) {
- appendFieldStart(buffer, fieldName);
- appendDetail(buffer, fieldName, value);
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString a byte
- * value.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param value the value to add to the toString
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, byte value) {
- buffer.append(value);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a char
- * value.
StringBuffer to populate
- * @param fieldName the field name
- * @param value the value to add to the toString
- */
- public void append(StringBuffer buffer, String fieldName, char value) {
- appendFieldStart(buffer, fieldName);
- appendDetail(buffer, fieldName, value);
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString a char
- * value.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param value the value to add to the toString
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, char value) {
- buffer.append(value);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a double
- * value.
StringBuffer to populate
- * @param fieldName the field name
- * @param value the value to add to the toString
- */
- public void append(StringBuffer buffer, String fieldName, double value) {
- appendFieldStart(buffer, fieldName);
- appendDetail(buffer, fieldName, value);
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString a double
- * value.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param value the value to add to the toString
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, double value) {
- buffer.append(value);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a float
- * value.
StringBuffer to populate
- * @param fieldName the field name
- * @param value the value to add to the toString
- */
- public void append(StringBuffer buffer, String fieldName, float value) {
- appendFieldStart(buffer, fieldName);
- appendDetail(buffer, fieldName, value);
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString a float
- * value.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param value the value to add to the toString
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, float value) {
- buffer.append(value);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a boolean
- * value.
StringBuffer to populate
- * @param fieldName the field name
- * @param value the value to add to the toString
- */
- public void append(StringBuffer buffer, String fieldName, boolean value) {
- appendFieldStart(buffer, fieldName);
- appendDetail(buffer, fieldName, value);
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString a boolean
- * value.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param value the value to add to the toString
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, boolean value) {
- buffer.append(value);
- }
-
- /**
- * Append to the toString an Object
- * array.
StringBuffer to populate
- * @param fieldName the field name
- * @param array the array to add to the toString
- * @param fullDetail true for detail, false
- * for summary info, null for style decides
- */
- public void append(StringBuffer buffer, String fieldName, Object[] array, Boolean fullDetail) {
- appendFieldStart(buffer, fieldName);
-
- if (array == null) {
- appendNullText(buffer, fieldName);
-
- } else if (isFullDetail(fullDetail)) {
- appendDetail(buffer, fieldName, array);
-
- } else {
- appendSummary(buffer, fieldName, array);
- }
-
- appendFieldEnd(buffer, fieldName);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString the detail of an
- * Object array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, Object[] array) {
- buffer.append(arrayStart);
- for (int i = 0; i < array.length; i++) {
- Object item = array[i];
- if (i > 0) {
- buffer.append(arraySeparator);
- }
- if (item == null) {
- appendNullText(buffer, fieldName);
-
- } else {
- appendInternal(buffer, fieldName, item, arrayContentDetail);
- }
- }
- buffer.append(arrayEnd);
- }
-
- /**
- * Append to the toString the detail of an array type.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- * @since 2.0
- */
- protected void reflectionAppendArrayDetail(StringBuffer buffer, String fieldName, Object array) {
- buffer.append(arrayStart);
- int length = Array.getLength(array);
- for (int i = 0; i < length; i++) {
- Object item = Array.get(array, i);
- if (i > 0) {
- buffer.append(arraySeparator);
- }
- if (item == null) {
- appendNullText(buffer, fieldName);
-
- } else {
- appendInternal(buffer, fieldName, item, arrayContentDetail);
- }
- }
- buffer.append(arrayEnd);
- }
-
- /**
- * Append to the toString a summary of an
- * Object array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendSummary(StringBuffer buffer, String fieldName, Object[] array) {
- appendSummarySize(buffer, fieldName, array.length);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a long
- * array.
StringBuffer to populate
- * @param fieldName the field name
- * @param array the array to add to the toString
- * @param fullDetail true for detail, false
- * for summary info, null for style decides
- */
- public void append(StringBuffer buffer, String fieldName, long[] array, Boolean fullDetail) {
- appendFieldStart(buffer, fieldName);
-
- if (array == null) {
- appendNullText(buffer, fieldName);
-
- } else if (isFullDetail(fullDetail)) {
- appendDetail(buffer, fieldName, array);
-
- } else {
- appendSummary(buffer, fieldName, array);
- }
-
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString the detail of a
- * long array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, long[] array) {
- buffer.append(arrayStart);
- for (int i = 0; i < array.length; i++) {
- if (i > 0) {
- buffer.append(arraySeparator);
- }
- appendDetail(buffer, fieldName, array[i]);
- }
- buffer.append(arrayEnd);
- }
-
- /**
- * Append to the toString a summary of a
- * long array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendSummary(StringBuffer buffer, String fieldName, long[] array) {
- appendSummarySize(buffer, fieldName, array.length);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString an int
- * array.
StringBuffer to populate
- * @param fieldName the field name
- * @param array the array to add to the toString
- * @param fullDetail true for detail, false
- * for summary info, null for style decides
- */
- public void append(StringBuffer buffer, String fieldName, int[] array, Boolean fullDetail) {
- appendFieldStart(buffer, fieldName);
-
- if (array == null) {
- appendNullText(buffer, fieldName);
-
- } else if (isFullDetail(fullDetail)) {
- appendDetail(buffer, fieldName, array);
-
- } else {
- appendSummary(buffer, fieldName, array);
- }
-
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString the detail of an
- * int array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, int[] array) {
- buffer.append(arrayStart);
- for (int i = 0; i < array.length; i++) {
- if (i > 0) {
- buffer.append(arraySeparator);
- }
- appendDetail(buffer, fieldName, array[i]);
- }
- buffer.append(arrayEnd);
- }
-
- /**
- * Append to the toString a summary of an
- * int array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendSummary(StringBuffer buffer, String fieldName, int[] array) {
- appendSummarySize(buffer, fieldName, array.length);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a short
- * array.
StringBuffer to populate
- * @param fieldName the field name
- * @param array the array to add to the toString
- * @param fullDetail true for detail, false
- * for summary info, null for style decides
- */
- public void append(StringBuffer buffer, String fieldName, short[] array, Boolean fullDetail) {
- appendFieldStart(buffer, fieldName);
-
- if (array == null) {
- appendNullText(buffer, fieldName);
-
- } else if (isFullDetail(fullDetail)) {
- appendDetail(buffer, fieldName, array);
-
- } else {
- appendSummary(buffer, fieldName, array);
- }
-
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString the detail of a
- * short array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, short[] array) {
- buffer.append(arrayStart);
- for (int i = 0; i < array.length; i++) {
- if (i > 0) {
- buffer.append(arraySeparator);
- }
- appendDetail(buffer, fieldName, array[i]);
- }
- buffer.append(arrayEnd);
- }
-
- /**
- * Append to the toString a summary of a
- * short array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendSummary(StringBuffer buffer, String fieldName, short[] array) {
- appendSummarySize(buffer, fieldName, array.length);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a byte
- * array.
StringBuffer to populate
- * @param fieldName the field name
- * @param array the array to add to the toString
- * @param fullDetail true for detail, false
- * for summary info, null for style decides
- */
- public void append(StringBuffer buffer, String fieldName, byte[] array, Boolean fullDetail) {
- appendFieldStart(buffer, fieldName);
-
- if (array == null) {
- appendNullText(buffer, fieldName);
-
- } else if (isFullDetail(fullDetail)) {
- appendDetail(buffer, fieldName, array);
-
- } else {
- appendSummary(buffer, fieldName, array);
- }
-
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString the detail of a
- * byte array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, byte[] array) {
- buffer.append(arrayStart);
- for (int i = 0; i < array.length; i++) {
- if (i > 0) {
- buffer.append(arraySeparator);
- }
- appendDetail(buffer, fieldName, array[i]);
- }
- buffer.append(arrayEnd);
- }
-
- /**
- * Append to the toString a summary of a
- * byte array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendSummary(StringBuffer buffer, String fieldName, byte[] array) {
- appendSummarySize(buffer, fieldName, array.length);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a char
- * array.
StringBuffer to populate
- * @param fieldName the field name
- * @param array the array to add to the toString
- * @param fullDetail true for detail, false
- * for summary info, null for style decides
- */
- public void append(StringBuffer buffer, String fieldName, char[] array, Boolean fullDetail) {
- appendFieldStart(buffer, fieldName);
-
- if (array == null) {
- appendNullText(buffer, fieldName);
-
- } else if (isFullDetail(fullDetail)) {
- appendDetail(buffer, fieldName, array);
-
- } else {
- appendSummary(buffer, fieldName, array);
- }
-
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString the detail of a
- * char array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, char[] array) {
- buffer.append(arrayStart);
- for (int i = 0; i < array.length; i++) {
- if (i > 0) {
- buffer.append(arraySeparator);
- }
- appendDetail(buffer, fieldName, array[i]);
- }
- buffer.append(arrayEnd);
- }
-
- /**
- * Append to the toString a summary of a
- * char array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendSummary(StringBuffer buffer, String fieldName, char[] array) {
- appendSummarySize(buffer, fieldName, array.length);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a double
- * array.
StringBuffer to populate
- * @param fieldName the field name
- * @param array the array to add to the toString
- * @param fullDetail true for detail, false
- * for summary info, null for style decides
- */
- public void append(StringBuffer buffer, String fieldName, double[] array, Boolean fullDetail) {
- appendFieldStart(buffer, fieldName);
-
- if (array == null) {
- appendNullText(buffer, fieldName);
-
- } else if (isFullDetail(fullDetail)) {
- appendDetail(buffer, fieldName, array);
-
- } else {
- appendSummary(buffer, fieldName, array);
- }
-
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString the detail of a
- * double array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, double[] array) {
- buffer.append(arrayStart);
- for (int i = 0; i < array.length; i++) {
- if (i > 0) {
- buffer.append(arraySeparator);
- }
- appendDetail(buffer, fieldName, array[i]);
- }
- buffer.append(arrayEnd);
- }
-
- /**
- * Append to the toString a summary of a
- * double array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendSummary(StringBuffer buffer, String fieldName, double[] array) {
- appendSummarySize(buffer, fieldName, array.length);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a float
- * array.
StringBuffer to populate
- * @param fieldName the field name
- * @param array the array to add to the toString
- * @param fullDetail true for detail, false
- * for summary info, null for style decides
- */
- public void append(StringBuffer buffer, String fieldName, float[] array, Boolean fullDetail) {
- appendFieldStart(buffer, fieldName);
-
- if (array == null) {
- appendNullText(buffer, fieldName);
-
- } else if (isFullDetail(fullDetail)) {
- appendDetail(buffer, fieldName, array);
-
- } else {
- appendSummary(buffer, fieldName, array);
- }
-
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString the detail of a
- * float array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, float[] array) {
- buffer.append(arrayStart);
- for (int i = 0; i < array.length; i++) {
- if (i > 0) {
- buffer.append(arraySeparator);
- }
- appendDetail(buffer, fieldName, array[i]);
- }
- buffer.append(arrayEnd);
- }
-
- /**
- * Append to the toString a summary of a
- * float array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendSummary(StringBuffer buffer, String fieldName, float[] array) {
- appendSummarySize(buffer, fieldName, array.length);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString a boolean
- * array.
StringBuffer to populate
- * @param fieldName the field name
- * @param array the array to add to the toString
- * @param fullDetail true for detail, false
- * for summary info, null for style decides
- */
- public void append(StringBuffer buffer, String fieldName, boolean[] array, Boolean fullDetail) {
- appendFieldStart(buffer, fieldName);
-
- if (array == null) {
- appendNullText(buffer, fieldName);
-
- } else if (isFullDetail(fullDetail)) {
- appendDetail(buffer, fieldName, array);
-
- } else {
- appendSummary(buffer, fieldName, array);
- }
-
- appendFieldEnd(buffer, fieldName);
- }
-
- /**
- * Append to the toString the detail of a
- * boolean array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendDetail(StringBuffer buffer, String fieldName, boolean[] array) {
- buffer.append(arrayStart);
- for (int i = 0; i < array.length; i++) {
- if (i > 0) {
- buffer.append(arraySeparator);
- }
- appendDetail(buffer, fieldName, array[i]);
- }
- buffer.append(arrayEnd);
- }
-
- /**
- * Append to the toString a summary of a
- * boolean array.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param array the array to add to the toString,
- * not null
- */
- protected void appendSummary(StringBuffer buffer, String fieldName, boolean[] array) {
- appendSummarySize(buffer, fieldName, array.length);
- }
-
- //----------------------------------------------------------------------------
-
- /**
- * Append to the toString the class name.
StringBuffer to populate
- * @param object the Object whose name to output
- */
- protected void appendClassName(StringBuffer buffer, Object object) {
- if (useClassName && object != null) {
- register(object);
- if (useShortClassName) {
- buffer.append(getShortClassName(object.getClass()));
- } else {
- buffer.append(object.getClass().getName());
- }
- }
- }
-
- /**
- * Append the {@link System#identityHashCode(java.lang.Object)}.
- * - * @param buffer theStringBuffer to populate
- * @param object the Object whose id to output
- */
- protected void appendIdentityHashCode(StringBuffer buffer, Object object) {
- if (this.isUseIdentityHashCode() && object!=null) {
- register(object);
- buffer.append('@');
- buffer.append(Integer.toHexString(System.identityHashCode(object)));
- }
- }
-
- /**
- * Append to the toString the content start.
StringBuffer to populate
- */
- protected void appendContentStart(StringBuffer buffer) {
- buffer.append(contentStart);
- }
-
- /**
- * Append to the toString the content end.
StringBuffer to populate
- */
- protected void appendContentEnd(StringBuffer buffer) {
- buffer.append(contentEnd);
- }
-
- /**
- * Append to the toString an indicator for null.
The default indicator is '<null>'.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- */
- protected void appendNullText(StringBuffer buffer, String fieldName) {
- buffer.append(nullText);
- }
-
- /**
- * Append to the toString the field separator.
StringBuffer to populate
- */
- protected void appendFieldSeparator(StringBuffer buffer) {
- buffer.append(fieldSeparator);
- }
-
- /**
- * Append to the toString the field start.
StringBuffer to populate
- * @param fieldName the field name
- */
- protected void appendFieldStart(StringBuffer buffer, String fieldName) {
- if (useFieldNames && fieldName != null) {
- buffer.append(fieldName);
- buffer.append(fieldNameValueSeparator);
- }
- }
-
- /**
- * Append to the toString the field end.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- */
- protected void appendFieldEnd(StringBuffer buffer, String fieldName) {
- appendFieldSeparator(buffer);
- }
-
- /**
- * Append to the toString a size summary.
The size summary is used to summarize the contents of
- * Collections, Maps and arrays.
The output consists of a prefix, the passed in size - * and a suffix.
- * - *The default format is '<size=n>'.
StringBuffer to populate
- * @param fieldName the field name, typically not used as already appended
- * @param size the size to append
- */
- protected void appendSummarySize(StringBuffer buffer, String fieldName, int size) {
- buffer.append(sizeStartText);
- buffer.append(size);
- buffer.append(sizeEndText);
- }
-
- /**
- * Is this field to be output in full detail.
- * - *This method converts a detail request into a detail level.
- * The calling code may request full detail (true),
- * but a subclass might ignore that and always return
- * false. The calling code may pass in
- * null indicating that it doesn't care about
- * the detail level. In this case the default detail level is
- * used.
Gets the short class name for a class.
- * - *The short class name is the classname excluding - * the package name.
- * - * @param cls theClass to get the short name of
- * @return the short name
- */
- protected String getShortClassName(Class> cls) {
- return ClassUtils.getShortClassName(cls);
- }
-
- // Setters and getters for the customizable parts of the style
- // These methods are not expected to be overridden, except to make public
- // (They are not public so that immutable subclasses can be written)
- //---------------------------------------------------------------------
-
- /**
- * Gets whether to use the class name.
- * - * @return the current useClassName flag - */ - protected boolean isUseClassName() { - return useClassName; - } - - /** - *Sets whether to use the class name.
- * - * @param useClassName the new useClassName flag - */ - protected void setUseClassName(boolean useClassName) { - this.useClassName = useClassName; - } - - //--------------------------------------------------------------------- - - /** - *Gets whether to output short or long class names.
- * - * @return the current useShortClassName flag - * @since 2.0 - */ - protected boolean isUseShortClassName() { - return useShortClassName; - } - - /** - *Sets whether to output short or long class names.
- * - * @param useShortClassName the new useShortClassName flag - * @since 2.0 - */ - protected void setUseShortClassName(boolean useShortClassName) { - this.useShortClassName = useShortClassName; - } - - //--------------------------------------------------------------------- - - /** - *Gets whether to use the identity hash code.
- * - * @return the current useIdentityHashCode flag - */ - protected boolean isUseIdentityHashCode() { - return useIdentityHashCode; - } - - /** - *Sets whether to use the identity hash code.
- * - * @param useIdentityHashCode the new useIdentityHashCode flag - */ - protected void setUseIdentityHashCode(boolean useIdentityHashCode) { - this.useIdentityHashCode = useIdentityHashCode; - } - - //--------------------------------------------------------------------- - - /** - *Gets whether to use the field names passed in.
- * - * @return the current useFieldNames flag - */ - protected boolean isUseFieldNames() { - return useFieldNames; - } - - /** - *Sets whether to use the field names passed in.
- * - * @param useFieldNames the new useFieldNames flag - */ - protected void setUseFieldNames(boolean useFieldNames) { - this.useFieldNames = useFieldNames; - } - - //--------------------------------------------------------------------- - - /** - *Gets whether to use full detail when the caller doesn't - * specify.
- * - * @return the current defaultFullDetail flag - */ - protected boolean isDefaultFullDetail() { - return defaultFullDetail; - } - - /** - *Sets whether to use full detail when the caller doesn't - * specify.
- * - * @param defaultFullDetail the new defaultFullDetail flag - */ - protected void setDefaultFullDetail(boolean defaultFullDetail) { - this.defaultFullDetail = defaultFullDetail; - } - - //--------------------------------------------------------------------- - - /** - *Gets whether to output array content detail.
- * - * @return the current array content detail setting - */ - protected boolean isArrayContentDetail() { - return arrayContentDetail; - } - - /** - *Sets whether to output array content detail.
- * - * @param arrayContentDetail the new arrayContentDetail flag - */ - protected void setArrayContentDetail(boolean arrayContentDetail) { - this.arrayContentDetail = arrayContentDetail; - } - - //--------------------------------------------------------------------- - - /** - *Gets the array start text.
- * - * @return the current array start text - */ - protected String getArrayStart() { - return arrayStart; - } - - /** - *Sets the array start text.
- * - *null is accepted, but will be converted to
- * an empty String.
Gets the array end text.
- * - * @return the current array end text - */ - protected String getArrayEnd() { - return arrayEnd; - } - - /** - *Sets the array end text.
- * - *null is accepted, but will be converted to
- * an empty String.
Gets the array separator text.
- * - * @return the current array separator text - */ - protected String getArraySeparator() { - return arraySeparator; - } - - /** - *Sets the array separator text.
- * - *null is accepted, but will be converted to
- * an empty String.
Gets the content start text.
- * - * @return the current content start text - */ - protected String getContentStart() { - return contentStart; - } - - /** - *Sets the content start text.
- * - *null is accepted, but will be converted to
- * an empty String.
Gets the content end text.
- * - * @return the current content end text - */ - protected String getContentEnd() { - return contentEnd; - } - - /** - *Sets the content end text.
- * - *null is accepted, but will be converted to
- * an empty String.
Gets the field name value separator text.
- * - * @return the current field name value separator text - */ - protected String getFieldNameValueSeparator() { - return fieldNameValueSeparator; - } - - /** - *Sets the field name value separator text.
- * - *null is accepted, but will be converted to
- * an empty String.
Gets the field separator text.
- * - * @return the current field separator text - */ - protected String getFieldSeparator() { - return fieldSeparator; - } - - /** - *Sets the field separator text.
- * - *null is accepted, but will be converted to
- * an empty String.
Gets whether the field separator should be added at the start - * of each buffer.
- * - * @return the fieldSeparatorAtStart flag - * @since 2.0 - */ - protected boolean isFieldSeparatorAtStart() { - return fieldSeparatorAtStart; - } - - /** - *Sets whether the field separator should be added at the start - * of each buffer.
- * - * @param fieldSeparatorAtStart the fieldSeparatorAtStart flag - * @since 2.0 - */ - protected void setFieldSeparatorAtStart(boolean fieldSeparatorAtStart) { - this.fieldSeparatorAtStart = fieldSeparatorAtStart; - } - - //--------------------------------------------------------------------- - - /** - *Gets whether the field separator should be added at the end - * of each buffer.
- * - * @return fieldSeparatorAtEnd flag - * @since 2.0 - */ - protected boolean isFieldSeparatorAtEnd() { - return fieldSeparatorAtEnd; - } - - /** - *Sets whether the field separator should be added at the end - * of each buffer.
- * - * @param fieldSeparatorAtEnd the fieldSeparatorAtEnd flag - * @since 2.0 - */ - protected void setFieldSeparatorAtEnd(boolean fieldSeparatorAtEnd) { - this.fieldSeparatorAtEnd = fieldSeparatorAtEnd; - } - - //--------------------------------------------------------------------- - - /** - *Gets the text to output when null found.
Sets the text to output when null found.
null is accepted, but will be converted to
- * an empty String.
Gets the start text to output when a Collection,
- * Map or array size is output.
This is output before the size value.
- * - * @return the current start of size text - */ - protected String getSizeStartText() { - return sizeStartText; - } - - /** - *Sets the start text to output when a Collection,
- * Map or array size is output.
This is output before the size value.
- * - *null is accepted, but will be converted to
- * an empty String.
Gets the end text to output when a Collection,
- * Map or array size is output.
This is output after the size value.
- * - * @return the current end of size text - */ - protected String getSizeEndText() { - return sizeEndText; - } - - /** - *Sets the end text to output when a Collection,
- * Map or array size is output.
This is output after the size value.
- * - *null is accepted, but will be converted to
- * an empty String.
Gets the start text to output when an Object is
- * output in summary mode.
This is output before the size value.
- * - * @return the current start of summary text - */ - protected String getSummaryObjectStartText() { - return summaryObjectStartText; - } - - /** - *Sets the start text to output when an Object is
- * output in summary mode.
This is output before the size value.
- * - *null is accepted, but will be converted to
- * an empty String.
Gets the end text to output when an Object is
- * output in summary mode.
This is output after the size value.
- * - * @return the current end of summary text - */ - protected String getSummaryObjectEndText() { - return summaryObjectEndText; - } - - /** - *Sets the end text to output when an Object is
- * output in summary mode.
This is output after the size value.
- * - *null is accepted, but will be converted to
- * an empty String.
Default ToStringStyle.
This is an inner class rather than using
- * StandardToStringStyle to ensure its immutability.
Constructor.
- * - *Use the static constant rather than instantiating.
- */ - DefaultToStringStyle() { - super(); - } - - /** - *Ensure Singleton after serialization.
ToStringStyle that does not print out
- * the field names.
This is an inner class rather than using
- * StandardToStringStyle to ensure its immutability.
- */
- private static final class NoFieldNameToStringStyle extends ToStringStyle {
-
- private static final long serialVersionUID = 1L;
-
- /**
- *
Constructor.
- * - *Use the static constant rather than instantiating.
- */ - NoFieldNameToStringStyle() { - super(); - this.setUseFieldNames(false); - } - - /** - *Ensure Singleton after serialization.
ToStringStyle that prints out the short
- * class name and no identity hashcode.
This is an inner class rather than using
- * StandardToStringStyle to ensure its immutability.
Constructor.
- * - *Use the static constant rather than instantiating.
- */ - ShortPrefixToStringStyle() { - super(); - this.setUseShortClassName(true); - this.setUseIdentityHashCode(false); - } - - /** - *Ensure Singleton after serialization.
ToStringStyle that does not print out the
- * classname, identity hashcode, content start or field name.
This is an inner class rather than using
- * StandardToStringStyle to ensure its immutability.
Constructor.
- * - *Use the static constant rather than instantiating.
- */ - SimpleToStringStyle() { - super(); - this.setUseClassName(false); - this.setUseIdentityHashCode(false); - this.setUseFieldNames(false); - this.setContentStart(""); - this.setContentEnd(""); - } - - /** - *Ensure Singleton after serialization.
ToStringStyle that outputs on multiple lines.
This is an inner class rather than using
- * StandardToStringStyle to ensure its immutability.
Constructor.
- * - *Use the static constant rather than instantiating.
- */ - MultiLineToStringStyle() { - super(); - this.setContentStart("["); - this.setFieldSeparator(SystemUtils.LINE_SEPARATOR + " "); - this.setFieldSeparatorAtStart(true); - this.setContentEnd(SystemUtils.LINE_SEPARATOR + "]"); - } - - /** - *Ensure Singleton after serialization.
Controls String formatting for {@link ToStringBuilder}.
+ * The main public interface is always via ToStringBuilder.
These classes are intended to be used as Singletons.
+ * There is no need to instantiate a new style each time. A program
+ * will generally use one of the predefined constants on this class.
+ * Alternatively, the {@link StandardToStringStyle} class can be used
+ * to set the individual settings. Thus most styles can be achieved
+ * without subclassing.
If required, a subclass can override as many or as few of the
+ * methods as it requires. Each object type (from boolean
+ * to long to Object to int[]) has
+ * its own methods to output it. Most have two versions, detail and summary.
+ *
+ *
For example, the detail version of the array based methods will + * output the whole array, whereas the summary method will just output + * the array length.
+ * + *If you want to format the output of certain objects, such as dates, you + * must create a subclass and override a method. + *
+ * public class MyStyle extends ToStringStyle {
+ * protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
+ * if (value instanceof Date) {
+ * value = new SimpleDateFormat("yyyy-MM-dd").format(value);
+ * }
+ * buffer.append(value);
+ * }
+ * }
+ *
+ *
+ *
+ * @since 1.0
+ * @version $Id: ToStringStyle.java 1091066 2011-04-11 13:30:11Z mbenson $
+ */
+public abstract class ToStringStyle implements Serializable {
+
+ /**
+ * Serialization version ID.
+ */
+ private static final long serialVersionUID = -2587890625525655916L;
+
+ /**
+ * The default toString style. Using the Using the Person
+ * example from {@link ToStringBuilder}, the output would look like this:
+ *
+ * + * Person@182f0db[name=John Doe,age=33,smoker=false] + *+ */ + public static final ToStringStyle DEFAULT_STYLE = new DefaultToStringStyle(); + + /** + * The multi line toString style. Using the Using the
Person
+ * example from {@link ToStringBuilder}, the output would look like this:
+ *
+ * + * Person@182f0db[ + * name=John Doe + * age=33 + * smoker=false + * ] + *+ */ + public static final ToStringStyle MULTI_LINE_STYLE = new MultiLineToStringStyle(); + + /** + * The no field names toString style. Using the Using the + *
Person example from {@link ToStringBuilder}, the output
+ * would look like this:
+ *
+ * + * Person@182f0db[John Doe,33,false] + *+ */ + public static final ToStringStyle NO_FIELD_NAMES_STYLE = new NoFieldNameToStringStyle(); + + /** + * The short prefix toString style. Using the
Person example
+ * from {@link ToStringBuilder}, the output would look like this:
+ *
+ * + * Person[name=John Doe,age=33,smoker=false] + *+ * + * @since 2.1 + */ + public static final ToStringStyle SHORT_PREFIX_STYLE = new ShortPrefixToStringStyle(); + + /** + * The simple toString style. Using the Using the
Person
+ * example from {@link ToStringBuilder}, the output would look like this:
+ *
+ * + * John Doe,33,false + *+ */ + public static final ToStringStyle SIMPLE_STYLE = new SimpleToStringStyle(); + + /** + *
+ * A registry of objects used by reflectionToString methods
+ * to detect cyclical object references and avoid infinite loops.
+ *
+ * Returns the registry of objects being traversed by the reflectionToString
+ * methods in the current thread.
+ *
+ * Returns true if the registry contains the given object.
+ * Used by the reflection methods to avoid infinite loops.
+ *
true if the registry contains the given
+ * object.
+ */
+ static boolean isRegistered(Object value) {
+ Map+ * Registers the given object. Used by the reflection methods to avoid + * infinite loops. + *
+ * + * @param value + * The object to register. + */ + static void register(Object value) { + if (value != null) { + Map+ * Unregisters the given object. + *
+ * + *+ * Used by the reflection methods to avoid infinite loops. + *
+ * + * @param value + * The object to unregister. + */ + static void unregister(Object value) { + if (value != null) { + Maptrue.
+ */
+ private boolean useFieldNames = true;
+
+ /**
+ * Whether to use the class name, the default is true.
+ */
+ private boolean useClassName = true;
+
+ /**
+ * Whether to use short class names, the default is false.
+ */
+ private boolean useShortClassName = false;
+
+ /**
+ * Whether to use the identity hash code, the default is true.
+ */
+ private boolean useIdentityHashCode = true;
+
+ /**
+ * The content start '['.
+ */
+ private String contentStart = "[";
+
+ /**
+ * The content end ']'.
+ */
+ private String contentEnd = "]";
+
+ /**
+ * The field name value separator '='.
+ */
+ private String fieldNameValueSeparator = "=";
+
+ /**
+ * Whether the field separator should be added before any other fields.
+ */
+ private boolean fieldSeparatorAtStart = false;
+
+ /**
+ * Whether the field separator should be added after any other fields.
+ */
+ private boolean fieldSeparatorAtEnd = false;
+
+ /**
+ * The field separator ','.
+ */
+ private String fieldSeparator = ",";
+
+ /**
+ * The array start '{'.
+ */
+ private String arrayStart = "{";
+
+ /**
+ * The array separator ','.
+ */
+ private String arraySeparator = ",";
+
+ /**
+ * The detail for array content.
+ */
+ private boolean arrayContentDetail = true;
+
+ /**
+ * The array end '}'.
+ */
+ private String arrayEnd = "}";
+
+ /**
+ * The value to use when fullDetail is null,
+ * the default value is true.
+ */
+ private boolean defaultFullDetail = true;
+
+ /**
+ * The null text '<null>'.
+ */
+ private String nullText = "'.
+ */
+ private String sizeStartText = "'>' .
+ */
+ private String sizeEndText = ">";
+
+ /**
+ * The summary object text start '<'.
+ */
+ private String summaryObjectStartText = "<";
+
+ /**
+ * The summary object text start '>'.
+ */
+ private String summaryObjectEndText = ">";
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ */ + protected ToStringStyle() { + super(); + } + + //---------------------------------------------------------------------------- + + /** + *Append to the toString the superclass toString.
NOTE: It assumes that the toString has been created from the same ToStringStyle.
+ * + *A null superToString is ignored.
StringBuffer to populate
+ * @param superToString the super.toString()
+ * @since 2.0
+ */
+ public void appendSuper(StringBuffer buffer, String superToString) {
+ appendToString(buffer, superToString);
+ }
+
+ /**
+ * Append to the toString another toString.
NOTE: It assumes that the toString has been created from the same ToStringStyle.
+ * + *A null toString is ignored.
StringBuffer to populate
+ * @param toString the additional toString
+ * @since 2.0
+ */
+ public void appendToString(StringBuffer buffer, String toString) {
+ if (toString != null) {
+ int pos1 = toString.indexOf(contentStart) + contentStart.length();
+ int pos2 = toString.lastIndexOf(contentEnd);
+ if (pos1 != pos2 && pos1 >= 0 && pos2 >= 0) {
+ String data = toString.substring(pos1, pos2);
+ if (fieldSeparatorAtStart) {
+ removeLastFieldSeparator(buffer);
+ }
+ buffer.append(data);
+ appendFieldSeparator(buffer);
+ }
+ }
+ }
+
+ /**
+ * Append to the toString the start of data indicator.
StringBuffer to populate
+ * @param object the Object to build a toString for
+ */
+ public void appendStart(StringBuffer buffer, Object object) {
+ if (object != null) {
+ appendClassName(buffer, object);
+ appendIdentityHashCode(buffer, object);
+ appendContentStart(buffer);
+ if (fieldSeparatorAtStart) {
+ appendFieldSeparator(buffer);
+ }
+ }
+ }
+
+ /**
+ * Append to the toString the end of data indicator.
StringBuffer to populate
+ * @param object the Object to build a
+ * toString for.
+ */
+ public void appendEnd(StringBuffer buffer, Object object) {
+ if (this.fieldSeparatorAtEnd == false) {
+ removeLastFieldSeparator(buffer);
+ }
+ appendContentEnd(buffer);
+ unregister(object);
+ }
+
+ /**
+ * Remove the last field separator from the buffer.
+ * + * @param buffer theStringBuffer to populate
+ * @since 2.0
+ */
+ protected void removeLastFieldSeparator(StringBuffer buffer) {
+ int len = buffer.length();
+ int sepLen = fieldSeparator.length();
+ if (len > 0 && sepLen > 0 && len >= sepLen) {
+ boolean match = true;
+ for (int i = 0; i < sepLen; i++) {
+ if (buffer.charAt(len - 1 - i) != fieldSeparator.charAt(sepLen - 1 - i)) {
+ match = false;
+ break;
+ }
+ }
+ if (match) {
+ buffer.setLength(len - sepLen);
+ }
+ }
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString an Object
+ * value, printing the full toString of the
+ * Object passed in.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param value the value to add to the toString
+ * @param fullDetail true for detail, false
+ * for summary info, null for style decides
+ */
+ public void append(StringBuffer buffer, String fieldName, Object value, Boolean fullDetail) {
+ appendFieldStart(buffer, fieldName);
+
+ if (value == null) {
+ appendNullText(buffer, fieldName);
+
+ } else {
+ appendInternal(buffer, fieldName, value, isFullDetail(fullDetail));
+ }
+
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString an Object,
+ * correctly interpreting its type.
This method performs the main lookup by Class type to correctly
+ * route arrays, Collections, Maps and
+ * Objects to the appropriate method.
Either detail or summary views can be specified.
+ * + *If a cycle is detected, an object will be appended with the
+ * Object.toString() format.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param value the value to add to the toString,
+ * not null
+ * @param detail output detail or not
+ */
+ protected void appendInternal(StringBuffer buffer, String fieldName, Object value, boolean detail) {
+ if (isRegistered(value)
+ && !(value instanceof Number || value instanceof Boolean || value instanceof Character)) {
+ appendCyclicObject(buffer, fieldName, value);
+ return;
+ }
+
+ register(value);
+
+ try {
+ if (value instanceof Collection>) {
+ if (detail) {
+ appendDetail(buffer, fieldName, (Collection>) value);
+ } else {
+ appendSummarySize(buffer, fieldName, ((Collection>) value).size());
+ }
+
+ } else if (value instanceof Map, ?>) {
+ if (detail) {
+ appendDetail(buffer, fieldName, (Map, ?>) value);
+ } else {
+ appendSummarySize(buffer, fieldName, ((Map, ?>) value).size());
+ }
+
+ } else if (value instanceof long[]) {
+ if (detail) {
+ appendDetail(buffer, fieldName, (long[]) value);
+ } else {
+ appendSummary(buffer, fieldName, (long[]) value);
+ }
+
+ } else if (value instanceof int[]) {
+ if (detail) {
+ appendDetail(buffer, fieldName, (int[]) value);
+ } else {
+ appendSummary(buffer, fieldName, (int[]) value);
+ }
+
+ } else if (value instanceof short[]) {
+ if (detail) {
+ appendDetail(buffer, fieldName, (short[]) value);
+ } else {
+ appendSummary(buffer, fieldName, (short[]) value);
+ }
+
+ } else if (value instanceof byte[]) {
+ if (detail) {
+ appendDetail(buffer, fieldName, (byte[]) value);
+ } else {
+ appendSummary(buffer, fieldName, (byte[]) value);
+ }
+
+ } else if (value instanceof char[]) {
+ if (detail) {
+ appendDetail(buffer, fieldName, (char[]) value);
+ } else {
+ appendSummary(buffer, fieldName, (char[]) value);
+ }
+
+ } else if (value instanceof double[]) {
+ if (detail) {
+ appendDetail(buffer, fieldName, (double[]) value);
+ } else {
+ appendSummary(buffer, fieldName, (double[]) value);
+ }
+
+ } else if (value instanceof float[]) {
+ if (detail) {
+ appendDetail(buffer, fieldName, (float[]) value);
+ } else {
+ appendSummary(buffer, fieldName, (float[]) value);
+ }
+
+ } else if (value instanceof boolean[]) {
+ if (detail) {
+ appendDetail(buffer, fieldName, (boolean[]) value);
+ } else {
+ appendSummary(buffer, fieldName, (boolean[]) value);
+ }
+
+ } else if (value.getClass().isArray()) {
+ if (detail) {
+ appendDetail(buffer, fieldName, (Object[]) value);
+ } else {
+ appendSummary(buffer, fieldName, (Object[]) value);
+ }
+
+ } else {
+ if (detail) {
+ appendDetail(buffer, fieldName, value);
+ } else {
+ appendSummary(buffer, fieldName, value);
+ }
+ }
+ } finally {
+ unregister(value);
+ }
+ }
+
+ /**
+ * Append to the toString an Object
+ * value that has been detected to participate in a cycle. This
+ * implementation will print the standard string value of the value.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param value the value to add to the toString,
+ * not null
+ *
+ * @since 2.2
+ */
+ protected void appendCyclicObject(StringBuffer buffer, String fieldName, Object value) {
+ ObjectUtils.identityToString(buffer, value);
+ }
+
+ /**
+ * Append to the toString an Object
+ * value, printing the full detail of the Object.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param value the value to add to the toString,
+ * not null
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
+ buffer.append(value);
+ }
+
+ /**
+ * Append to the toString a Collection.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param coll the Collection to add to the
+ * toString, not null
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, Collection> coll) {
+ buffer.append(coll);
+ }
+
+ /**
+ * Append to the toString a Map.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param map the Map to add to the toString,
+ * not null
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, Map, ?> map) {
+ buffer.append(map);
+ }
+
+ /**
+ * Append to the toString an Object
+ * value, printing a summary of the Object.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param value the value to add to the toString,
+ * not null
+ */
+ protected void appendSummary(StringBuffer buffer, String fieldName, Object value) {
+ buffer.append(summaryObjectStartText);
+ buffer.append(getShortClassName(value.getClass()));
+ buffer.append(summaryObjectEndText);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a long
+ * value.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param value the value to add to the toString
+ */
+ public void append(StringBuffer buffer, String fieldName, long value) {
+ appendFieldStart(buffer, fieldName);
+ appendDetail(buffer, fieldName, value);
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString a long
+ * value.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param value the value to add to the toString
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, long value) {
+ buffer.append(value);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString an int
+ * value.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param value the value to add to the toString
+ */
+ public void append(StringBuffer buffer, String fieldName, int value) {
+ appendFieldStart(buffer, fieldName);
+ appendDetail(buffer, fieldName, value);
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString an int
+ * value.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param value the value to add to the toString
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, int value) {
+ buffer.append(value);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a short
+ * value.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param value the value to add to the toString
+ */
+ public void append(StringBuffer buffer, String fieldName, short value) {
+ appendFieldStart(buffer, fieldName);
+ appendDetail(buffer, fieldName, value);
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString a short
+ * value.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param value the value to add to the toString
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, short value) {
+ buffer.append(value);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a byte
+ * value.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param value the value to add to the toString
+ */
+ public void append(StringBuffer buffer, String fieldName, byte value) {
+ appendFieldStart(buffer, fieldName);
+ appendDetail(buffer, fieldName, value);
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString a byte
+ * value.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param value the value to add to the toString
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, byte value) {
+ buffer.append(value);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a char
+ * value.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param value the value to add to the toString
+ */
+ public void append(StringBuffer buffer, String fieldName, char value) {
+ appendFieldStart(buffer, fieldName);
+ appendDetail(buffer, fieldName, value);
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString a char
+ * value.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param value the value to add to the toString
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, char value) {
+ buffer.append(value);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a double
+ * value.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param value the value to add to the toString
+ */
+ public void append(StringBuffer buffer, String fieldName, double value) {
+ appendFieldStart(buffer, fieldName);
+ appendDetail(buffer, fieldName, value);
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString a double
+ * value.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param value the value to add to the toString
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, double value) {
+ buffer.append(value);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a float
+ * value.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param value the value to add to the toString
+ */
+ public void append(StringBuffer buffer, String fieldName, float value) {
+ appendFieldStart(buffer, fieldName);
+ appendDetail(buffer, fieldName, value);
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString a float
+ * value.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param value the value to add to the toString
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, float value) {
+ buffer.append(value);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a boolean
+ * value.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param value the value to add to the toString
+ */
+ public void append(StringBuffer buffer, String fieldName, boolean value) {
+ appendFieldStart(buffer, fieldName);
+ appendDetail(buffer, fieldName, value);
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString a boolean
+ * value.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param value the value to add to the toString
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, boolean value) {
+ buffer.append(value);
+ }
+
+ /**
+ * Append to the toString an Object
+ * array.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param array the array to add to the toString
+ * @param fullDetail true for detail, false
+ * for summary info, null for style decides
+ */
+ public void append(StringBuffer buffer, String fieldName, Object[] array, Boolean fullDetail) {
+ appendFieldStart(buffer, fieldName);
+
+ if (array == null) {
+ appendNullText(buffer, fieldName);
+
+ } else if (isFullDetail(fullDetail)) {
+ appendDetail(buffer, fieldName, array);
+
+ } else {
+ appendSummary(buffer, fieldName, array);
+ }
+
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString the detail of an
+ * Object array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, Object[] array) {
+ buffer.append(arrayStart);
+ for (int i = 0; i < array.length; i++) {
+ Object item = array[i];
+ if (i > 0) {
+ buffer.append(arraySeparator);
+ }
+ if (item == null) {
+ appendNullText(buffer, fieldName);
+
+ } else {
+ appendInternal(buffer, fieldName, item, arrayContentDetail);
+ }
+ }
+ buffer.append(arrayEnd);
+ }
+
+ /**
+ * Append to the toString the detail of an array type.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ * @since 2.0
+ */
+ protected void reflectionAppendArrayDetail(StringBuffer buffer, String fieldName, Object array) {
+ buffer.append(arrayStart);
+ int length = Array.getLength(array);
+ for (int i = 0; i < length; i++) {
+ Object item = Array.get(array, i);
+ if (i > 0) {
+ buffer.append(arraySeparator);
+ }
+ if (item == null) {
+ appendNullText(buffer, fieldName);
+
+ } else {
+ appendInternal(buffer, fieldName, item, arrayContentDetail);
+ }
+ }
+ buffer.append(arrayEnd);
+ }
+
+ /**
+ * Append to the toString a summary of an
+ * Object array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendSummary(StringBuffer buffer, String fieldName, Object[] array) {
+ appendSummarySize(buffer, fieldName, array.length);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a long
+ * array.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param array the array to add to the toString
+ * @param fullDetail true for detail, false
+ * for summary info, null for style decides
+ */
+ public void append(StringBuffer buffer, String fieldName, long[] array, Boolean fullDetail) {
+ appendFieldStart(buffer, fieldName);
+
+ if (array == null) {
+ appendNullText(buffer, fieldName);
+
+ } else if (isFullDetail(fullDetail)) {
+ appendDetail(buffer, fieldName, array);
+
+ } else {
+ appendSummary(buffer, fieldName, array);
+ }
+
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString the detail of a
+ * long array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, long[] array) {
+ buffer.append(arrayStart);
+ for (int i = 0; i < array.length; i++) {
+ if (i > 0) {
+ buffer.append(arraySeparator);
+ }
+ appendDetail(buffer, fieldName, array[i]);
+ }
+ buffer.append(arrayEnd);
+ }
+
+ /**
+ * Append to the toString a summary of a
+ * long array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendSummary(StringBuffer buffer, String fieldName, long[] array) {
+ appendSummarySize(buffer, fieldName, array.length);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString an int
+ * array.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param array the array to add to the toString
+ * @param fullDetail true for detail, false
+ * for summary info, null for style decides
+ */
+ public void append(StringBuffer buffer, String fieldName, int[] array, Boolean fullDetail) {
+ appendFieldStart(buffer, fieldName);
+
+ if (array == null) {
+ appendNullText(buffer, fieldName);
+
+ } else if (isFullDetail(fullDetail)) {
+ appendDetail(buffer, fieldName, array);
+
+ } else {
+ appendSummary(buffer, fieldName, array);
+ }
+
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString the detail of an
+ * int array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, int[] array) {
+ buffer.append(arrayStart);
+ for (int i = 0; i < array.length; i++) {
+ if (i > 0) {
+ buffer.append(arraySeparator);
+ }
+ appendDetail(buffer, fieldName, array[i]);
+ }
+ buffer.append(arrayEnd);
+ }
+
+ /**
+ * Append to the toString a summary of an
+ * int array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendSummary(StringBuffer buffer, String fieldName, int[] array) {
+ appendSummarySize(buffer, fieldName, array.length);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a short
+ * array.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param array the array to add to the toString
+ * @param fullDetail true for detail, false
+ * for summary info, null for style decides
+ */
+ public void append(StringBuffer buffer, String fieldName, short[] array, Boolean fullDetail) {
+ appendFieldStart(buffer, fieldName);
+
+ if (array == null) {
+ appendNullText(buffer, fieldName);
+
+ } else if (isFullDetail(fullDetail)) {
+ appendDetail(buffer, fieldName, array);
+
+ } else {
+ appendSummary(buffer, fieldName, array);
+ }
+
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString the detail of a
+ * short array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, short[] array) {
+ buffer.append(arrayStart);
+ for (int i = 0; i < array.length; i++) {
+ if (i > 0) {
+ buffer.append(arraySeparator);
+ }
+ appendDetail(buffer, fieldName, array[i]);
+ }
+ buffer.append(arrayEnd);
+ }
+
+ /**
+ * Append to the toString a summary of a
+ * short array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendSummary(StringBuffer buffer, String fieldName, short[] array) {
+ appendSummarySize(buffer, fieldName, array.length);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a byte
+ * array.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param array the array to add to the toString
+ * @param fullDetail true for detail, false
+ * for summary info, null for style decides
+ */
+ public void append(StringBuffer buffer, String fieldName, byte[] array, Boolean fullDetail) {
+ appendFieldStart(buffer, fieldName);
+
+ if (array == null) {
+ appendNullText(buffer, fieldName);
+
+ } else if (isFullDetail(fullDetail)) {
+ appendDetail(buffer, fieldName, array);
+
+ } else {
+ appendSummary(buffer, fieldName, array);
+ }
+
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString the detail of a
+ * byte array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, byte[] array) {
+ buffer.append(arrayStart);
+ for (int i = 0; i < array.length; i++) {
+ if (i > 0) {
+ buffer.append(arraySeparator);
+ }
+ appendDetail(buffer, fieldName, array[i]);
+ }
+ buffer.append(arrayEnd);
+ }
+
+ /**
+ * Append to the toString a summary of a
+ * byte array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendSummary(StringBuffer buffer, String fieldName, byte[] array) {
+ appendSummarySize(buffer, fieldName, array.length);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a char
+ * array.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param array the array to add to the toString
+ * @param fullDetail true for detail, false
+ * for summary info, null for style decides
+ */
+ public void append(StringBuffer buffer, String fieldName, char[] array, Boolean fullDetail) {
+ appendFieldStart(buffer, fieldName);
+
+ if (array == null) {
+ appendNullText(buffer, fieldName);
+
+ } else if (isFullDetail(fullDetail)) {
+ appendDetail(buffer, fieldName, array);
+
+ } else {
+ appendSummary(buffer, fieldName, array);
+ }
+
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString the detail of a
+ * char array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, char[] array) {
+ buffer.append(arrayStart);
+ for (int i = 0; i < array.length; i++) {
+ if (i > 0) {
+ buffer.append(arraySeparator);
+ }
+ appendDetail(buffer, fieldName, array[i]);
+ }
+ buffer.append(arrayEnd);
+ }
+
+ /**
+ * Append to the toString a summary of a
+ * char array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendSummary(StringBuffer buffer, String fieldName, char[] array) {
+ appendSummarySize(buffer, fieldName, array.length);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a double
+ * array.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param array the array to add to the toString
+ * @param fullDetail true for detail, false
+ * for summary info, null for style decides
+ */
+ public void append(StringBuffer buffer, String fieldName, double[] array, Boolean fullDetail) {
+ appendFieldStart(buffer, fieldName);
+
+ if (array == null) {
+ appendNullText(buffer, fieldName);
+
+ } else if (isFullDetail(fullDetail)) {
+ appendDetail(buffer, fieldName, array);
+
+ } else {
+ appendSummary(buffer, fieldName, array);
+ }
+
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString the detail of a
+ * double array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, double[] array) {
+ buffer.append(arrayStart);
+ for (int i = 0; i < array.length; i++) {
+ if (i > 0) {
+ buffer.append(arraySeparator);
+ }
+ appendDetail(buffer, fieldName, array[i]);
+ }
+ buffer.append(arrayEnd);
+ }
+
+ /**
+ * Append to the toString a summary of a
+ * double array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendSummary(StringBuffer buffer, String fieldName, double[] array) {
+ appendSummarySize(buffer, fieldName, array.length);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a float
+ * array.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param array the array to add to the toString
+ * @param fullDetail true for detail, false
+ * for summary info, null for style decides
+ */
+ public void append(StringBuffer buffer, String fieldName, float[] array, Boolean fullDetail) {
+ appendFieldStart(buffer, fieldName);
+
+ if (array == null) {
+ appendNullText(buffer, fieldName);
+
+ } else if (isFullDetail(fullDetail)) {
+ appendDetail(buffer, fieldName, array);
+
+ } else {
+ appendSummary(buffer, fieldName, array);
+ }
+
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString the detail of a
+ * float array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, float[] array) {
+ buffer.append(arrayStart);
+ for (int i = 0; i < array.length; i++) {
+ if (i > 0) {
+ buffer.append(arraySeparator);
+ }
+ appendDetail(buffer, fieldName, array[i]);
+ }
+ buffer.append(arrayEnd);
+ }
+
+ /**
+ * Append to the toString a summary of a
+ * float array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendSummary(StringBuffer buffer, String fieldName, float[] array) {
+ appendSummarySize(buffer, fieldName, array.length);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString a boolean
+ * array.
StringBuffer to populate
+ * @param fieldName the field name
+ * @param array the array to add to the toString
+ * @param fullDetail true for detail, false
+ * for summary info, null for style decides
+ */
+ public void append(StringBuffer buffer, String fieldName, boolean[] array, Boolean fullDetail) {
+ appendFieldStart(buffer, fieldName);
+
+ if (array == null) {
+ appendNullText(buffer, fieldName);
+
+ } else if (isFullDetail(fullDetail)) {
+ appendDetail(buffer, fieldName, array);
+
+ } else {
+ appendSummary(buffer, fieldName, array);
+ }
+
+ appendFieldEnd(buffer, fieldName);
+ }
+
+ /**
+ * Append to the toString the detail of a
+ * boolean array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendDetail(StringBuffer buffer, String fieldName, boolean[] array) {
+ buffer.append(arrayStart);
+ for (int i = 0; i < array.length; i++) {
+ if (i > 0) {
+ buffer.append(arraySeparator);
+ }
+ appendDetail(buffer, fieldName, array[i]);
+ }
+ buffer.append(arrayEnd);
+ }
+
+ /**
+ * Append to the toString a summary of a
+ * boolean array.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param array the array to add to the toString,
+ * not null
+ */
+ protected void appendSummary(StringBuffer buffer, String fieldName, boolean[] array) {
+ appendSummarySize(buffer, fieldName, array.length);
+ }
+
+ //----------------------------------------------------------------------------
+
+ /**
+ * Append to the toString the class name.
StringBuffer to populate
+ * @param object the Object whose name to output
+ */
+ protected void appendClassName(StringBuffer buffer, Object object) {
+ if (useClassName && object != null) {
+ register(object);
+ if (useShortClassName) {
+ buffer.append(getShortClassName(object.getClass()));
+ } else {
+ buffer.append(object.getClass().getName());
+ }
+ }
+ }
+
+ /**
+ * Append the {@link System#identityHashCode(java.lang.Object)}.
+ * + * @param buffer theStringBuffer to populate
+ * @param object the Object whose id to output
+ */
+ protected void appendIdentityHashCode(StringBuffer buffer, Object object) {
+ if (this.isUseIdentityHashCode() && object!=null) {
+ register(object);
+ buffer.append('@');
+ buffer.append(Integer.toHexString(System.identityHashCode(object)));
+ }
+ }
+
+ /**
+ * Append to the toString the content start.
StringBuffer to populate
+ */
+ protected void appendContentStart(StringBuffer buffer) {
+ buffer.append(contentStart);
+ }
+
+ /**
+ * Append to the toString the content end.
StringBuffer to populate
+ */
+ protected void appendContentEnd(StringBuffer buffer) {
+ buffer.append(contentEnd);
+ }
+
+ /**
+ * Append to the toString an indicator for null.
The default indicator is '<null>'.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ */
+ protected void appendNullText(StringBuffer buffer, String fieldName) {
+ buffer.append(nullText);
+ }
+
+ /**
+ * Append to the toString the field separator.
StringBuffer to populate
+ */
+ protected void appendFieldSeparator(StringBuffer buffer) {
+ buffer.append(fieldSeparator);
+ }
+
+ /**
+ * Append to the toString the field start.
StringBuffer to populate
+ * @param fieldName the field name
+ */
+ protected void appendFieldStart(StringBuffer buffer, String fieldName) {
+ if (useFieldNames && fieldName != null) {
+ buffer.append(fieldName);
+ buffer.append(fieldNameValueSeparator);
+ }
+ }
+
+ /**
+ * Append to the toString the field end.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ */
+ protected void appendFieldEnd(StringBuffer buffer, String fieldName) {
+ appendFieldSeparator(buffer);
+ }
+
+ /**
+ * Append to the toString a size summary.
The size summary is used to summarize the contents of
+ * Collections, Maps and arrays.
The output consists of a prefix, the passed in size + * and a suffix.
+ * + *The default format is '<size=n>'.
StringBuffer to populate
+ * @param fieldName the field name, typically not used as already appended
+ * @param size the size to append
+ */
+ protected void appendSummarySize(StringBuffer buffer, String fieldName, int size) {
+ buffer.append(sizeStartText);
+ buffer.append(size);
+ buffer.append(sizeEndText);
+ }
+
+ /**
+ * Is this field to be output in full detail.
+ * + *This method converts a detail request into a detail level.
+ * The calling code may request full detail (true),
+ * but a subclass might ignore that and always return
+ * false. The calling code may pass in
+ * null indicating that it doesn't care about
+ * the detail level. In this case the default detail level is
+ * used.
Gets the short class name for a class.
+ * + *The short class name is the classname excluding + * the package name.
+ * + * @param cls theClass to get the short name of
+ * @return the short name
+ */
+ protected String getShortClassName(Class> cls) {
+ return ClassUtils.getShortClassName(cls);
+ }
+
+ // Setters and getters for the customizable parts of the style
+ // These methods are not expected to be overridden, except to make public
+ // (They are not public so that immutable subclasses can be written)
+ //---------------------------------------------------------------------
+
+ /**
+ * Gets whether to use the class name.
+ * + * @return the current useClassName flag + */ + protected boolean isUseClassName() { + return useClassName; + } + + /** + *Sets whether to use the class name.
+ * + * @param useClassName the new useClassName flag + */ + protected void setUseClassName(boolean useClassName) { + this.useClassName = useClassName; + } + + //--------------------------------------------------------------------- + + /** + *Gets whether to output short or long class names.
+ * + * @return the current useShortClassName flag + * @since 2.0 + */ + protected boolean isUseShortClassName() { + return useShortClassName; + } + + /** + *Sets whether to output short or long class names.
+ * + * @param useShortClassName the new useShortClassName flag + * @since 2.0 + */ + protected void setUseShortClassName(boolean useShortClassName) { + this.useShortClassName = useShortClassName; + } + + //--------------------------------------------------------------------- + + /** + *Gets whether to use the identity hash code.
+ * + * @return the current useIdentityHashCode flag + */ + protected boolean isUseIdentityHashCode() { + return useIdentityHashCode; + } + + /** + *Sets whether to use the identity hash code.
+ * + * @param useIdentityHashCode the new useIdentityHashCode flag + */ + protected void setUseIdentityHashCode(boolean useIdentityHashCode) { + this.useIdentityHashCode = useIdentityHashCode; + } + + //--------------------------------------------------------------------- + + /** + *Gets whether to use the field names passed in.
+ * + * @return the current useFieldNames flag + */ + protected boolean isUseFieldNames() { + return useFieldNames; + } + + /** + *Sets whether to use the field names passed in.
+ * + * @param useFieldNames the new useFieldNames flag + */ + protected void setUseFieldNames(boolean useFieldNames) { + this.useFieldNames = useFieldNames; + } + + //--------------------------------------------------------------------- + + /** + *Gets whether to use full detail when the caller doesn't + * specify.
+ * + * @return the current defaultFullDetail flag + */ + protected boolean isDefaultFullDetail() { + return defaultFullDetail; + } + + /** + *Sets whether to use full detail when the caller doesn't + * specify.
+ * + * @param defaultFullDetail the new defaultFullDetail flag + */ + protected void setDefaultFullDetail(boolean defaultFullDetail) { + this.defaultFullDetail = defaultFullDetail; + } + + //--------------------------------------------------------------------- + + /** + *Gets whether to output array content detail.
+ * + * @return the current array content detail setting + */ + protected boolean isArrayContentDetail() { + return arrayContentDetail; + } + + /** + *Sets whether to output array content detail.
+ * + * @param arrayContentDetail the new arrayContentDetail flag + */ + protected void setArrayContentDetail(boolean arrayContentDetail) { + this.arrayContentDetail = arrayContentDetail; + } + + //--------------------------------------------------------------------- + + /** + *Gets the array start text.
+ * + * @return the current array start text + */ + protected String getArrayStart() { + return arrayStart; + } + + /** + *Sets the array start text.
+ * + *null is accepted, but will be converted to
+ * an empty String.
Gets the array end text.
+ * + * @return the current array end text + */ + protected String getArrayEnd() { + return arrayEnd; + } + + /** + *Sets the array end text.
+ * + *null is accepted, but will be converted to
+ * an empty String.
Gets the array separator text.
+ * + * @return the current array separator text + */ + protected String getArraySeparator() { + return arraySeparator; + } + + /** + *Sets the array separator text.
+ * + *null is accepted, but will be converted to
+ * an empty String.
Gets the content start text.
+ * + * @return the current content start text + */ + protected String getContentStart() { + return contentStart; + } + + /** + *Sets the content start text.
+ * + *null is accepted, but will be converted to
+ * an empty String.
Gets the content end text.
+ * + * @return the current content end text + */ + protected String getContentEnd() { + return contentEnd; + } + + /** + *Sets the content end text.
+ * + *null is accepted, but will be converted to
+ * an empty String.
Gets the field name value separator text.
+ * + * @return the current field name value separator text + */ + protected String getFieldNameValueSeparator() { + return fieldNameValueSeparator; + } + + /** + *Sets the field name value separator text.
+ * + *null is accepted, but will be converted to
+ * an empty String.
Gets the field separator text.
+ * + * @return the current field separator text + */ + protected String getFieldSeparator() { + return fieldSeparator; + } + + /** + *Sets the field separator text.
+ * + *null is accepted, but will be converted to
+ * an empty String.
Gets whether the field separator should be added at the start + * of each buffer.
+ * + * @return the fieldSeparatorAtStart flag + * @since 2.0 + */ + protected boolean isFieldSeparatorAtStart() { + return fieldSeparatorAtStart; + } + + /** + *Sets whether the field separator should be added at the start + * of each buffer.
+ * + * @param fieldSeparatorAtStart the fieldSeparatorAtStart flag + * @since 2.0 + */ + protected void setFieldSeparatorAtStart(boolean fieldSeparatorAtStart) { + this.fieldSeparatorAtStart = fieldSeparatorAtStart; + } + + //--------------------------------------------------------------------- + + /** + *Gets whether the field separator should be added at the end + * of each buffer.
+ * + * @return fieldSeparatorAtEnd flag + * @since 2.0 + */ + protected boolean isFieldSeparatorAtEnd() { + return fieldSeparatorAtEnd; + } + + /** + *Sets whether the field separator should be added at the end + * of each buffer.
+ * + * @param fieldSeparatorAtEnd the fieldSeparatorAtEnd flag + * @since 2.0 + */ + protected void setFieldSeparatorAtEnd(boolean fieldSeparatorAtEnd) { + this.fieldSeparatorAtEnd = fieldSeparatorAtEnd; + } + + //--------------------------------------------------------------------- + + /** + *Gets the text to output when null found.
Sets the text to output when null found.
null is accepted, but will be converted to
+ * an empty String.
Gets the start text to output when a Collection,
+ * Map or array size is output.
This is output before the size value.
+ * + * @return the current start of size text + */ + protected String getSizeStartText() { + return sizeStartText; + } + + /** + *Sets the start text to output when a Collection,
+ * Map or array size is output.
This is output before the size value.
+ * + *null is accepted, but will be converted to
+ * an empty String.
Gets the end text to output when a Collection,
+ * Map or array size is output.
This is output after the size value.
+ * + * @return the current end of size text + */ + protected String getSizeEndText() { + return sizeEndText; + } + + /** + *Sets the end text to output when a Collection,
+ * Map or array size is output.
This is output after the size value.
+ * + *null is accepted, but will be converted to
+ * an empty String.
Gets the start text to output when an Object is
+ * output in summary mode.
This is output before the size value.
+ * + * @return the current start of summary text + */ + protected String getSummaryObjectStartText() { + return summaryObjectStartText; + } + + /** + *Sets the start text to output when an Object is
+ * output in summary mode.
This is output before the size value.
+ * + *null is accepted, but will be converted to
+ * an empty String.
Gets the end text to output when an Object is
+ * output in summary mode.
This is output after the size value.
+ * + * @return the current end of summary text + */ + protected String getSummaryObjectEndText() { + return summaryObjectEndText; + } + + /** + *Sets the end text to output when an Object is
+ * output in summary mode.
This is output after the size value.
+ * + *null is accepted, but will be converted to
+ * an empty String.
Default ToStringStyle.
This is an inner class rather than using
+ * StandardToStringStyle to ensure its immutability.
Constructor.
+ * + *Use the static constant rather than instantiating.
+ */ + DefaultToStringStyle() { + super(); + } + + /** + *Ensure Singleton after serialization.
ToStringStyle that does not print out
+ * the field names.
This is an inner class rather than using
+ * StandardToStringStyle to ensure its immutability.
+ */
+ private static final class NoFieldNameToStringStyle extends ToStringStyle {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
Constructor.
+ * + *Use the static constant rather than instantiating.
+ */ + NoFieldNameToStringStyle() { + super(); + this.setUseFieldNames(false); + } + + /** + *Ensure Singleton after serialization.
ToStringStyle that prints out the short
+ * class name and no identity hashcode.
This is an inner class rather than using
+ * StandardToStringStyle to ensure its immutability.
Constructor.
+ * + *Use the static constant rather than instantiating.
+ */ + ShortPrefixToStringStyle() { + super(); + this.setUseShortClassName(true); + this.setUseIdentityHashCode(false); + } + + /** + *Ensure Singleton after serialization.
ToStringStyle that does not print out the
+ * classname, identity hashcode, content start or field name.
This is an inner class rather than using
+ * StandardToStringStyle to ensure its immutability.
Constructor.
+ * + *Use the static constant rather than instantiating.
+ */ + SimpleToStringStyle() { + super(); + this.setUseClassName(false); + this.setUseIdentityHashCode(false); + this.setUseFieldNames(false); + this.setContentStart(""); + this.setContentEnd(""); + } + + /** + *Ensure Singleton after serialization.
ToStringStyle that outputs on multiple lines.
This is an inner class rather than using
+ * StandardToStringStyle to ensure its immutability.
Constructor.
+ * + *Use the static constant rather than instantiating.
+ */ + MultiLineToStringStyle() { + super(); + this.setContentStart("["); + this.setFieldSeparator(SystemUtils.LINE_SEPARATOR + " "); + this.setFieldSeparatorAtStart(true); + this.setContentEnd(SystemUtils.LINE_SEPARATOR + "]"); + } + + /** + *Ensure Singleton after serialization.
- * An exception that provides an easy and safe way to add contextual information. - *
- * An exception trace itself is often insufficient to provide rapid diagnosis of the issue. - * Frequently what is needed is a select few pieces of local contextual data. - * Providing this data is tricky however, due to concerns over formatting and nulls. - *
- * The contexted exception approach allows the exception to be created together with a - * list of context label-value pairs. This additional information is automatically included in - * the message and printed stack trace. - *
- * An unchecked version of this exception is provided by ContextedRuntimeException. - *
- *- * To use this class write code as follows: - *
- *
- * try {
- * ...
- * } catch (Exception e) {
- * throw new ContextedException("Error posting account transaction", e)
- * .addContextValue("Account Number", accountNumber)
- * .addContextValue("Amount Posted", amountPosted)
- * .addContextValue("Previous Balance", previousBalance)
- * }
- * }
- * or improve diagnose data at a higher level:
- *
- * try {
- * ...
- * } catch (ContextedException e) {
- * throw e.setContextValue("Transaction Id", transactionId);
- * } catch (Exception e) {
- * if (e instanceof ExceptionContext) {
- * e.setContextValue("Transaction Id", transactionId);
- * }
- * throw e;
- * }
- * }
- *
- * - * The output in a printStacktrace() (which often is written to a log) would look something like the following: - *
- * org.apache.commons.lang3.exception.ContextedException: java.lang.Exception: Error posting account transaction - * Exception Context: - * [1:Account Number=null] - * [2:Amount Posted=100.00] - * [3:Previous Balance=-2.17] - * [4:Transaction Id=94ef1d15-d443-46c4-822b-637f26244899] - * - * --------------------------------- - * at org.apache.commons.lang3.exception.ContextedExceptionTest.testAddValue(ContextedExceptionTest.java:88) - * ..... (rest of trace) - *- * - * - * @see ContextedRuntimeException - * @since 3.0 - */ -public class ContextedException extends Exception implements ExceptionContext { - - /** The serialization version. */ - private static final long serialVersionUID = 20110706L; - /** The context where the data is stored. */ - private final ExceptionContext exceptionContext; - - /** - * Instantiates ContextedException without message or cause. - *
- * The context information is stored using a default implementation. - */ - public ContextedException() { - super(); - exceptionContext = new DefaultExceptionContext(); - } - - /** - * Instantiates ContextedException with message, but without cause. - *
- * The context information is stored using a default implementation. - * - * @param message the exception message, may be null - */ - public ContextedException(String message) { - super(message); - exceptionContext = new DefaultExceptionContext(); - } - - /** - * Instantiates ContextedException with cause, but without message. - *
- * The context information is stored using a default implementation. - * - * @param cause the underlying cause of the exception, may be null - */ - public ContextedException(Throwable cause) { - super(cause); - exceptionContext = new DefaultExceptionContext(); - } - - /** - * Instantiates ContextedException with cause and message. - *
- * The context information is stored using a default implementation. - * - * @param message the exception message, may be null - * @param cause the underlying cause of the exception, may be null - */ - public ContextedException(String message, Throwable cause) { - super(message, cause); - exceptionContext = new DefaultExceptionContext(); - } - - /** - * Instantiates ContextedException with cause, message, and ExceptionContext. - * - * @param message the exception message, may be null - * @param cause the underlying cause of the exception, may be null - * @param context the context used to store the additional information, null uses default implementation - */ - public ContextedException(String message, Throwable cause, ExceptionContext context) { - super(message, cause); - if (context == null) { - context = new DefaultExceptionContext(); - } - exceptionContext = context; - } - - //----------------------------------------------------------------------- - /** - * Adds information helpful to a developer in diagnosing and correcting the problem. - * For the information to be meaningful, the value passed should have a reasonable - * toString() implementation. - * Different values can be added with the same label multiple times. - *
- * Note: This exception is only serializable if the object added is serializable. - *
- * - * @param label a textual label associated with information, {@code null} not recommended - * @param value information needed to understand exception, may be {@code null} - * @return {@code this}, for method chaining, not {@code null} - */ - public ContextedException addContextValue(String label, Object value) { - exceptionContext.addContextValue(label, value); - return this; - } - - /** - * Sets information helpful to a developer in diagnosing and correcting the problem. - * For the information to be meaningful, the value passed should have a reasonable - * toString() implementation. - * Any existing values with the same labels are removed before the new one is added. - *- * Note: This exception is only serializable if the object added as value is serializable. - *
- * - * @param label a textual label associated with information, {@code null} not recommended - * @param value information needed to understand exception, may be {@code null} - * @return {@code this}, for method chaining, not {@code null} - */ - public ContextedException setContextValue(String label, Object value) { - exceptionContext.setContextValue(label, value); - return this; - } - - /** - * {@inheritDoc} - */ - public List+ * An exception that provides an easy and safe way to add contextual information. + *
+ * An exception trace itself is often insufficient to provide rapid diagnosis of the issue. + * Frequently what is needed is a select few pieces of local contextual data. + * Providing this data is tricky however, due to concerns over formatting and nulls. + *
+ * The contexted exception approach allows the exception to be created together with a + * list of context label-value pairs. This additional information is automatically included in + * the message and printed stack trace. + *
+ * An unchecked version of this exception is provided by ContextedRuntimeException. + *
+ *+ * To use this class write code as follows: + *
+ *
+ * try {
+ * ...
+ * } catch (Exception e) {
+ * throw new ContextedException("Error posting account transaction", e)
+ * .addContextValue("Account Number", accountNumber)
+ * .addContextValue("Amount Posted", amountPosted)
+ * .addContextValue("Previous Balance", previousBalance)
+ * }
+ * }
+ * or improve diagnose data at a higher level:
+ *
+ * try {
+ * ...
+ * } catch (ContextedException e) {
+ * throw e.setContextValue("Transaction Id", transactionId);
+ * } catch (Exception e) {
+ * if (e instanceof ExceptionContext) {
+ * e.setContextValue("Transaction Id", transactionId);
+ * }
+ * throw e;
+ * }
+ * }
+ *
+ * + * The output in a printStacktrace() (which often is written to a log) would look something like the following: + *
+ * org.apache.commons.lang3.exception.ContextedException: java.lang.Exception: Error posting account transaction + * Exception Context: + * [1:Account Number=null] + * [2:Amount Posted=100.00] + * [3:Previous Balance=-2.17] + * [4:Transaction Id=94ef1d15-d443-46c4-822b-637f26244899] + * + * --------------------------------- + * at org.apache.commons.lang3.exception.ContextedExceptionTest.testAddValue(ContextedExceptionTest.java:88) + * ..... (rest of trace) + *+ * + * + * @see ContextedRuntimeException + * @since 3.0 + */ +public class ContextedException extends Exception implements ExceptionContext { + + /** The serialization version. */ + private static final long serialVersionUID = 20110706L; + /** The context where the data is stored. */ + private final ExceptionContext exceptionContext; + + /** + * Instantiates ContextedException without message or cause. + *
+ * The context information is stored using a default implementation. + */ + public ContextedException() { + super(); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedException with message, but without cause. + *
+ * The context information is stored using a default implementation. + * + * @param message the exception message, may be null + */ + public ContextedException(String message) { + super(message); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedException with cause, but without message. + *
+ * The context information is stored using a default implementation. + * + * @param cause the underlying cause of the exception, may be null + */ + public ContextedException(Throwable cause) { + super(cause); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedException with cause and message. + *
+ * The context information is stored using a default implementation. + * + * @param message the exception message, may be null + * @param cause the underlying cause of the exception, may be null + */ + public ContextedException(String message, Throwable cause) { + super(message, cause); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedException with cause, message, and ExceptionContext. + * + * @param message the exception message, may be null + * @param cause the underlying cause of the exception, may be null + * @param context the context used to store the additional information, null uses default implementation + */ + public ContextedException(String message, Throwable cause, ExceptionContext context) { + super(message, cause); + if (context == null) { + context = new DefaultExceptionContext(); + } + exceptionContext = context; + } + + //----------------------------------------------------------------------- + /** + * Adds information helpful to a developer in diagnosing and correcting the problem. + * For the information to be meaningful, the value passed should have a reasonable + * toString() implementation. + * Different values can be added with the same label multiple times. + *
+ * Note: This exception is only serializable if the object added is serializable. + *
+ * + * @param label a textual label associated with information, {@code null} not recommended + * @param value information needed to understand exception, may be {@code null} + * @return {@code this}, for method chaining, not {@code null} + */ + public ContextedException addContextValue(String label, Object value) { + exceptionContext.addContextValue(label, value); + return this; + } + + /** + * Sets information helpful to a developer in diagnosing and correcting the problem. + * For the information to be meaningful, the value passed should have a reasonable + * toString() implementation. + * Any existing values with the same labels are removed before the new one is added. + *+ * Note: This exception is only serializable if the object added as value is serializable. + *
+ * + * @param label a textual label associated with information, {@code null} not recommended + * @param value information needed to understand exception, may be {@code null} + * @return {@code this}, for method chaining, not {@code null} + */ + public ContextedException setContextValue(String label, Object value) { + exceptionContext.setContextValue(label, value); + return this; + } + + /** + * {@inheritDoc} + */ + public List- * A runtime exception that provides an easy and safe way to add contextual information. - *
- * An exception trace itself is often insufficient to provide rapid diagnosis of the issue. - * Frequently what is needed is a select few pieces of local contextual data. - * Providing this data is tricky however, due to concerns over formatting and nulls. - *
- * The contexted exception approach allows the exception to be created together with a - * list of context label-value pairs. This additional information is automatically included in - * the message and printed stack trace. - *
- * A checked version of this exception is provided by ContextedException. - *
- *- * To use this class write code as follows: - *
- *
- * try {
- * ...
- * } catch (Exception e) {
- * throw new ContextedRuntimeException("Error posting account transaction", e)
- * .addContextValue("Account Number", accountNumber)
- * .addContextValue("Amount Posted", amountPosted)
- * .addContextValue("Previous Balance", previousBalance)
- * }
- * }
- * or improve diagnose data at a higher level:
- *
- * try {
- * ...
- * } catch (ContextedRuntimeException e) {
- * throw e.setContextValue("Transaction Id", transactionId);
- * } catch (Exception e) {
- * if (e instanceof ExceptionContext) {
- * e.setContextValue("Transaction Id", transactionId);
- * }
- * throw e;
- * }
- * }
- *
- * - * The output in a printStacktrace() (which often is written to a log) would look something like the following: - *
- * org.apache.commons.lang3.exception.ContextedRuntimeException: java.lang.Exception: Error posting account transaction - * Exception Context: - * [1:Account Number=null] - * [2:Amount Posted=100.00] - * [3:Previous Balance=-2.17] - * [4:Transaction Id=94ef1d15-d443-46c4-822b-637f26244899] - * - * --------------------------------- - * at org.apache.commons.lang3.exception.ContextedRuntimeExceptionTest.testAddValue(ContextedExceptionTest.java:88) - * ..... (rest of trace) - *- * - * - * @see ContextedException - * @since 3.0 - */ -public class ContextedRuntimeException extends RuntimeException implements ExceptionContext { - - /** The serialization version. */ - private static final long serialVersionUID = 20110706L; - /** The context where the data is stored. */ - private final ExceptionContext exceptionContext; - - /** - * Instantiates ContextedRuntimeException without message or cause. - *
- * The context information is stored using a default implementation. - */ - public ContextedRuntimeException() { - super(); - exceptionContext = new DefaultExceptionContext(); - } - - /** - * Instantiates ContextedRuntimeException with message, but without cause. - *
- * The context information is stored using a default implementation. - * - * @param message the exception message, may be null - */ - public ContextedRuntimeException(String message) { - super(message); - exceptionContext = new DefaultExceptionContext(); - } - - /** - * Instantiates ContextedRuntimeException with cause, but without message. - *
- * The context information is stored using a default implementation. - * - * @param cause the underlying cause of the exception, may be null - */ - public ContextedRuntimeException(Throwable cause) { - super(cause); - exceptionContext = new DefaultExceptionContext(); - } - - /** - * Instantiates ContextedRuntimeException with cause and message. - *
- * The context information is stored using a default implementation. - * - * @param message the exception message, may be null - * @param cause the underlying cause of the exception, may be null - */ - public ContextedRuntimeException(String message, Throwable cause) { - super(message, cause); - exceptionContext = new DefaultExceptionContext(); - } - - /** - * Instantiates ContextedRuntimeException with cause, message, and ExceptionContext. - * - * @param message the exception message, may be null - * @param cause the underlying cause of the exception, may be null - * @param context the context used to store the additional information, null uses default implementation - */ - public ContextedRuntimeException(String message, Throwable cause, ExceptionContext context) { - super(message, cause); - if (context == null) { - context = new DefaultExceptionContext(); - } - exceptionContext = context; - } - - //----------------------------------------------------------------------- - /** - * Adds information helpful to a developer in diagnosing and correcting the problem. - * For the information to be meaningful, the value passed should have a reasonable - * toString() implementation. - * Different values can be added with the same label multiple times. - *
- * Note: This exception is only serializable if the object added is serializable. - *
- * - * @param label a textual label associated with information, {@code null} not recommended - * @param value information needed to understand exception, may be {@code null} - * @return {@code this}, for method chaining, not {@code null} - */ - public ContextedRuntimeException addContextValue(String label, Object value) { - exceptionContext.addContextValue(label, value); - return this; - } - - /** - * Sets information helpful to a developer in diagnosing and correcting the problem. - * For the information to be meaningful, the value passed should have a reasonable - * toString() implementation. - * Any existing values with the same labels are removed before the new one is added. - *- * Note: This exception is only serializable if the object added as value is serializable. - *
- * - * @param label a textual label associated with information, {@code null} not recommended - * @param value information needed to understand exception, may be {@code null} - * @return {@code this}, for method chaining, not {@code null} - */ - public ContextedRuntimeException setContextValue(String label, Object value) { - exceptionContext.setContextValue(label, value); - return this; - } - - /** - * {@inheritDoc} - */ - public List+ * A runtime exception that provides an easy and safe way to add contextual information. + *
+ * An exception trace itself is often insufficient to provide rapid diagnosis of the issue. + * Frequently what is needed is a select few pieces of local contextual data. + * Providing this data is tricky however, due to concerns over formatting and nulls. + *
+ * The contexted exception approach allows the exception to be created together with a + * list of context label-value pairs. This additional information is automatically included in + * the message and printed stack trace. + *
+ * A checked version of this exception is provided by ContextedException. + *
+ *+ * To use this class write code as follows: + *
+ *
+ * try {
+ * ...
+ * } catch (Exception e) {
+ * throw new ContextedRuntimeException("Error posting account transaction", e)
+ * .addContextValue("Account Number", accountNumber)
+ * .addContextValue("Amount Posted", amountPosted)
+ * .addContextValue("Previous Balance", previousBalance)
+ * }
+ * }
+ * or improve diagnose data at a higher level:
+ *
+ * try {
+ * ...
+ * } catch (ContextedRuntimeException e) {
+ * throw e.setContextValue("Transaction Id", transactionId);
+ * } catch (Exception e) {
+ * if (e instanceof ExceptionContext) {
+ * e.setContextValue("Transaction Id", transactionId);
+ * }
+ * throw e;
+ * }
+ * }
+ *
+ * + * The output in a printStacktrace() (which often is written to a log) would look something like the following: + *
+ * org.apache.commons.lang3.exception.ContextedRuntimeException: java.lang.Exception: Error posting account transaction + * Exception Context: + * [1:Account Number=null] + * [2:Amount Posted=100.00] + * [3:Previous Balance=-2.17] + * [4:Transaction Id=94ef1d15-d443-46c4-822b-637f26244899] + * + * --------------------------------- + * at org.apache.commons.lang3.exception.ContextedRuntimeExceptionTest.testAddValue(ContextedExceptionTest.java:88) + * ..... (rest of trace) + *+ * + * + * @see ContextedException + * @since 3.0 + */ +public class ContextedRuntimeException extends RuntimeException implements ExceptionContext { + + /** The serialization version. */ + private static final long serialVersionUID = 20110706L; + /** The context where the data is stored. */ + private final ExceptionContext exceptionContext; + + /** + * Instantiates ContextedRuntimeException without message or cause. + *
+ * The context information is stored using a default implementation. + */ + public ContextedRuntimeException() { + super(); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedRuntimeException with message, but without cause. + *
+ * The context information is stored using a default implementation. + * + * @param message the exception message, may be null + */ + public ContextedRuntimeException(String message) { + super(message); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedRuntimeException with cause, but without message. + *
+ * The context information is stored using a default implementation. + * + * @param cause the underlying cause of the exception, may be null + */ + public ContextedRuntimeException(Throwable cause) { + super(cause); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedRuntimeException with cause and message. + *
+ * The context information is stored using a default implementation. + * + * @param message the exception message, may be null + * @param cause the underlying cause of the exception, may be null + */ + public ContextedRuntimeException(String message, Throwable cause) { + super(message, cause); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedRuntimeException with cause, message, and ExceptionContext. + * + * @param message the exception message, may be null + * @param cause the underlying cause of the exception, may be null + * @param context the context used to store the additional information, null uses default implementation + */ + public ContextedRuntimeException(String message, Throwable cause, ExceptionContext context) { + super(message, cause); + if (context == null) { + context = new DefaultExceptionContext(); + } + exceptionContext = context; + } + + //----------------------------------------------------------------------- + /** + * Adds information helpful to a developer in diagnosing and correcting the problem. + * For the information to be meaningful, the value passed should have a reasonable + * toString() implementation. + * Different values can be added with the same label multiple times. + *
+ * Note: This exception is only serializable if the object added is serializable. + *
+ * + * @param label a textual label associated with information, {@code null} not recommended + * @param value information needed to understand exception, may be {@code null} + * @return {@code this}, for method chaining, not {@code null} + */ + public ContextedRuntimeException addContextValue(String label, Object value) { + exceptionContext.addContextValue(label, value); + return this; + } + + /** + * Sets information helpful to a developer in diagnosing and correcting the problem. + * For the information to be meaningful, the value passed should have a reasonable + * toString() implementation. + * Any existing values with the same labels are removed before the new one is added. + *+ * Note: This exception is only serializable if the object added as value is serializable. + *
+ * + * @param label a textual label associated with information, {@code null} not recommended + * @param value information needed to understand exception, may be {@code null} + * @return {@code this}, for method chaining, not {@code null} + */ + public ContextedRuntimeException setContextValue(String label, Object value) { + exceptionContext.setContextValue(label, value); + return this; + } + + /** + * {@inheritDoc} + */ + public List- * This implementation is serializable, however this is dependent on the values that - * are added also being serializable. - *
- * - * @see ContextedException - * @see ContextedRuntimeException - * @since 3.0 - */ -public class DefaultExceptionContext implements ExceptionContext, Serializable { - - /** The serialization version. */ - private static final long serialVersionUID = 20110706L; - - /** The list storing the label-data pairs. */ - private final List+ * This implementation is serializable, however this is dependent on the values that + * are added also being serializable. + *
+ * + * @see ContextedException + * @see ContextedRuntimeException + * @since 3.0 + */ +public class DefaultExceptionContext implements ExceptionContext, Serializable { + + /** The serialization version. */ + private static final long serialVersionUID = 20110706L; + + /** The list storing the label-data pairs. */ + private final List- * Implementations are expected to manage the pairs in a list-style collection - * that keeps the pairs in the sequence of their addition. - *
- * - * @see ContextedException - * @see ContextedRuntimeException - * @since 3.0 - */ -public interface ExceptionContext { - - /** - * Adds a contextual label-value pair into this context. - *- * The pair will be added to the context, independently of an already - * existing pair with the same label. - *
- * - * @param label the label of the item to add, {@code null} not recommended - * @param value the value of item to add, may be {@code null} - * @return {@code this}, for method chaining, not {@code null} - */ - public ExceptionContext addContextValue(String label, Object value); - - /** - * Sets a contextual label-value pair into this context. - *- * The pair will be added normally, but any existing label-value pair with - * the same label is removed from the context. - *
- * - * @param label the label of the item to add, {@code null} not recommended - * @param value the value of item to add, may be {@code null} - * @return {@code this}, for method chaining, not {@code null} - */ - public ExceptionContext setContextValue(String label, Object value); - - /** - * Retrieves all the contextual data values associated with the label. - * - * @param label the label to get the contextual values for, may be {@code null} - * @return the contextual values associated with the label, never {@code null} - */ - public List+ * Implementations are expected to manage the pairs in a list-style collection + * that keeps the pairs in the sequence of their addition. + *
+ * + * @see ContextedException + * @see ContextedRuntimeException + * @since 3.0 + */ +public interface ExceptionContext { + + /** + * Adds a contextual label-value pair into this context. + *+ * The pair will be added to the context, independently of an already + * existing pair with the same label. + *
+ * + * @param label the label of the item to add, {@code null} not recommended + * @param value the value of item to add, may be {@code null} + * @return {@code this}, for method chaining, not {@code null} + */ + public ExceptionContext addContextValue(String label, Object value); + + /** + * Sets a contextual label-value pair into this context. + *+ * The pair will be added normally, but any existing label-value pair with + * the same label is removed from the context. + *
+ * + * @param label the label of the item to add, {@code null} not recommended + * @param value the value of item to add, may be {@code null} + * @return {@code this}, for method chaining, not {@code null} + */ + public ExceptionContext setContextValue(String label, Object value); + + /** + * Retrieves all the contextual data values associated with the label. + * + * @param label the label to get the contextual values for, may be {@code null} + * @return the contextual values associated with the label, never {@code null} + */ + public ListProvides utilities for manipulating and examining
- * Throwable objects.
Used when printing stack frames to denote the start of a - * wrapped exception.
- * - *Package private for accessibility by test suite.
- */ - static final String WRAPPED_MARKER = " [wrapped] "; - - /** - *The names of methods commonly used to access a wrapped exception.
- */ - // TODO: Remove in Lang 4.0 - private static final String[] CAUSE_METHOD_NAMES = { - "getCause", - "getNextException", - "getTargetException", - "getException", - "getSourceException", - "getRootCause", - "getCausedByException", - "getNested", - "getLinkedException", - "getNestedException", - "getLinkedCause", - "getThrowable", - }; - - /** - *
- * Public constructor allows an instance of ExceptionUtils to be created, although that is not
- * normally necessary.
- *
Returns the default names used when searching for the cause of an exception.
- * - *This may be modified and used in the overloaded getCause(Throwable, String[]) method.
- * - * @return cloned array of the default method names - * @since 3.0 - * @deprecated This feature will be removed in Lang 4.0 - */ - @Deprecated - public static String[] getDefaultCauseMethodNames() { - return ArrayUtils.clone(CAUSE_METHOD_NAMES); - } - - //----------------------------------------------------------------------- - /** - *Introspects the Throwable to obtain the cause.
The method searches for methods with specific names that return a
- * Throwable object. This will pick up most wrapping exceptions,
- * including those from JDK 1.4.
- *
- *
The default list searched for are:
- *getCause()getNextException()getTargetException()getException()getSourceException()getRootCause()getCausedByException()getNested()If none of the above is found, returns null.
Throwable,
- * null if none found or null throwable input
- * @since 1.0
- * @deprecated This feature will be removed in Lang 4.0
- */
- @Deprecated
- public static Throwable getCause(Throwable throwable) {
- return getCause(throwable, CAUSE_METHOD_NAMES);
- }
-
- /**
- * Introspects the Throwable to obtain the cause.
A null set of method names means use the default set.
- * A null in the set of method names will be ignored.
Throwable,
- * null if none found or null throwable input
- * @since 1.0
- * @deprecated This feature will be removed in Lang 4.0
- */
- @Deprecated
- public static Throwable getCause(Throwable throwable, String[] methodNames) {
- if (throwable == null) {
- return null;
- }
-
- if (methodNames == null) {
- methodNames = CAUSE_METHOD_NAMES;
- }
-
- for (String methodName : methodNames) {
- if (methodName != null) {
- Throwable cause = getCauseUsingMethodName(throwable, methodName);
- if (cause != null) {
- return cause;
- }
- }
- }
-
- return null;
- }
-
- /**
- * Introspects the Throwable to obtain the root cause.
This method walks through the exception chain to the last element, - * "root" of the tree, using {@link #getCause(Throwable)}, and - * returns that exception.
- * - *From version 2.2, this method handles recursive cause structures - * that might otherwise cause infinite loops. If the throwable parameter - * has a cause of itself, then null will be returned. If the throwable - * parameter cause chain loops, the last element in the chain before the - * loop is returned.
- * - * @param throwable the throwable to get the root cause for, may be null - * @return the root cause of theThrowable,
- * null if none found or null throwable input
- */
- public static Throwable getRootCause(Throwable throwable) {
- ListFinds a Throwable by method name.
null if not found
- */
- // TODO: Remove in Lang 4.0
- private static Throwable getCauseUsingMethodName(Throwable throwable, String methodName) {
- Method method = null;
- try {
- method = throwable.getClass().getMethod(methodName);
- } catch (NoSuchMethodException ignored) { // NOPMD
- // exception ignored
- } catch (SecurityException ignored) { // NOPMD
- // exception ignored
- }
-
- if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) {
- try {
- return (Throwable) method.invoke(throwable);
- } catch (IllegalAccessException ignored) { // NOPMD
- // exception ignored
- } catch (IllegalArgumentException ignored) { // NOPMD
- // exception ignored
- } catch (InvocationTargetException ignored) { // NOPMD
- // exception ignored
- }
- }
- return null;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Counts the number of Throwable objects in the
- * exception chain.
A throwable without cause will return 1.
- * A throwable with one cause will return 2 and so on.
- * A null throwable will return 0.
From version 2.2, this method handles recursive cause structures - * that might otherwise cause infinite loops. The cause chain is - * processed until the end is reached, or until the next item in the - * chain is already in the result set.
- * - * @param throwable the throwable to inspect, may be null - * @return the count of throwables, zero if null input - */ - public static int getThrowableCount(Throwable throwable) { - return getThrowableList(throwable).size(); - } - - /** - *Returns the list of Throwable objects in the
- * exception chain.
A throwable without cause will return an array containing
- * one element - the input throwable.
- * A throwable with one cause will return an array containing
- * two elements. - the input throwable and the cause throwable.
- * A null throwable will return an array of size zero.
From version 2.2, this method handles recursive cause structures - * that might otherwise cause infinite loops. The cause chain is - * processed until the end is reached, or until the next item in the - * chain is already in the result set.
- * - * @see #getThrowableList(Throwable) - * @param throwable the throwable to inspect, may be null - * @return the array of throwables, never null - */ - public static Throwable[] getThrowables(Throwable throwable) { - ListReturns the list of Throwable objects in the
- * exception chain.
A throwable without cause will return a list containing
- * one element - the input throwable.
- * A throwable with one cause will return a list containing
- * two elements. - the input throwable and the cause throwable.
- * A null throwable will return a list of size zero.
This method handles recursive cause structures that might - * otherwise cause infinite loops. The cause chain is processed until - * the end is reached, or until the next item in the chain is already - * in the result set.
- * - * @param throwable the throwable to inspect, may be null - * @return the list of throwables, never null - * @since Commons Lang 2.2 - */ - public static ListReturns the (zero based) index of the first Throwable
- * that matches the specified class (exactly) in the exception chain.
- * Subclasses of the specified class do not match - see
- * {@link #indexOfType(Throwable, Class)} for the opposite.
A null throwable returns -1.
- * A null type returns -1.
- * No match in the chain returns -1.
Returns the (zero based) index of the first Throwable
- * that matches the specified type in the exception chain from
- * a specified index.
- * Subclasses of the specified class do not match - see
- * {@link #indexOfType(Throwable, Class, int)} for the opposite.
A null throwable returns -1.
- * A null type returns -1.
- * No match in the chain returns -1.
- * A negative start index is treated as zero.
- * A start index greater than the number of throwables returns -1.
Returns the (zero based) index of the first Throwable
- * that matches the specified class or subclass in the exception chain.
- * Subclasses of the specified class do match - see
- * {@link #indexOfThrowable(Throwable, Class)} for the opposite.
A null throwable returns -1.
- * A null type returns -1.
- * No match in the chain returns -1.
Returns the (zero based) index of the first Throwable
- * that matches the specified type in the exception chain from
- * a specified index.
- * Subclasses of the specified class do match - see
- * {@link #indexOfThrowable(Throwable, Class)} for the opposite.
A null throwable returns -1.
- * A null type returns -1.
- * No match in the chain returns -1.
- * A negative start index is treated as zero.
- * A start index greater than the number of throwables returns -1.
Worker method for the indexOfType methods.
true, compares with {@link Class#isAssignableFrom(Class)}, otherwise compares
- * using references
- * @return index of the type within throwables nested withing the specified throwable
- */
- private static int indexOf(Throwable throwable, Class> type, int fromIndex, boolean subclass) {
- if (throwable == null || type == null) {
- return -1;
- }
- if (fromIndex < 0) {
- fromIndex = 0;
- }
- Throwable[] throwables = ExceptionUtils.getThrowables(throwable);
- if (fromIndex >= throwables.length) {
- return -1;
- }
- if (subclass) {
- for (int i = fromIndex; i < throwables.length; i++) {
- if (type.isAssignableFrom(throwables[i].getClass())) {
- return i;
- }
- }
- } else {
- for (int i = fromIndex; i < throwables.length; i++) {
- if (type.equals(throwables[i].getClass())) {
- return i;
- }
- }
- }
- return -1;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Prints a compact stack trace for the root cause of a throwable
- * to System.err.
The compact stack trace starts with the root cause and prints - * stack frames up to the place where it was caught and wrapped. - * Then it prints the wrapped exception and continues with stack frames - * until the wrapper exception is caught and wrapped again, etc.
- * - *The output of this method is consistent across JDK versions. - * Note that this is the opposite order to the JDK1.4 display.
- * - *The method is equivalent to printStackTrace for throwables
- * that don't have nested causes.
Prints a compact stack trace for the root cause of a throwable.
- * - *The compact stack trace starts with the root cause and prints - * stack frames up to the place where it was caught and wrapped. - * Then it prints the wrapped exception and continues with stack frames - * until the wrapper exception is caught and wrapped again, etc.
- * - *The output of this method is consistent across JDK versions. - * Note that this is the opposite order to the JDK1.4 display.
- * - *The method is equivalent to printStackTrace for throwables
- * that don't have nested causes.
null
- * @since 2.0
- */
- public static void printRootCauseStackTrace(Throwable throwable, PrintStream stream) {
- if (throwable == null) {
- return;
- }
- if (stream == null) {
- throw new IllegalArgumentException("The PrintStream must not be null");
- }
- String trace[] = getRootCauseStackTrace(throwable);
- for (String element : trace) {
- stream.println(element);
- }
- stream.flush();
- }
-
- /**
- * Prints a compact stack trace for the root cause of a throwable.
- * - *The compact stack trace starts with the root cause and prints - * stack frames up to the place where it was caught and wrapped. - * Then it prints the wrapped exception and continues with stack frames - * until the wrapper exception is caught and wrapped again, etc.
- * - *The output of this method is consistent across JDK versions. - * Note that this is the opposite order to the JDK1.4 display.
- * - *The method is equivalent to printStackTrace for throwables
- * that don't have nested causes.
null
- * @since 2.0
- */
- public static void printRootCauseStackTrace(Throwable throwable, PrintWriter writer) {
- if (throwable == null) {
- return;
- }
- if (writer == null) {
- throw new IllegalArgumentException("The PrintWriter must not be null");
- }
- String trace[] = getRootCauseStackTrace(throwable);
- for (String element : trace) {
- writer.println(element);
- }
- writer.flush();
- }
-
- //-----------------------------------------------------------------------
- /**
- * Creates a compact stack trace for the root cause of the supplied
- * Throwable.
The output of this method is consistent across JDK versions. - * It consists of the root exception followed by each of its wrapping - * exceptions separated by '[wrapped]'. Note that this is the opposite - * order to the JDK1.4 display.
- * - * @param throwable the throwable to examine, may be null - * @return an array of stack trace frames, never null - * @since 2.0 - */ - public static String[] getRootCauseStackTrace(Throwable throwable) { - if (throwable == null) { - return ArrayUtils.EMPTY_STRING_ARRAY; - } - Throwable throwables[] = getThrowables(throwable); - int count = throwables.length; - ListRemoves common frames from the cause trace given the two stack traces.
- * - * @param causeFrames stack trace of a cause throwable - * @param wrapperFrames stack trace of a wrapper throwable - * @throws IllegalArgumentException if either argument is null - * @since 2.0 - */ - public static void removeCommonFrames(ListGets the stack trace from a Throwable as a String.
- * - *The result of this method vary by JDK version as this method - * uses {@link Throwable#printStackTrace(java.io.PrintWriter)}. - * On JDK1.3 and earlier, the cause exception will not be shown - * unless the specified throwable alters printStackTrace.
- * - * @param throwable theThrowable to be examined
- * @return the stack trace as generated by the exception's
- * printStackTrace(PrintWriter) method
- */
- public static String getStackTrace(Throwable throwable) {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw, true);
- throwable.printStackTrace(pw);
- return sw.getBuffer().toString();
- }
-
- /**
- * Captures the stack trace associated with the specified
- * Throwable object, decomposing it into a list of
- * stack frames.
The result of this method vary by JDK version as this method - * uses {@link Throwable#printStackTrace(java.io.PrintWriter)}. - * On JDK1.3 and earlier, the cause exception will not be shown - * unless the specified throwable alters printStackTrace.
- * - * @param throwable theThrowable to examine, may be null
- * @return an array of strings describing each stack frame, never null
- */
- public static String[] getStackFrames(Throwable throwable) {
- if (throwable == null) {
- return ArrayUtils.EMPTY_STRING_ARRAY;
- }
- return getStackFrames(getStackTrace(throwable));
- }
-
- //-----------------------------------------------------------------------
- /**
- * Returns an array where each element is a line from the argument.
- * - *The end of line is determined by the value of {@link SystemUtils#LINE_SEPARATOR}.
- * - * @param stackTrace a stack trace String - * @return an array where each element is a line from the argument - */ - static String[] getStackFrames(String stackTrace) { - String linebreak = SystemUtils.LINE_SEPARATOR; - StringTokenizer frames = new StringTokenizer(stackTrace, linebreak); - ListProduces a List of stack frames - the message
- * is not included. Only the trace of the specified exception is
- * returned, any caused by trace is stripped.
This works in most cases - it will only fail if the exception
- * message contains a line that starts with:
- * " at".
- * The message returned is of the form - * {ClassNameWithoutPackage}: {ThrowableMessage} - * - * @param th the throwable to get a message for, null returns empty string - * @return the message, non-null - * @since Commons Lang 2.2 - */ - public static String getMessage(Throwable th) { - if (th == null) { - return ""; - } - String clsName = ClassUtils.getShortClassName(th, null); - String msg = th.getMessage(); - return clsName + ": " + StringUtils.defaultString(msg); - } - - //----------------------------------------------------------------------- - /** - * Gets a short message summarising the root cause exception. - *
- * The message returned is of the form - * {ClassNameWithoutPackage}: {ThrowableMessage} - * - * @param th the throwable to get a message for, null returns empty string - * @return the message, non-null - * @since Commons Lang 2.2 - */ - public static String getRootCauseMessage(Throwable th) { - Throwable root = ExceptionUtils.getRootCause(th); - root = (root == null ? th : root); - return getMessage(root); - } - -} +/* + * 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.commons.lang3.exception; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.SystemUtils; + +/** + *
Provides utilities for manipulating and examining
+ * Throwable objects.
Used when printing stack frames to denote the start of a + * wrapped exception.
+ * + *Package private for accessibility by test suite.
+ */ + static final String WRAPPED_MARKER = " [wrapped] "; + + /** + *The names of methods commonly used to access a wrapped exception.
+ */ + // TODO: Remove in Lang 4.0 + private static final String[] CAUSE_METHOD_NAMES = { + "getCause", + "getNextException", + "getTargetException", + "getException", + "getSourceException", + "getRootCause", + "getCausedByException", + "getNested", + "getLinkedException", + "getNestedException", + "getLinkedCause", + "getThrowable", + }; + + /** + *
+ * Public constructor allows an instance of ExceptionUtils to be created, although that is not
+ * normally necessary.
+ *
Returns the default names used when searching for the cause of an exception.
+ * + *This may be modified and used in the overloaded getCause(Throwable, String[]) method.
+ * + * @return cloned array of the default method names + * @since 3.0 + * @deprecated This feature will be removed in Lang 4.0 + */ + @Deprecated + public static String[] getDefaultCauseMethodNames() { + return ArrayUtils.clone(CAUSE_METHOD_NAMES); + } + + //----------------------------------------------------------------------- + /** + *Introspects the Throwable to obtain the cause.
The method searches for methods with specific names that return a
+ * Throwable object. This will pick up most wrapping exceptions,
+ * including those from JDK 1.4.
+ *
+ *
The default list searched for are:
+ *getCause()getNextException()getTargetException()getException()getSourceException()getRootCause()getCausedByException()getNested()If none of the above is found, returns null.
Throwable,
+ * null if none found or null throwable input
+ * @since 1.0
+ * @deprecated This feature will be removed in Lang 4.0
+ */
+ @Deprecated
+ public static Throwable getCause(Throwable throwable) {
+ return getCause(throwable, CAUSE_METHOD_NAMES);
+ }
+
+ /**
+ * Introspects the Throwable to obtain the cause.
A null set of method names means use the default set.
+ * A null in the set of method names will be ignored.
Throwable,
+ * null if none found or null throwable input
+ * @since 1.0
+ * @deprecated This feature will be removed in Lang 4.0
+ */
+ @Deprecated
+ public static Throwable getCause(Throwable throwable, String[] methodNames) {
+ if (throwable == null) {
+ return null;
+ }
+
+ if (methodNames == null) {
+ methodNames = CAUSE_METHOD_NAMES;
+ }
+
+ for (String methodName : methodNames) {
+ if (methodName != null) {
+ Throwable cause = getCauseUsingMethodName(throwable, methodName);
+ if (cause != null) {
+ return cause;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Introspects the Throwable to obtain the root cause.
This method walks through the exception chain to the last element, + * "root" of the tree, using {@link #getCause(Throwable)}, and + * returns that exception.
+ * + *From version 2.2, this method handles recursive cause structures + * that might otherwise cause infinite loops. If the throwable parameter + * has a cause of itself, then null will be returned. If the throwable + * parameter cause chain loops, the last element in the chain before the + * loop is returned.
+ * + * @param throwable the throwable to get the root cause for, may be null + * @return the root cause of theThrowable,
+ * null if none found or null throwable input
+ */
+ public static Throwable getRootCause(Throwable throwable) {
+ ListFinds a Throwable by method name.
null if not found
+ */
+ // TODO: Remove in Lang 4.0
+ private static Throwable getCauseUsingMethodName(Throwable throwable, String methodName) {
+ Method method = null;
+ try {
+ method = throwable.getClass().getMethod(methodName);
+ } catch (NoSuchMethodException ignored) { // NOPMD
+ // exception ignored
+ } catch (SecurityException ignored) { // NOPMD
+ // exception ignored
+ }
+
+ if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) {
+ try {
+ return (Throwable) method.invoke(throwable);
+ } catch (IllegalAccessException ignored) { // NOPMD
+ // exception ignored
+ } catch (IllegalArgumentException ignored) { // NOPMD
+ // exception ignored
+ } catch (InvocationTargetException ignored) { // NOPMD
+ // exception ignored
+ }
+ }
+ return null;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Counts the number of Throwable objects in the
+ * exception chain.
A throwable without cause will return 1.
+ * A throwable with one cause will return 2 and so on.
+ * A null throwable will return 0.
From version 2.2, this method handles recursive cause structures + * that might otherwise cause infinite loops. The cause chain is + * processed until the end is reached, or until the next item in the + * chain is already in the result set.
+ * + * @param throwable the throwable to inspect, may be null + * @return the count of throwables, zero if null input + */ + public static int getThrowableCount(Throwable throwable) { + return getThrowableList(throwable).size(); + } + + /** + *Returns the list of Throwable objects in the
+ * exception chain.
A throwable without cause will return an array containing
+ * one element - the input throwable.
+ * A throwable with one cause will return an array containing
+ * two elements. - the input throwable and the cause throwable.
+ * A null throwable will return an array of size zero.
From version 2.2, this method handles recursive cause structures + * that might otherwise cause infinite loops. The cause chain is + * processed until the end is reached, or until the next item in the + * chain is already in the result set.
+ * + * @see #getThrowableList(Throwable) + * @param throwable the throwable to inspect, may be null + * @return the array of throwables, never null + */ + public static Throwable[] getThrowables(Throwable throwable) { + ListReturns the list of Throwable objects in the
+ * exception chain.
A throwable without cause will return a list containing
+ * one element - the input throwable.
+ * A throwable with one cause will return a list containing
+ * two elements. - the input throwable and the cause throwable.
+ * A null throwable will return a list of size zero.
This method handles recursive cause structures that might + * otherwise cause infinite loops. The cause chain is processed until + * the end is reached, or until the next item in the chain is already + * in the result set.
+ * + * @param throwable the throwable to inspect, may be null + * @return the list of throwables, never null + * @since Commons Lang 2.2 + */ + public static ListReturns the (zero based) index of the first Throwable
+ * that matches the specified class (exactly) in the exception chain.
+ * Subclasses of the specified class do not match - see
+ * {@link #indexOfType(Throwable, Class)} for the opposite.
A null throwable returns -1.
+ * A null type returns -1.
+ * No match in the chain returns -1.
Returns the (zero based) index of the first Throwable
+ * that matches the specified type in the exception chain from
+ * a specified index.
+ * Subclasses of the specified class do not match - see
+ * {@link #indexOfType(Throwable, Class, int)} for the opposite.
A null throwable returns -1.
+ * A null type returns -1.
+ * No match in the chain returns -1.
+ * A negative start index is treated as zero.
+ * A start index greater than the number of throwables returns -1.
Returns the (zero based) index of the first Throwable
+ * that matches the specified class or subclass in the exception chain.
+ * Subclasses of the specified class do match - see
+ * {@link #indexOfThrowable(Throwable, Class)} for the opposite.
A null throwable returns -1.
+ * A null type returns -1.
+ * No match in the chain returns -1.
Returns the (zero based) index of the first Throwable
+ * that matches the specified type in the exception chain from
+ * a specified index.
+ * Subclasses of the specified class do match - see
+ * {@link #indexOfThrowable(Throwable, Class)} for the opposite.
A null throwable returns -1.
+ * A null type returns -1.
+ * No match in the chain returns -1.
+ * A negative start index is treated as zero.
+ * A start index greater than the number of throwables returns -1.
Worker method for the indexOfType methods.
true, compares with {@link Class#isAssignableFrom(Class)}, otherwise compares
+ * using references
+ * @return index of the type within throwables nested withing the specified throwable
+ */
+ private static int indexOf(Throwable throwable, Class> type, int fromIndex, boolean subclass) {
+ if (throwable == null || type == null) {
+ return -1;
+ }
+ if (fromIndex < 0) {
+ fromIndex = 0;
+ }
+ Throwable[] throwables = ExceptionUtils.getThrowables(throwable);
+ if (fromIndex >= throwables.length) {
+ return -1;
+ }
+ if (subclass) {
+ for (int i = fromIndex; i < throwables.length; i++) {
+ if (type.isAssignableFrom(throwables[i].getClass())) {
+ return i;
+ }
+ }
+ } else {
+ for (int i = fromIndex; i < throwables.length; i++) {
+ if (type.equals(throwables[i].getClass())) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Prints a compact stack trace for the root cause of a throwable
+ * to System.err.
The compact stack trace starts with the root cause and prints + * stack frames up to the place where it was caught and wrapped. + * Then it prints the wrapped exception and continues with stack frames + * until the wrapper exception is caught and wrapped again, etc.
+ * + *The output of this method is consistent across JDK versions. + * Note that this is the opposite order to the JDK1.4 display.
+ * + *The method is equivalent to printStackTrace for throwables
+ * that don't have nested causes.
Prints a compact stack trace for the root cause of a throwable.
+ * + *The compact stack trace starts with the root cause and prints + * stack frames up to the place where it was caught and wrapped. + * Then it prints the wrapped exception and continues with stack frames + * until the wrapper exception is caught and wrapped again, etc.
+ * + *The output of this method is consistent across JDK versions. + * Note that this is the opposite order to the JDK1.4 display.
+ * + *The method is equivalent to printStackTrace for throwables
+ * that don't have nested causes.
null
+ * @since 2.0
+ */
+ public static void printRootCauseStackTrace(Throwable throwable, PrintStream stream) {
+ if (throwable == null) {
+ return;
+ }
+ if (stream == null) {
+ throw new IllegalArgumentException("The PrintStream must not be null");
+ }
+ String trace[] = getRootCauseStackTrace(throwable);
+ for (String element : trace) {
+ stream.println(element);
+ }
+ stream.flush();
+ }
+
+ /**
+ * Prints a compact stack trace for the root cause of a throwable.
+ * + *The compact stack trace starts with the root cause and prints + * stack frames up to the place where it was caught and wrapped. + * Then it prints the wrapped exception and continues with stack frames + * until the wrapper exception is caught and wrapped again, etc.
+ * + *The output of this method is consistent across JDK versions. + * Note that this is the opposite order to the JDK1.4 display.
+ * + *The method is equivalent to printStackTrace for throwables
+ * that don't have nested causes.
null
+ * @since 2.0
+ */
+ public static void printRootCauseStackTrace(Throwable throwable, PrintWriter writer) {
+ if (throwable == null) {
+ return;
+ }
+ if (writer == null) {
+ throw new IllegalArgumentException("The PrintWriter must not be null");
+ }
+ String trace[] = getRootCauseStackTrace(throwable);
+ for (String element : trace) {
+ writer.println(element);
+ }
+ writer.flush();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Creates a compact stack trace for the root cause of the supplied
+ * Throwable.
The output of this method is consistent across JDK versions. + * It consists of the root exception followed by each of its wrapping + * exceptions separated by '[wrapped]'. Note that this is the opposite + * order to the JDK1.4 display.
+ * + * @param throwable the throwable to examine, may be null + * @return an array of stack trace frames, never null + * @since 2.0 + */ + public static String[] getRootCauseStackTrace(Throwable throwable) { + if (throwable == null) { + return ArrayUtils.EMPTY_STRING_ARRAY; + } + Throwable throwables[] = getThrowables(throwable); + int count = throwables.length; + ListRemoves common frames from the cause trace given the two stack traces.
+ * + * @param causeFrames stack trace of a cause throwable + * @param wrapperFrames stack trace of a wrapper throwable + * @throws IllegalArgumentException if either argument is null + * @since 2.0 + */ + public static void removeCommonFrames(ListGets the stack trace from a Throwable as a String.
+ * + *The result of this method vary by JDK version as this method + * uses {@link Throwable#printStackTrace(java.io.PrintWriter)}. + * On JDK1.3 and earlier, the cause exception will not be shown + * unless the specified throwable alters printStackTrace.
+ * + * @param throwable theThrowable to be examined
+ * @return the stack trace as generated by the exception's
+ * printStackTrace(PrintWriter) method
+ */
+ public static String getStackTrace(Throwable throwable) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw, true);
+ throwable.printStackTrace(pw);
+ return sw.getBuffer().toString();
+ }
+
+ /**
+ * Captures the stack trace associated with the specified
+ * Throwable object, decomposing it into a list of
+ * stack frames.
The result of this method vary by JDK version as this method + * uses {@link Throwable#printStackTrace(java.io.PrintWriter)}. + * On JDK1.3 and earlier, the cause exception will not be shown + * unless the specified throwable alters printStackTrace.
+ * + * @param throwable theThrowable to examine, may be null
+ * @return an array of strings describing each stack frame, never null
+ */
+ public static String[] getStackFrames(Throwable throwable) {
+ if (throwable == null) {
+ return ArrayUtils.EMPTY_STRING_ARRAY;
+ }
+ return getStackFrames(getStackTrace(throwable));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns an array where each element is a line from the argument.
+ * + *The end of line is determined by the value of {@link SystemUtils#LINE_SEPARATOR}.
+ * + * @param stackTrace a stack trace String + * @return an array where each element is a line from the argument + */ + static String[] getStackFrames(String stackTrace) { + String linebreak = SystemUtils.LINE_SEPARATOR; + StringTokenizer frames = new StringTokenizer(stackTrace, linebreak); + ListProduces a List of stack frames - the message
+ * is not included. Only the trace of the specified exception is
+ * returned, any caused by trace is stripped.
This works in most cases - it will only fail if the exception
+ * message contains a line that starts with:
+ * " at".
+ * The message returned is of the form + * {ClassNameWithoutPackage}: {ThrowableMessage} + * + * @param th the throwable to get a message for, null returns empty string + * @return the message, non-null + * @since Commons Lang 2.2 + */ + public static String getMessage(Throwable th) { + if (th == null) { + return ""; + } + String clsName = ClassUtils.getShortClassName(th, null); + String msg = th.getMessage(); + return clsName + ": " + StringUtils.defaultString(msg); + } + + //----------------------------------------------------------------------- + /** + * Gets a short message summarising the root cause exception. + *
+ * The message returned is of the form + * {ClassNameWithoutPackage}: {ThrowableMessage} + * + * @param th the throwable to get a message for, null returns empty string + * @return the message, non-null + * @since Commons Lang 2.2 + */ + public static String getRootCauseMessage(Throwable th) { + Throwable root = ExceptionUtils.getRootCause(th); + root = (root == null ? th : root); + return getMessage(root); + } + +} diff --git a/src/org/apache/commons/lang3/mutable/Mutable.java b/src/org/apache/commons/lang3/mutable/Mutable.java index 64514f0..25a78f2 100644 --- a/src/org/apache/commons/lang3/mutable/Mutable.java +++ b/src/org/apache/commons/lang3/mutable/Mutable.java @@ -1,54 +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.commons.lang3.mutable; - -/** - * Provides mutable access to a value. - *
- * Mutable is used as a generic interface to the implementations in this package.
- *
- * A typical use case would be to enable a primitive or string to be passed to a method and allow that method to
- * effectively change the value of the primitive/string. Another use case is to store a frequently changing primitive in
- * a collection (for example a total in a map) without needing to create new Integer/Long wrapper objects.
- *
- * @since 2.1
- * @param
+ *
+ * A typical use case would be to enable a primitive or string to be passed to a method and allow that method to
+ * effectively change the value of the primitive/string. Another use case is to store a frequently changing primitive in
+ * a collection (for example a total in a map) without needing to create new Integer/Long wrapper objects.
+ *
+ * @since 2.1
+ * @param
- * Note that as MutableBoolean does not extend Boolean, it is not treated by String.format as a Boolean parameter.
- *
- * @see Boolean
- * @since 2.2
- * @version $Id: MutableBoolean.java 1160571 2011-08-23 07:36:08Z bayard $
- */
-public class MutableBoolean implements Mutable
+ * Note that as MutableBoolean does not extend Boolean, it is not treated by String.format as a Boolean parameter.
+ *
+ * @see Boolean
+ * @since 2.2
+ * @version $Id: MutableBoolean.java 1160571 2011-08-23 07:36:08Z bayard $
+ */
+public class MutableBoolean implements Mutable
- * Note that as MutableByte does not extend Byte, it is not treated by String.format as a Byte parameter.
- *
- * @see Byte
- * @since 2.1
- * @version $Id: MutableByte.java 1160571 2011-08-23 07:36:08Z bayard $
- */
-public class MutableByte extends Number implements Comparable
+ * Note that as MutableByte does not extend Byte, it is not treated by String.format as a Byte parameter.
+ *
+ * @see Byte
+ * @since 2.1
+ * @version $Id: MutableByte.java 1160571 2011-08-23 07:36:08Z bayard $
+ */
+public class MutableByte extends Number implements Comparable
- * Note that as MutableDouble does not extend Double, it is not treated by String.format as a Double parameter.
- *
- * @see Double
- * @since 2.1
- * @version $Id: MutableDouble.java 1160571 2011-08-23 07:36:08Z bayard $
- */
-public class MutableDouble extends Number implements Comparable
- * Note that in most cases, for two instances of class
- * also has the value
+ * Note that as MutableDouble does not extend Double, it is not treated by String.format as a Double parameter.
+ *
+ * @see Double
+ * @since 2.1
+ * @version $Id: MutableDouble.java 1160571 2011-08-23 07:36:08Z bayard $
+ */
+public class MutableDouble extends Number implements ComparableMutable is used as a generic interface to the implementations in this package.
+ * boolean wrapper.
- * true.
- *
- * @return true if the current value is true
- * @since 2.5
- */
- public boolean isTrue() {
- return value == true;
- }
-
- /**
- * Checks if the current value is false.
- *
- * @return true if the current value is false
- * @since 2.5
- */
- public boolean isFalse() {
- return value == false;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Returns the value of this MutableBoolean as a boolean.
- *
- * @return the boolean value represented by this object.
- */
- public boolean booleanValue() {
- return value;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Gets this mutable as an instance of Boolean.
- *
- * @return a Boolean instance containing the value from this mutable, never null
- * @since 2.5
- */
- public Boolean toBoolean() {
- return Boolean.valueOf(booleanValue());
- }
-
- //-----------------------------------------------------------------------
- /**
- * Compares this object to the specified object. The result is true if and only if the argument is
- * not null and is an MutableBoolean object that contains the same
- * boolean value as this object.
- *
- * @param obj the object to compare with, null returns false
- * @return true if the objects are the same; false otherwise.
- */
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof MutableBoolean) {
- return value == ((MutableBoolean) obj).booleanValue();
- }
- return false;
- }
-
- /**
- * Returns a suitable hash code for this mutable.
- *
- * @return the hash code returned by Boolean.TRUE or Boolean.FALSE
- */
- @Override
- public int hashCode() {
- return value ? Boolean.TRUE.hashCode() : Boolean.FALSE.hashCode();
- }
-
- //-----------------------------------------------------------------------
- /**
- * Compares this mutable to another in ascending order.
- *
- * @param other the other mutable to compare to, not null
- * @return negative if this is less, zero if equal, positive if greater
- * where false is less than true
- */
- public int compareTo(MutableBoolean other) {
- boolean anotherVal = other.value;
- return value == anotherVal ? 0 : (value ? 1 : -1);
- }
-
- //-----------------------------------------------------------------------
- /**
- * Returns the String value of this mutable.
- *
- * @return the mutable value as a string
- */
- @Override
- public String toString() {
- return String.valueOf(value);
- }
-
-}
+/*
+ * 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.commons.lang3.mutable;
+
+import java.io.Serializable;
+
+/**
+ * A mutable boolean wrapper.
+ * true.
+ *
+ * @return true if the current value is true
+ * @since 2.5
+ */
+ public boolean isTrue() {
+ return value == true;
+ }
+
+ /**
+ * Checks if the current value is false.
+ *
+ * @return true if the current value is false
+ * @since 2.5
+ */
+ public boolean isFalse() {
+ return value == false;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns the value of this MutableBoolean as a boolean.
+ *
+ * @return the boolean value represented by this object.
+ */
+ public boolean booleanValue() {
+ return value;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets this mutable as an instance of Boolean.
+ *
+ * @return a Boolean instance containing the value from this mutable, never null
+ * @since 2.5
+ */
+ public Boolean toBoolean() {
+ return Boolean.valueOf(booleanValue());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Compares this object to the specified object. The result is true if and only if the argument is
+ * not null and is an MutableBoolean object that contains the same
+ * boolean value as this object.
+ *
+ * @param obj the object to compare with, null returns false
+ * @return true if the objects are the same; false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof MutableBoolean) {
+ return value == ((MutableBoolean) obj).booleanValue();
+ }
+ return false;
+ }
+
+ /**
+ * Returns a suitable hash code for this mutable.
+ *
+ * @return the hash code returned by Boolean.TRUE or Boolean.FALSE
+ */
+ @Override
+ public int hashCode() {
+ return value ? Boolean.TRUE.hashCode() : Boolean.FALSE.hashCode();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Compares this mutable to another in ascending order.
+ *
+ * @param other the other mutable to compare to, not null
+ * @return negative if this is less, zero if equal, positive if greater
+ * where false is less than true
+ */
+ public int compareTo(MutableBoolean other) {
+ boolean anotherVal = other.value;
+ return value == anotherVal ? 0 : (value ? 1 : -1);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns the String value of this mutable.
+ *
+ * @return the mutable value as a string
+ */
+ @Override
+ public String toString() {
+ return String.valueOf(value);
+ }
+
+}
diff --git a/src/org/apache/commons/lang3/mutable/MutableByte.java b/src/org/apache/commons/lang3/mutable/MutableByte.java
index 129d86d..0a50108 100644
--- a/src/org/apache/commons/lang3/mutable/MutableByte.java
+++ b/src/org/apache/commons/lang3/mutable/MutableByte.java
@@ -1,283 +1,283 @@
-/*
- * 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.commons.lang3.mutable;
-
-/**
- * A mutable byte wrapper.
- * true if and only if the argument is
- * not null and is a MutableByte object that contains the same byte value
- * as this object.
- *
- * @param obj the object to compare with, null returns false
- * @return true if the objects are the same; false otherwise.
- */
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof MutableByte) {
- return value == ((MutableByte) obj).byteValue();
- }
- return false;
- }
-
- /**
- * Returns a suitable hash code for this mutable.
- *
- * @return a suitable hash code
- */
- @Override
- public int hashCode() {
- return value;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Compares this mutable to another in ascending order.
- *
- * @param other the other mutable to compare to, not null
- * @return negative if this is less, zero if equal, positive if greater
- */
- public int compareTo(MutableByte other) {
- byte anotherVal = other.value;
- return value < anotherVal ? -1 : (value == anotherVal ? 0 : 1);
- }
-
- //-----------------------------------------------------------------------
- /**
- * Returns the String value of this mutable.
- *
- * @return the mutable value as a string
- */
- @Override
- public String toString() {
- return String.valueOf(value);
- }
-
-}
+/*
+ * 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.commons.lang3.mutable;
+
+/**
+ * A mutable byte wrapper.
+ * true if and only if the argument is
+ * not null and is a MutableByte object that contains the same byte value
+ * as this object.
+ *
+ * @param obj the object to compare with, null returns false
+ * @return true if the objects are the same; false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof MutableByte) {
+ return value == ((MutableByte) obj).byteValue();
+ }
+ return false;
+ }
+
+ /**
+ * Returns a suitable hash code for this mutable.
+ *
+ * @return a suitable hash code
+ */
+ @Override
+ public int hashCode() {
+ return value;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Compares this mutable to another in ascending order.
+ *
+ * @param other the other mutable to compare to, not null
+ * @return negative if this is less, zero if equal, positive if greater
+ */
+ public int compareTo(MutableByte other) {
+ byte anotherVal = other.value;
+ return value < anotherVal ? -1 : (value == anotherVal ? 0 : 1);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns the String value of this mutable.
+ *
+ * @return the mutable value as a string
+ */
+ @Override
+ public String toString() {
+ return String.valueOf(value);
+ }
+
+}
diff --git a/src/org/apache/commons/lang3/mutable/MutableDouble.java b/src/org/apache/commons/lang3/mutable/MutableDouble.java
index f4acfa9..588a711 100644
--- a/src/org/apache/commons/lang3/mutable/MutableDouble.java
+++ b/src/org/apache/commons/lang3/mutable/MutableDouble.java
@@ -1,312 +1,312 @@
-/*
- * 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.commons.lang3.mutable;
-
-/**
- * A mutable double wrapper.
- * true if and only if the argument
- * is not null and is a Double object that represents a double that has the identical
- * bit pattern to the bit pattern of the double represented by this object. For this purpose, two
- * double values are considered to be the same if and only if the method
- * {@link Double#doubleToLongBits(double)}returns the same long value when applied to each.
- * Double,d1 and d2,
- * the value of d1.equals(d2) is true if and only if
- *
- *
- *
- * d1.doubleValue() == d2.doubleValue()
- *
- *
- * true. However, there are two exceptions:
- *
- *
- *
- * @param obj the object to compare with, null returns false
- * @return d1 and d2 both represent Double.NaN, then the
- * equals method returns true, even though Double.NaN==Double.NaN has
- * the value false.
- * d1 represents +0.0 while d2 represents -0.0,
- * or vice versa, the equal test has the value false, even though
- * +0.0==-0.0 has the value true. This allows hashtables to operate properly.
- * true if the objects are the same; false otherwise.
- */
- @Override
- public boolean equals(Object obj) {
- return (obj instanceof MutableDouble)
- && (Double.doubleToLongBits(((MutableDouble) obj).value) == Double.doubleToLongBits(value));
- }
-
- /**
- * Returns a suitable hash code for this mutable.
- *
- * @return a suitable hash code
- */
- @Override
- public int hashCode() {
- long bits = Double.doubleToLongBits(value);
- return (int) (bits ^ (bits >>> 32));
- }
-
- //-----------------------------------------------------------------------
- /**
- * Compares this mutable to another in ascending order.
- *
- * @param other the other mutable to compare to, not null
- * @return negative if this is less, zero if equal, positive if greater
- */
- public int compareTo(MutableDouble other) {
- double anotherVal = other.value;
- return Double.compare(value, anotherVal);
- }
-
- //-----------------------------------------------------------------------
- /**
- * Returns the String value of this mutable.
- *
- * @return the mutable value as a string
- */
- @Override
- public String toString() {
- return String.valueOf(value);
- }
-
-}
+/*
+ * 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.commons.lang3.mutable;
+
+/**
+ * A mutable double wrapper.
+ *