commons-lang-2.6-src/build.xml 100644 0 0 32203 11513702447 13534 0 ustar 0 0
The standard Java libraries fail to provide enough methods for manipulation of its main components. The Lang Package provides these extra methods. There are other classes which might justifiably be included in java.lang someday, this package also provides for them.
This proposal is to create a package of Java utility classes for the classes that are in java.lang's hierarchy, or are considered to be so standard as to justify existence in java.lang. The Lang Package also applies to primitives and arrays.
Lang relies only on standard JDK 1.2 (or later) APIs for production deployment. It utilizes the JUnit unit testing framework for developing and executing unit tests, but this is of interest only to developers of the component. Lang will be a dependency for several existing components in the open source world.
No external configuration files are utilized.
The initial classes came from the Commons.Util subproject.
The proposed package name for the new component is
org.apache.commons.lang
.
lang
in the
jakarta-commons
CVS repository.The initial committers on the Lang component shall be as follows:
Operations on arrays, primitive arrays (like int[]
) and
* primitive wrapper arrays (like Integer[]
).
This class tries to handle null
input gracefully.
* An exception will not be thrown for a null
* array input. However, an Object array that contains a null
* element may throw an exception. Each method documents its behaviour.
#ThreadSafe#
* @author Apache Software Foundation * @author Moritz Petersen * @author Fredrik Westermarck * @author Nikolay Metchev * @author Matthew Hawthorne * @author Tim O'Brien * @author Pete Gieser * @author Gary Gregory * @author Ashwin S * @author Maarten Coene * @since 2.0 * @version $Id: ArrayUtils.java 1056988 2011-01-09 17:58:53Z niallp $ */ public class ArrayUtils { /** * An empty immutableObject
array.
*/
public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
/**
* An empty immutable Class
array.
*/
public static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
/**
* An empty immutable String
array.
*/
public static final String[] EMPTY_STRING_ARRAY = new String[0];
/**
* An empty immutable long
array.
*/
public static final long[] EMPTY_LONG_ARRAY = new long[0];
/**
* An empty immutable Long
array.
*/
public static final Long[] EMPTY_LONG_OBJECT_ARRAY = new Long[0];
/**
* An empty immutable int
array.
*/
public static final int[] EMPTY_INT_ARRAY = new int[0];
/**
* An empty immutable Integer
array.
*/
public static final Integer[] EMPTY_INTEGER_OBJECT_ARRAY = new Integer[0];
/**
* An empty immutable short
array.
*/
public static final short[] EMPTY_SHORT_ARRAY = new short[0];
/**
* An empty immutable Short
array.
*/
public static final Short[] EMPTY_SHORT_OBJECT_ARRAY = new Short[0];
/**
* An empty immutable byte
array.
*/
public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
/**
* An empty immutable Byte
array.
*/
public static final Byte[] EMPTY_BYTE_OBJECT_ARRAY = new Byte[0];
/**
* An empty immutable double
array.
*/
public static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
/**
* An empty immutable Double
array.
*/
public static final Double[] EMPTY_DOUBLE_OBJECT_ARRAY = new Double[0];
/**
* An empty immutable float
array.
*/
public static final float[] EMPTY_FLOAT_ARRAY = new float[0];
/**
* An empty immutable Float
array.
*/
public static final Float[] EMPTY_FLOAT_OBJECT_ARRAY = new Float[0];
/**
* An empty immutable boolean
array.
*/
public static final boolean[] EMPTY_BOOLEAN_ARRAY = new boolean[0];
/**
* An empty immutable Boolean
array.
*/
public static final Boolean[] EMPTY_BOOLEAN_OBJECT_ARRAY = new Boolean[0];
/**
* An empty immutable char
array.
*/
public static final char[] EMPTY_CHAR_ARRAY = new char[0];
/**
* An empty immutable Character
array.
*/
public static final Character[] EMPTY_CHARACTER_OBJECT_ARRAY = new Character[0];
/**
* The index value when an element is not found in a list or array: -1
.
* This value is returned by methods in this class and can also be used in comparisons with values returned by
* various method from {@link java.util.List}.
*/
public static final int INDEX_NOT_FOUND = -1;
/**
* ArrayUtils instances should NOT be constructed in standard programming.
* Instead, the class should be used as ArrayUtils.clone(new int[] {2})
.
This constructor is public to permit tools that require a JavaBean instance * to operate.
*/ public ArrayUtils() { super(); } // Basic methods handling multi-dimensional arrays //----------------------------------------------------------------------- /** *Outputs an array as a String, treating 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 {a,b}
.
null
* @return a String representation of the array, '{}' if null array input
*/
public static String toString(Object array) {
return toString(array, "{}");
}
/**
* Outputs an array as a String handling null
s.
Multi-dimensional arrays are handled correctly, including * multi-dimensional primitive arrays.
* *The format is that of Java source code, for example {a,b}
.
null
* @param stringIfNull the String to return if the array is null
* @return a String representation of the array
*/
public static String toString(Object array, String stringIfNull) {
if (array == null) {
return stringIfNull;
}
return new ToStringBuilder(array, ToStringStyle.SIMPLE_STYLE).append(array).toString();
}
/**
* Get a hashCode for an array handling multi-dimensional arrays correctly.
* *Multi-dimensional primitive arrays are also handled correctly by this method.
* * @param array the array to get a hashCode for, may benull
* @return a hashCode for the array, zero if null array input
*/
public static int hashCode(Object array) {
return new HashCodeBuilder().append(array).toHashCode();
}
/**
* Compares two arrays, using equals(), handling multi-dimensional arrays * correctly.
* *Multi-dimensional primitive arrays are also handled correctly by this method.
* * @param array1 the left hand array to compare, may benull
* @param array2 the right hand array to compare, may be null
* @return true
if the arrays are equal
*/
public static boolean isEquals(Object array1, Object array2) {
return new EqualsBuilder().append(array1, array2).isEquals();
}
// To map
//-----------------------------------------------------------------------
/**
* 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:
** // Create a Map mapping colors. * Map colorMap = MapUtils.toMap(new String[][] {{ * {"RED", "#FF0000"}, * {"GREEN", "#00FF00"}, * {"BLUE", "#0000FF"}}); ** *
This method returns null
for a null
input array.
null
* @return a Map
that was created from the array
* @throws IllegalArgumentException if one element of this Array is
* itself an Array containing less then two elements
* @throws IllegalArgumentException if the array contains elements other
* than {@link java.util.Map.Entry} and an Array
*/
public static Map toMap(Object[] array) {
if (array == null) {
return null;
}
final Map map = new HashMap((int) (array.length * 1.5));
for (int i = 0; i < array.length; i++) {
Object object = array[i];
if (object instanceof Map.Entry) {
Map.Entry entry = (Map.Entry) object;
map.put(entry.getKey(), entry.getValue());
} else if (object instanceof Object[]) {
Object[] entry = (Object[]) object;
if (entry.length < 2) {
throw new IllegalArgumentException("Array element " + i + ", '"
+ object
+ "', has a length less than 2");
}
map.put(entry[0], entry[1]);
} else {
throw new IllegalArgumentException("Array element " + i + ", '"
+ object
+ "', is neither of type Map.Entry nor an Array");
}
}
return map;
}
// Clone
//-----------------------------------------------------------------------
/**
* Shallow clones an array returning a typecast result and handling
* null
.
The objects in the array are not cloned, thus there is no special * handling for multi-dimensional arrays.
* *This method returns null
for a null
input array.
null
* @return the cloned array, null
if null
input
*/
public static Object[] clone(Object[] array) {
if (array == null) {
return null;
}
return (Object[]) array.clone();
}
/**
* Clones an array returning a typecast result and handling
* null
.
This method returns null
for a null
input array.
null
* @return the cloned array, null
if null
input
*/
public static long[] clone(long[] array) {
if (array == null) {
return null;
}
return (long[]) array.clone();
}
/**
* Clones an array returning a typecast result and handling
* null
.
This method returns null
for a null
input array.
null
* @return the cloned array, null
if null
input
*/
public static int[] clone(int[] array) {
if (array == null) {
return null;
}
return (int[]) array.clone();
}
/**
* Clones an array returning a typecast result and handling
* null
.
This method returns null
for a null
input array.
null
* @return the cloned array, null
if null
input
*/
public static short[] clone(short[] array) {
if (array == null) {
return null;
}
return (short[]) array.clone();
}
/**
* Clones an array returning a typecast result and handling
* null
.
This method returns null
for a null
input array.
null
* @return the cloned array, null
if null
input
*/
public static char[] clone(char[] array) {
if (array == null) {
return null;
}
return (char[]) array.clone();
}
/**
* Clones an array returning a typecast result and handling
* null
.
This method returns null
for a null
input array.
null
* @return the cloned array, null
if null
input
*/
public static byte[] clone(byte[] array) {
if (array == null) {
return null;
}
return (byte[]) array.clone();
}
/**
* Clones an array returning a typecast result and handling
* null
.
This method returns null
for a null
input array.
null
* @return the cloned array, null
if null
input
*/
public static double[] clone(double[] array) {
if (array == null) {
return null;
}
return (double[]) array.clone();
}
/**
* Clones an array returning a typecast result and handling
* null
.
This method returns null
for a null
input array.
null
* @return the cloned array, null
if null
input
*/
public static float[] clone(float[] array) {
if (array == null) {
return null;
}
return (float[]) array.clone();
}
/**
* Clones an array returning a typecast result and handling
* null
.
This method returns null
for a null
input array.
null
* @return the cloned array, null
if null
input
*/
public static boolean[] clone(boolean[] array) {
if (array == null) {
return null;
}
return (boolean[]) array.clone();
}
// nullToEmpty
//-----------------------------------------------------------------------
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static Object[] nullToEmpty(Object[] array) {
if (array == null || array.length == 0) {
return EMPTY_OBJECT_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static String[] nullToEmpty(String[] array) {
if (array == null || array.length == 0) {
return EMPTY_STRING_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static long[] nullToEmpty(long[] array) {
if (array == null || array.length == 0) {
return EMPTY_LONG_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static int[] nullToEmpty(int[] array) {
if (array == null || array.length == 0) {
return EMPTY_INT_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static short[] nullToEmpty(short[] array) {
if (array == null || array.length == 0) {
return EMPTY_SHORT_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static char[] nullToEmpty(char[] array) {
if (array == null || array.length == 0) {
return EMPTY_CHAR_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static byte[] nullToEmpty(byte[] array) {
if (array == null || array.length == 0) {
return EMPTY_BYTE_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static double[] nullToEmpty(double[] array) {
if (array == null || array.length == 0) {
return EMPTY_DOUBLE_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static float[] nullToEmpty(float[] array) {
if (array == null || array.length == 0) {
return EMPTY_FLOAT_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static boolean[] nullToEmpty(boolean[] array) {
if (array == null || array.length == 0) {
return EMPTY_BOOLEAN_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static Long[] nullToEmpty(Long[] array) {
if (array == null || array.length == 0) {
return EMPTY_LONG_OBJECT_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static Integer[] nullToEmpty(Integer[] array) {
if (array == null || array.length == 0) {
return EMPTY_INTEGER_OBJECT_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static Short[] nullToEmpty(Short[] array) {
if (array == null || array.length == 0) {
return EMPTY_SHORT_OBJECT_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static Character[] nullToEmpty(Character[] array) {
if (array == null || array.length == 0) {
return EMPTY_CHARACTER_OBJECT_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static Byte[] nullToEmpty(Byte[] array) {
if (array == null || array.length == 0) {
return EMPTY_BYTE_OBJECT_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static Double[] nullToEmpty(Double[] array) {
if (array == null || array.length == 0) {
return EMPTY_DOUBLE_OBJECT_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static Float[] nullToEmpty(Float[] array) {
if (array == null || array.length == 0) {
return EMPTY_FLOAT_OBJECT_ARRAY;
}
return array;
}
/**
* Defensive programming technique to change a null
* reference to an empty one.
This method returns an empty array for a null
input array.
As a memory optimizing technique an empty array passed in will be overridden with
* the empty public static
references in this class.
null
or empty
* @return the same array, public static
empty array if null
or empty input
* @since 2.5
*/
public static Boolean[] nullToEmpty(Boolean[] array) {
if (array == null || array.length == 0) {
return EMPTY_BOOLEAN_OBJECT_ARRAY;
}
return array;
}
// Subarrays
//-----------------------------------------------------------------------
/**
* Produces a new array containing the elements between * the start and end indices.
* *The start index is inclusive, the end index exclusive. * Null array input produces null output.
* *The component type of the subarray is always the same as
* that of the input array. Thus, if the input is an array of type
* Date
, the following usage is envisaged:
* Date[] someDates = (Date[])ArrayUtils.subarray(allDates, 2, 5); ** * @param array the array * @param startIndexInclusive the starting index. Undervalue (<0) * is promoted to 0, overvalue (>array.length) results * in an empty array. * @param endIndexExclusive elements up to endIndex-1 are present in the * returned subarray. Undervalue (< startIndex) produces * empty array, overvalue (>array.length) is demoted to * array length. * @return a new array containing the elements between * the start and end indices. * @since 2.1 */ public static Object[] subarray(Object[] array, int startIndexInclusive, int endIndexExclusive) { if (array == null) { return null; } if (startIndexInclusive < 0) { startIndexInclusive = 0; } if (endIndexExclusive > array.length) { endIndexExclusive = array.length; } int newSize = endIndexExclusive - startIndexInclusive; Class type = array.getClass().getComponentType(); if (newSize <= 0) { return (Object[]) Array.newInstance(type, 0); } Object[] subarray = (Object[]) Array.newInstance(type, newSize); System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); return subarray; } /** *
Produces a new long
array containing the elements
* between the start and end indices.
The start index is inclusive, the end index exclusive. * Null array input produces null output.
* * @param array the array * @param startIndexInclusive the starting index. Undervalue (<0) * is promoted to 0, overvalue (>array.length) results * in an empty array. * @param endIndexExclusive elements up to endIndex-1 are present in the * returned subarray. Undervalue (< startIndex) produces * empty array, overvalue (>array.length) is demoted to * array length. * @return a new array containing the elements between * the start and end indices. * @since 2.1 */ public static long[] subarray(long[] array, int startIndexInclusive, int endIndexExclusive) { if (array == null) { return null; } if (startIndexInclusive < 0) { startIndexInclusive = 0; } if (endIndexExclusive > array.length) { endIndexExclusive = array.length; } int newSize = endIndexExclusive - startIndexInclusive; if (newSize <= 0) { return EMPTY_LONG_ARRAY; } long[] subarray = new long[newSize]; System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); return subarray; } /** *Produces a new int
array containing the elements
* between the start and end indices.
The start index is inclusive, the end index exclusive. * Null array input produces null output.
* * @param array the array * @param startIndexInclusive the starting index. Undervalue (<0) * is promoted to 0, overvalue (>array.length) results * in an empty array. * @param endIndexExclusive elements up to endIndex-1 are present in the * returned subarray. Undervalue (< startIndex) produces * empty array, overvalue (>array.length) is demoted to * array length. * @return a new array containing the elements between * the start and end indices. * @since 2.1 */ public static int[] subarray(int[] array, int startIndexInclusive, int endIndexExclusive) { if (array == null) { return null; } if (startIndexInclusive < 0) { startIndexInclusive = 0; } if (endIndexExclusive > array.length) { endIndexExclusive = array.length; } int newSize = endIndexExclusive - startIndexInclusive; if (newSize <= 0) { return EMPTY_INT_ARRAY; } int[] subarray = new int[newSize]; System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); return subarray; } /** *Produces a new short
array containing the elements
* between the start and end indices.
The start index is inclusive, the end index exclusive. * Null array input produces null output.
* * @param array the array * @param startIndexInclusive the starting index. Undervalue (<0) * is promoted to 0, overvalue (>array.length) results * in an empty array. * @param endIndexExclusive elements up to endIndex-1 are present in the * returned subarray. Undervalue (< startIndex) produces * empty array, overvalue (>array.length) is demoted to * array length. * @return a new array containing the elements between * the start and end indices. * @since 2.1 */ public static short[] subarray(short[] array, int startIndexInclusive, int endIndexExclusive) { if (array == null) { return null; } if (startIndexInclusive < 0) { startIndexInclusive = 0; } if (endIndexExclusive > array.length) { endIndexExclusive = array.length; } int newSize = endIndexExclusive - startIndexInclusive; if (newSize <= 0) { return EMPTY_SHORT_ARRAY; } short[] subarray = new short[newSize]; System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); return subarray; } /** *Produces a new char
array containing the elements
* between the start and end indices.
The start index is inclusive, the end index exclusive. * Null array input produces null output.
* * @param array the array * @param startIndexInclusive the starting index. Undervalue (<0) * is promoted to 0, overvalue (>array.length) results * in an empty array. * @param endIndexExclusive elements up to endIndex-1 are present in the * returned subarray. Undervalue (< startIndex) produces * empty array, overvalue (>array.length) is demoted to * array length. * @return a new array containing the elements between * the start and end indices. * @since 2.1 */ public static char[] subarray(char[] array, int startIndexInclusive, int endIndexExclusive) { if (array == null) { return null; } if (startIndexInclusive < 0) { startIndexInclusive = 0; } if (endIndexExclusive > array.length) { endIndexExclusive = array.length; } int newSize = endIndexExclusive - startIndexInclusive; if (newSize <= 0) { return EMPTY_CHAR_ARRAY; } char[] subarray = new char[newSize]; System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); return subarray; } /** *Produces a new byte
array containing the elements
* between the start and end indices.
The start index is inclusive, the end index exclusive. * Null array input produces null output.
* * @param array the array * @param startIndexInclusive the starting index. Undervalue (<0) * is promoted to 0, overvalue (>array.length) results * in an empty array. * @param endIndexExclusive elements up to endIndex-1 are present in the * returned subarray. Undervalue (< startIndex) produces * empty array, overvalue (>array.length) is demoted to * array length. * @return a new array containing the elements between * the start and end indices. * @since 2.1 */ public static byte[] subarray(byte[] array, int startIndexInclusive, int endIndexExclusive) { if (array == null) { return null; } if (startIndexInclusive < 0) { startIndexInclusive = 0; } if (endIndexExclusive > array.length) { endIndexExclusive = array.length; } int newSize = endIndexExclusive - startIndexInclusive; if (newSize <= 0) { return EMPTY_BYTE_ARRAY; } byte[] subarray = new byte[newSize]; System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); return subarray; } /** *Produces a new double
array containing the elements
* between the start and end indices.
The start index is inclusive, the end index exclusive. * Null array input produces null output.
* * @param array the array * @param startIndexInclusive the starting index. Undervalue (<0) * is promoted to 0, overvalue (>array.length) results * in an empty array. * @param endIndexExclusive elements up to endIndex-1 are present in the * returned subarray. Undervalue (< startIndex) produces * empty array, overvalue (>array.length) is demoted to * array length. * @return a new array containing the elements between * the start and end indices. * @since 2.1 */ public static double[] subarray(double[] array, int startIndexInclusive, int endIndexExclusive) { if (array == null) { return null; } if (startIndexInclusive < 0) { startIndexInclusive = 0; } if (endIndexExclusive > array.length) { endIndexExclusive = array.length; } int newSize = endIndexExclusive - startIndexInclusive; if (newSize <= 0) { return EMPTY_DOUBLE_ARRAY; } double[] subarray = new double[newSize]; System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); return subarray; } /** *Produces a new float
array containing the elements
* between the start and end indices.
The start index is inclusive, the end index exclusive. * Null array input produces null output.
* * @param array the array * @param startIndexInclusive the starting index. Undervalue (<0) * is promoted to 0, overvalue (>array.length) results * in an empty array. * @param endIndexExclusive elements up to endIndex-1 are present in the * returned subarray. Undervalue (< startIndex) produces * empty array, overvalue (>array.length) is demoted to * array length. * @return a new array containing the elements between * the start and end indices. * @since 2.1 */ public static float[] subarray(float[] array, int startIndexInclusive, int endIndexExclusive) { if (array == null) { return null; } if (startIndexInclusive < 0) { startIndexInclusive = 0; } if (endIndexExclusive > array.length) { endIndexExclusive = array.length; } int newSize = endIndexExclusive - startIndexInclusive; if (newSize <= 0) { return EMPTY_FLOAT_ARRAY; } float[] subarray = new float[newSize]; System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); return subarray; } /** *Produces a new boolean
array containing the elements
* between the start and end indices.
The start index is inclusive, the end index exclusive. * Null array input produces null output.
* * @param array the array * @param startIndexInclusive the starting index. Undervalue (<0) * is promoted to 0, overvalue (>array.length) results * in an empty array. * @param endIndexExclusive elements up to endIndex-1 are present in the * returned subarray. Undervalue (< startIndex) produces * empty array, overvalue (>array.length) is demoted to * array length. * @return a new array containing the elements between * the start and end indices. * @since 2.1 */ public static boolean[] subarray(boolean[] array, int startIndexInclusive, int endIndexExclusive) { if (array == null) { return null; } if (startIndexInclusive < 0) { startIndexInclusive = 0; } if (endIndexExclusive > array.length) { endIndexExclusive = array.length; } int newSize = endIndexExclusive - startIndexInclusive; if (newSize <= 0) { return EMPTY_BOOLEAN_ARRAY; } boolean[] subarray = new boolean[newSize]; System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); return subarray; } // Is same length //----------------------------------------------------------------------- /** *Checks whether two arrays are the same length, treating
* null
arrays as length 0
.
*
*
Any multi-dimensional aspects of the arrays are ignored.
* * @param array1 the first array, may benull
* @param array2 the second array, may be null
* @return true
if length of arrays matches, treating
* null
as an empty array
*/
public static boolean isSameLength(Object[] array1, Object[] array2) {
if ((array1 == null && array2 != null && array2.length > 0) ||
(array2 == null && array1 != null && array1.length > 0) ||
(array1 != null && array2 != null && array1.length != array2.length)) {
return false;
}
return true;
}
/**
* Checks whether two arrays are the same length, treating
* null
arrays as length 0
.
null
* @param array2 the second array, may be null
* @return true
if length of arrays matches, treating
* null
as an empty array
*/
public static boolean isSameLength(long[] array1, long[] array2) {
if ((array1 == null && array2 != null && array2.length > 0) ||
(array2 == null && array1 != null && array1.length > 0) ||
(array1 != null && array2 != null && array1.length != array2.length)) {
return false;
}
return true;
}
/**
* Checks whether two arrays are the same length, treating
* null
arrays as length 0
.
null
* @param array2 the second array, may be null
* @return true
if length of arrays matches, treating
* null
as an empty array
*/
public static boolean isSameLength(int[] array1, int[] array2) {
if ((array1 == null && array2 != null && array2.length > 0) ||
(array2 == null && array1 != null && array1.length > 0) ||
(array1 != null && array2 != null && array1.length != array2.length)) {
return false;
}
return true;
}
/**
* Checks whether two arrays are the same length, treating
* null
arrays as length 0
.
null
* @param array2 the second array, may be null
* @return true
if length of arrays matches, treating
* null
as an empty array
*/
public static boolean isSameLength(short[] array1, short[] array2) {
if ((array1 == null && array2 != null && array2.length > 0) ||
(array2 == null && array1 != null && array1.length > 0) ||
(array1 != null && array2 != null && array1.length != array2.length)) {
return false;
}
return true;
}
/**
* Checks whether two arrays are the same length, treating
* null
arrays as length 0
.
null
* @param array2 the second array, may be null
* @return true
if length of arrays matches, treating
* null
as an empty array
*/
public static boolean isSameLength(char[] array1, char[] array2) {
if ((array1 == null && array2 != null && array2.length > 0) ||
(array2 == null && array1 != null && array1.length > 0) ||
(array1 != null && array2 != null && array1.length != array2.length)) {
return false;
}
return true;
}
/**
* Checks whether two arrays are the same length, treating
* null
arrays as length 0
.
null
* @param array2 the second array, may be null
* @return true
if length of arrays matches, treating
* null
as an empty array
*/
public static boolean isSameLength(byte[] array1, byte[] array2) {
if ((array1 == null && array2 != null && array2.length > 0) ||
(array2 == null && array1 != null && array1.length > 0) ||
(array1 != null && array2 != null && array1.length != array2.length)) {
return false;
}
return true;
}
/**
* Checks whether two arrays are the same length, treating
* null
arrays as length 0
.
null
* @param array2 the second array, may be null
* @return true
if length of arrays matches, treating
* null
as an empty array
*/
public static boolean isSameLength(double[] array1, double[] array2) {
if ((array1 == null && array2 != null && array2.length > 0) ||
(array2 == null && array1 != null && array1.length > 0) ||
(array1 != null && array2 != null && array1.length != array2.length)) {
return false;
}
return true;
}
/**
* Checks whether two arrays are the same length, treating
* null
arrays as length 0
.
null
* @param array2 the second array, may be null
* @return true
if length of arrays matches, treating
* null
as an empty array
*/
public static boolean isSameLength(float[] array1, float[] array2) {
if ((array1 == null && array2 != null && array2.length > 0) ||
(array2 == null && array1 != null && array1.length > 0) ||
(array1 != null && array2 != null && array1.length != array2.length)) {
return false;
}
return true;
}
/**
* Checks whether two arrays are the same length, treating
* null
arrays as length 0
.
null
* @param array2 the second array, may be null
* @return true
if length of arrays matches, treating
* null
as an empty array
*/
public static boolean isSameLength(boolean[] array1, boolean[] array2) {
if ((array1 == null && array2 != null && array2.length > 0) ||
(array2 == null && array1 != null && array1.length > 0) ||
(array1 != null && array2 != null && array1.length != array2.length)) {
return false;
}
return true;
}
//-----------------------------------------------------------------------
/**
* Returns the length of the specified array.
* This method can deal with Object
arrays and with primitive arrays.
If the input array is null
, 0
is returned.
* ArrayUtils.getLength(null) = 0 * ArrayUtils.getLength([]) = 0 * ArrayUtils.getLength([null]) = 1 * ArrayUtils.getLength([true, false]) = 2 * ArrayUtils.getLength([1, 2, 3]) = 3 * ArrayUtils.getLength(["a", "b", "c"]) = 3 ** * @param array the array to retrieve the length from, may be null * @return The length of the array, or
0
if the array is null
* @throws IllegalArgumentException if the object arguement is not an array.
* @since 2.1
*/
public static int getLength(Object array) {
if (array == null) {
return 0;
}
return Array.getLength(array);
}
/**
* Checks whether two arrays are the same type taking into account * multi-dimensional arrays.
* * @param array1 the first array, must not benull
* @param array2 the second array, must not be null
* @return true
if type of arrays matches
* @throws IllegalArgumentException if either array is null
*/
public static boolean isSameType(Object array1, Object array2) {
if (array1 == null || array2 == null) {
throw new IllegalArgumentException("The Array must not be null");
}
return array1.getClass().getName().equals(array2.getClass().getName());
}
// Reverse
//-----------------------------------------------------------------------
/**
* Reverses the order of the given array.
* *There is no special handling for multi-dimensional arrays.
* *This method does nothing for a null
input array.
null
*/
public static void reverse(Object[] array) {
if (array == null) {
return;
}
int i = 0;
int j = array.length - 1;
Object tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
}
/**
* Reverses the order of the given array.
* *This method does nothing for a null
input array.
null
*/
public static void reverse(long[] array) {
if (array == null) {
return;
}
int i = 0;
int j = array.length - 1;
long tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
}
/**
* Reverses the order of the given array.
* *This method does nothing for a null
input array.
null
*/
public static void reverse(int[] array) {
if (array == null) {
return;
}
int i = 0;
int j = array.length - 1;
int tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
}
/**
* Reverses the order of the given array.
* *This method does nothing for a null
input array.
null
*/
public static void reverse(short[] array) {
if (array == null) {
return;
}
int i = 0;
int j = array.length - 1;
short tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
}
/**
* Reverses the order of the given array.
* *This method does nothing for a null
input array.
null
*/
public static void reverse(char[] array) {
if (array == null) {
return;
}
int i = 0;
int j = array.length - 1;
char tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
}
/**
* Reverses the order of the given array.
* *This method does nothing for a null
input array.
null
*/
public static void reverse(byte[] array) {
if (array == null) {
return;
}
int i = 0;
int j = array.length - 1;
byte tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
}
/**
* Reverses the order of the given array.
* *This method does nothing for a null
input array.
null
*/
public static void reverse(double[] array) {
if (array == null) {
return;
}
int i = 0;
int j = array.length - 1;
double tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
}
/**
* Reverses the order of the given array.
* *This method does nothing for a null
input array.
null
*/
public static void reverse(float[] array) {
if (array == null) {
return;
}
int i = 0;
int j = array.length - 1;
float tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
}
/**
* Reverses the order of the given array.
* *This method does nothing for a null
input array.
null
*/
public static void reverse(boolean[] array) {
if (array == null) {
return;
}
int i = 0;
int j = array.length - 1;
boolean tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
}
// IndexOf search
// ----------------------------------------------------------------------
// Object IndexOf
//-----------------------------------------------------------------------
/**
* Finds the index of the given object in the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param objectToFind the object to find, may be null
* @return the index of the object within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(Object[] array, Object objectToFind) {
return indexOf(array, objectToFind, 0);
}
/**
* Finds the index of the given object in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex is treated as zero. A startIndex larger than the array
* length will return {@link #INDEX_NOT_FOUND} (-1
).
null
* @param objectToFind the object to find, may be null
* @param startIndex the index to start searching at
* @return the index of the object within the array starting at the index,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(Object[] array, Object objectToFind, int startIndex) {
if (array == null) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
startIndex = 0;
}
if (objectToFind == null) {
for (int i = startIndex; i < array.length; i++) {
if (array[i] == null) {
return i;
}
}
} else if (array.getClass().getComponentType().isInstance(objectToFind)) {
for (int i = startIndex; i < array.length; i++) {
if (objectToFind.equals(array[i])) {
return i;
}
}
}
return INDEX_NOT_FOUND;
}
/**
* Finds the last index of the given object within the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param objectToFind the object to find, may be null
* @return the last index of the object within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(Object[] array, Object objectToFind) {
return lastIndexOf(array, objectToFind, Integer.MAX_VALUE);
}
/**
* Finds the last index of the given object in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex will return {@link #INDEX_NOT_FOUND} (-1
). A startIndex larger than
* the array length will search from the end of the array.
null
* @param objectToFind the object to find, may be null
* @param startIndex the start index to travers backwards from
* @return the last index of the object within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(Object[] array, Object objectToFind, int startIndex) {
if (array == null) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
return INDEX_NOT_FOUND;
} else if (startIndex >= array.length) {
startIndex = array.length - 1;
}
if (objectToFind == null) {
for (int i = startIndex; i >= 0; i--) {
if (array[i] == null) {
return i;
}
}
} else if (array.getClass().getComponentType().isInstance(objectToFind)) {
for (int i = startIndex; i >= 0; i--) {
if (objectToFind.equals(array[i])) {
return i;
}
}
}
return INDEX_NOT_FOUND;
}
/**
* Checks if the object is in the given array.
* *The method returns false
if a null
array is passed in.
true
if the array contains the object
*/
public static boolean contains(Object[] array, Object objectToFind) {
return indexOf(array, objectToFind) != INDEX_NOT_FOUND;
}
// long IndexOf
//-----------------------------------------------------------------------
/**
* Finds the index of the given value in the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the value to find
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(long[] array, long valueToFind) {
return indexOf(array, valueToFind, 0);
}
/**
* Finds the index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex is treated as zero. A startIndex larger than the array
* length will return {@link #INDEX_NOT_FOUND} (-1
).
null
* @param valueToFind the value to find
* @param startIndex the index to start searching at
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(long[] array, long valueToFind, int startIndex) {
if (array == null) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
startIndex = 0;
}
for (int i = startIndex; i < array.length; i++) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Finds the last index of the given value within the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the object to find
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(long[] array, long valueToFind) {
return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
}
/**
* Finds the last index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex will return {@link #INDEX_NOT_FOUND} (-1
). A startIndex larger than the
* array length will search from the end of the array.
null
* @param valueToFind the value to find
* @param startIndex the start index to travers backwards from
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(long[] array, long valueToFind, int startIndex) {
if (array == null) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
return INDEX_NOT_FOUND;
} else if (startIndex >= array.length) {
startIndex = array.length - 1;
}
for (int i = startIndex; i >= 0; i--) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Checks if the value is in the given array.
* *The method returns false
if a null
array is passed in.
true
if the array contains the object
*/
public static boolean contains(long[] array, long valueToFind) {
return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
}
// int IndexOf
//-----------------------------------------------------------------------
/**
* Finds the index of the given value in the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the value to find
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(int[] array, int valueToFind) {
return indexOf(array, valueToFind, 0);
}
/**
* Finds the index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex is treated as zero. A startIndex larger than the array
* length will return {@link #INDEX_NOT_FOUND} (-1
).
null
* @param valueToFind the value to find
* @param startIndex the index to start searching at
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(int[] array, int valueToFind, int startIndex) {
if (array == null) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
startIndex = 0;
}
for (int i = startIndex; i < array.length; i++) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Finds the last index of the given value within the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the object to find
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(int[] array, int valueToFind) {
return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
}
/**
* Finds the last index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex will return {@link #INDEX_NOT_FOUND} (-1
). A startIndex larger than the
* array length will search from the end of the array.
null
* @param valueToFind the value to find
* @param startIndex the start index to travers backwards from
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(int[] array, int valueToFind, int startIndex) {
if (array == null) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
return INDEX_NOT_FOUND;
} else if (startIndex >= array.length) {
startIndex = array.length - 1;
}
for (int i = startIndex; i >= 0; i--) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Checks if the value is in the given array.
* *The method returns false
if a null
array is passed in.
true
if the array contains the object
*/
public static boolean contains(int[] array, int valueToFind) {
return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
}
// short IndexOf
//-----------------------------------------------------------------------
/**
* Finds the index of the given value in the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the value to find
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(short[] array, short valueToFind) {
return indexOf(array, valueToFind, 0);
}
/**
* Finds the index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex is treated as zero. A startIndex larger than the array
* length will return {@link #INDEX_NOT_FOUND} (-1
).
null
* @param valueToFind the value to find
* @param startIndex the index to start searching at
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(short[] array, short valueToFind, int startIndex) {
if (array == null) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
startIndex = 0;
}
for (int i = startIndex; i < array.length; i++) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Finds the last index of the given value within the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the object to find
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(short[] array, short valueToFind) {
return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
}
/**
* Finds the last index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex will return {@link #INDEX_NOT_FOUND} (-1
). A startIndex larger than the
* array length will search from the end of the array.
null
* @param valueToFind the value to find
* @param startIndex the start index to travers backwards from
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(short[] array, short valueToFind, int startIndex) {
if (array == null) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
return INDEX_NOT_FOUND;
} else if (startIndex >= array.length) {
startIndex = array.length - 1;
}
for (int i = startIndex; i >= 0; i--) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Checks if the value is in the given array.
* *The method returns false
if a null
array is passed in.
true
if the array contains the object
*/
public static boolean contains(short[] array, short valueToFind) {
return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
}
// char IndexOf
//-----------------------------------------------------------------------
/**
* Finds the index of the given value in the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the value to find
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
* @since 2.1
*/
public static int indexOf(char[] array, char valueToFind) {
return indexOf(array, valueToFind, 0);
}
/**
* Finds the index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex is treated as zero. A startIndex larger than the array
* length will return {@link #INDEX_NOT_FOUND} (-1
).
null
* @param valueToFind the value to find
* @param startIndex the index to start searching at
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
* @since 2.1
*/
public static int indexOf(char[] array, char valueToFind, int startIndex) {
if (array == null) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
startIndex = 0;
}
for (int i = startIndex; i < array.length; i++) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Finds the last index of the given value within the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the object to find
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
* @since 2.1
*/
public static int lastIndexOf(char[] array, char valueToFind) {
return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
}
/**
* Finds the last index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex will return {@link #INDEX_NOT_FOUND} (-1
). A startIndex larger than the
* array length will search from the end of the array.
null
* @param valueToFind the value to find
* @param startIndex the start index to travers backwards from
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
* @since 2.1
*/
public static int lastIndexOf(char[] array, char valueToFind, int startIndex) {
if (array == null) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
return INDEX_NOT_FOUND;
} else if (startIndex >= array.length) {
startIndex = array.length - 1;
}
for (int i = startIndex; i >= 0; i--) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Checks if the value is in the given array.
* *The method returns false
if a null
array is passed in.
true
if the array contains the object
* @since 2.1
*/
public static boolean contains(char[] array, char valueToFind) {
return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
}
// byte IndexOf
//-----------------------------------------------------------------------
/**
* Finds the index of the given value in the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the value to find
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(byte[] array, byte valueToFind) {
return indexOf(array, valueToFind, 0);
}
/**
* Finds the index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex is treated as zero. A startIndex larger than the array
* length will return {@link #INDEX_NOT_FOUND} (-1
).
null
* @param valueToFind the value to find
* @param startIndex the index to start searching at
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(byte[] array, byte valueToFind, int startIndex) {
if (array == null) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
startIndex = 0;
}
for (int i = startIndex; i < array.length; i++) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Finds the last index of the given value within the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the object to find
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(byte[] array, byte valueToFind) {
return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
}
/**
* Finds the last index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex will return {@link #INDEX_NOT_FOUND} (-1
). A startIndex larger than the
* array length will search from the end of the array.
null
* @param valueToFind the value to find
* @param startIndex the start index to travers backwards from
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(byte[] array, byte valueToFind, int startIndex) {
if (array == null) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
return INDEX_NOT_FOUND;
} else if (startIndex >= array.length) {
startIndex = array.length - 1;
}
for (int i = startIndex; i >= 0; i--) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Checks if the value is in the given array.
* *The method returns false
if a null
array is passed in.
true
if the array contains the object
*/
public static boolean contains(byte[] array, byte valueToFind) {
return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
}
// double IndexOf
//-----------------------------------------------------------------------
/**
* Finds the index of the given value in the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the value to find
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(double[] array, double valueToFind) {
return indexOf(array, valueToFind, 0);
}
/**
* Finds the index of the given value within a given tolerance in the array. * This method will return the index of the first value which falls between the region * defined by valueToFind - tolerance and valueToFind + tolerance.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the value to find
* @param tolerance tolerance of the search
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(double[] array, double valueToFind, double tolerance) {
return indexOf(array, valueToFind, 0, tolerance);
}
/**
* Finds the index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex is treated as zero. A startIndex larger than the array
* length will return {@link #INDEX_NOT_FOUND} (-1
).
null
* @param valueToFind the value to find
* @param startIndex the index to start searching at
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(double[] array, double valueToFind, int startIndex) {
if (ArrayUtils.isEmpty(array)) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
startIndex = 0;
}
for (int i = startIndex; i < array.length; i++) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Finds the index of the given value in the array starting at the given index. * This method will return the index of the first value which falls between the region * defined by valueToFind - tolerance and valueToFind + tolerance.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex is treated as zero. A startIndex larger than the array
* length will return {@link #INDEX_NOT_FOUND} (-1
).
null
* @param valueToFind the value to find
* @param startIndex the index to start searching at
* @param tolerance tolerance of the search
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(double[] array, double valueToFind, int startIndex, double tolerance) {
if (ArrayUtils.isEmpty(array)) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
startIndex = 0;
}
double min = valueToFind - tolerance;
double max = valueToFind + tolerance;
for (int i = startIndex; i < array.length; i++) {
if (array[i] >= min && array[i] <= max) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Finds the last index of the given value within the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the object to find
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(double[] array, double valueToFind) {
return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
}
/**
* Finds the last index of the given value within a given tolerance in the array. * This method will return the index of the last value which falls between the region * defined by valueToFind - tolerance and valueToFind + tolerance.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the value to find
* @param tolerance tolerance of the search
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(double[] array, double valueToFind, double tolerance) {
return lastIndexOf(array, valueToFind, Integer.MAX_VALUE, tolerance);
}
/**
* Finds the last index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex will return {@link #INDEX_NOT_FOUND} (-1
). A startIndex larger than the
* array length will search from the end of the array.
null
* @param valueToFind the value to find
* @param startIndex the start index to travers backwards from
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(double[] array, double valueToFind, int startIndex) {
if (ArrayUtils.isEmpty(array)) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
return INDEX_NOT_FOUND;
} else if (startIndex >= array.length) {
startIndex = array.length - 1;
}
for (int i = startIndex; i >= 0; i--) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Finds the last index of the given value in the array starting at the given index. * This method will return the index of the last value which falls between the region * defined by valueToFind - tolerance and valueToFind + tolerance.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex will return {@link #INDEX_NOT_FOUND} (-1
). A startIndex larger than the
* array length will search from the end of the array.
null
* @param valueToFind the value to find
* @param startIndex the start index to travers backwards from
* @param tolerance search for value within plus/minus this amount
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(double[] array, double valueToFind, int startIndex, double tolerance) {
if (ArrayUtils.isEmpty(array)) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
return INDEX_NOT_FOUND;
} else if (startIndex >= array.length) {
startIndex = array.length - 1;
}
double min = valueToFind - tolerance;
double max = valueToFind + tolerance;
for (int i = startIndex; i >= 0; i--) {
if (array[i] >= min && array[i] <= max) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Checks if the value is in the given array.
* *The method returns false
if a null
array is passed in.
true
if the array contains the object
*/
public static boolean contains(double[] array, double valueToFind) {
return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
}
/**
* Checks if a value falling within the given tolerance is in the * given array. If the array contains a value within the inclusive range * defined by (value - tolerance) to (value + tolerance).
* *The method returns false
if a null
array
* is passed in.
Finds the index of the given value in the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the value to find
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(float[] array, float valueToFind) {
return indexOf(array, valueToFind, 0);
}
/**
* Finds the index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex is treated as zero. A startIndex larger than the array
* length will return {@link #INDEX_NOT_FOUND} (-1
).
null
* @param valueToFind the value to find
* @param startIndex the index to start searching at
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(float[] array, float valueToFind, int startIndex) {
if (ArrayUtils.isEmpty(array)) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
startIndex = 0;
}
for (int i = startIndex; i < array.length; i++) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Finds the last index of the given value within the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the object to find
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(float[] array, float valueToFind) {
return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
}
/**
* Finds the last index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex will return {@link #INDEX_NOT_FOUND} (-1
). A startIndex larger than the
* array length will search from the end of the array.
null
* @param valueToFind the value to find
* @param startIndex the start index to travers backwards from
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(float[] array, float valueToFind, int startIndex) {
if (ArrayUtils.isEmpty(array)) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
return INDEX_NOT_FOUND;
} else if (startIndex >= array.length) {
startIndex = array.length - 1;
}
for (int i = startIndex; i >= 0; i--) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Checks if the value is in the given array.
* *The method returns false
if a null
array is passed in.
true
if the array contains the object
*/
public static boolean contains(float[] array, float valueToFind) {
return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
}
// boolean IndexOf
//-----------------------------------------------------------------------
/**
* Finds the index of the given value in the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
null
* @param valueToFind the value to find
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int indexOf(boolean[] array, boolean valueToFind) {
return indexOf(array, valueToFind, 0);
}
/**
* Finds the index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex is treated as zero. A startIndex larger than the array
* length will return {@link #INDEX_NOT_FOUND} (-1
).
null
* @param valueToFind the value to find
* @param startIndex the index to start searching at
* @return the index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
* array input
*/
public static int indexOf(boolean[] array, boolean valueToFind, int startIndex) {
if (ArrayUtils.isEmpty(array)) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
startIndex = 0;
}
for (int i = startIndex; i < array.length; i++) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Finds the last index of the given value within the array.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) if
* null
array input.
null
* @param valueToFind the object to find
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(boolean[] array, boolean valueToFind) {
return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
}
/**
* Finds the last index of the given value in the array starting at the given index.
* *This method returns {@link #INDEX_NOT_FOUND} (-1
) for a null
input array.
A negative startIndex will return {@link #INDEX_NOT_FOUND} (-1
). A startIndex larger than
* the array length will search from the end of the array.
null
* @param valueToFind the value to find
* @param startIndex the start index to travers backwards from
* @return the last index of the value within the array,
* {@link #INDEX_NOT_FOUND} (-1
) if not found or null
array input
*/
public static int lastIndexOf(boolean[] array, boolean valueToFind, int startIndex) {
if (ArrayUtils.isEmpty(array)) {
return INDEX_NOT_FOUND;
}
if (startIndex < 0) {
return INDEX_NOT_FOUND;
} else if (startIndex >= array.length) {
startIndex = array.length - 1;
}
for (int i = startIndex; i >= 0; i--) {
if (valueToFind == array[i]) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Checks if the value is in the given array.
* *The method returns false
if a null
array is passed in.
true
if the array contains the object
*/
public static boolean contains(boolean[] array, boolean valueToFind) {
return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
}
// Primitive/Object array converters
// ----------------------------------------------------------------------
// Character array converters
// ----------------------------------------------------------------------
/**
* Converts an array of object Characters to primitives.
* *This method returns null
for a null
input array.
Character
array, may be null
* @return a char
array, null
if null array input
* @throws NullPointerException if array content is null
*/
public static char[] toPrimitive(Character[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_CHAR_ARRAY;
}
final char[] result = new char[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i].charValue();
}
return result;
}
/**
* Converts an array of object Character to primitives handling null
.
This method returns null
for a null
input array.
Character
array, may be null
* @param valueForNull the value to insert if null
found
* @return a char
array, null
if null array input
*/
public static char[] toPrimitive(Character[] array, char valueForNull) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_CHAR_ARRAY;
}
final char[] result = new char[array.length];
for (int i = 0; i < array.length; i++) {
Character b = array[i];
result[i] = (b == null ? valueForNull : b.charValue());
}
return result;
}
/**
* Converts an array of primitive chars to objects.
* *This method returns null
for a null
input array.
char
array
* @return a Character
array, null
if null array input
*/
public static Character[] toObject(char[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_CHARACTER_OBJECT_ARRAY;
}
final Character[] result = new Character[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = new Character(array[i]);
}
return result;
}
// Long array converters
// ----------------------------------------------------------------------
/**
* Converts an array of object Longs to primitives.
* *This method returns null
for a null
input array.
Long
array, may be null
* @return a long
array, null
if null array input
* @throws NullPointerException if array content is null
*/
public static long[] toPrimitive(Long[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_LONG_ARRAY;
}
final long[] result = new long[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i].longValue();
}
return result;
}
/**
* Converts an array of object Long to primitives handling null
.
This method returns null
for a null
input array.
Long
array, may be null
* @param valueForNull the value to insert if null
found
* @return a long
array, null
if null array input
*/
public static long[] toPrimitive(Long[] array, long valueForNull) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_LONG_ARRAY;
}
final long[] result = new long[array.length];
for (int i = 0; i < array.length; i++) {
Long b = array[i];
result[i] = (b == null ? valueForNull : b.longValue());
}
return result;
}
/**
* Converts an array of primitive longs to objects.
* *This method returns null
for a null
input array.
long
array
* @return a Long
array, null
if null array input
*/
public static Long[] toObject(long[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_LONG_OBJECT_ARRAY;
}
final Long[] result = new Long[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = new Long(array[i]);
}
return result;
}
// Int array converters
// ----------------------------------------------------------------------
/**
* Converts an array of object Integers to primitives.
* *This method returns null
for a null
input array.
Integer
array, may be null
* @return an int
array, null
if null array input
* @throws NullPointerException if array content is null
*/
public static int[] toPrimitive(Integer[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_INT_ARRAY;
}
final int[] result = new int[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i].intValue();
}
return result;
}
/**
* Converts an array of object Integer to primitives handling null
.
This method returns null
for a null
input array.
Integer
array, may be null
* @param valueForNull the value to insert if null
found
* @return an int
array, null
if null array input
*/
public static int[] toPrimitive(Integer[] array, int valueForNull) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_INT_ARRAY;
}
final int[] result = new int[array.length];
for (int i = 0; i < array.length; i++) {
Integer b = array[i];
result[i] = (b == null ? valueForNull : b.intValue());
}
return result;
}
/**
* Converts an array of primitive ints to objects.
* *This method returns null
for a null
input array.
int
array
* @return an Integer
array, null
if null array input
*/
public static Integer[] toObject(int[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_INTEGER_OBJECT_ARRAY;
}
final Integer[] result = new Integer[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = new Integer(array[i]);
}
return result;
}
// Short array converters
// ----------------------------------------------------------------------
/**
* Converts an array of object Shorts to primitives.
* *This method returns null
for a null
input array.
Short
array, may be null
* @return a byte
array, null
if null array input
* @throws NullPointerException if array content is null
*/
public static short[] toPrimitive(Short[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_SHORT_ARRAY;
}
final short[] result = new short[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i].shortValue();
}
return result;
}
/**
* Converts an array of object Short to primitives handling null
.
This method returns null
for a null
input array.
Short
array, may be null
* @param valueForNull the value to insert if null
found
* @return a byte
array, null
if null array input
*/
public static short[] toPrimitive(Short[] array, short valueForNull) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_SHORT_ARRAY;
}
final short[] result = new short[array.length];
for (int i = 0; i < array.length; i++) {
Short b = array[i];
result[i] = (b == null ? valueForNull : b.shortValue());
}
return result;
}
/**
* Converts an array of primitive shorts to objects.
* *This method returns null
for a null
input array.
short
array
* @return a Short
array, null
if null array input
*/
public static Short[] toObject(short[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_SHORT_OBJECT_ARRAY;
}
final Short[] result = new Short[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = new Short(array[i]);
}
return result;
}
// Byte array converters
// ----------------------------------------------------------------------
/**
* Converts an array of object Bytes to primitives.
* *This method returns null
for a null
input array.
Byte
array, may be null
* @return a byte
array, null
if null array input
* @throws NullPointerException if array content is null
*/
public static byte[] toPrimitive(Byte[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_BYTE_ARRAY;
}
final byte[] result = new byte[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i].byteValue();
}
return result;
}
/**
* Converts an array of object Bytes to primitives handling null
.
This method returns null
for a null
input array.
Byte
array, may be null
* @param valueForNull the value to insert if null
found
* @return a byte
array, null
if null array input
*/
public static byte[] toPrimitive(Byte[] array, byte valueForNull) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_BYTE_ARRAY;
}
final byte[] result = new byte[array.length];
for (int i = 0; i < array.length; i++) {
Byte b = array[i];
result[i] = (b == null ? valueForNull : b.byteValue());
}
return result;
}
/**
* Converts an array of primitive bytes to objects.
* *This method returns null
for a null
input array.
byte
array
* @return a Byte
array, null
if null array input
*/
public static Byte[] toObject(byte[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_BYTE_OBJECT_ARRAY;
}
final Byte[] result = new Byte[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = new Byte(array[i]);
}
return result;
}
// Double array converters
// ----------------------------------------------------------------------
/**
* Converts an array of object Doubles to primitives.
* *This method returns null
for a null
input array.
Double
array, may be null
* @return a double
array, null
if null array input
* @throws NullPointerException if array content is null
*/
public static double[] toPrimitive(Double[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_DOUBLE_ARRAY;
}
final double[] result = new double[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i].doubleValue();
}
return result;
}
/**
* Converts an array of object Doubles to primitives handling null
.
This method returns null
for a null
input array.
Double
array, may be null
* @param valueForNull the value to insert if null
found
* @return a double
array, null
if null array input
*/
public static double[] toPrimitive(Double[] array, double valueForNull) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_DOUBLE_ARRAY;
}
final double[] result = new double[array.length];
for (int i = 0; i < array.length; i++) {
Double b = array[i];
result[i] = (b == null ? valueForNull : b.doubleValue());
}
return result;
}
/**
* Converts an array of primitive doubles to objects.
* *This method returns null
for a null
input array.
double
array
* @return a Double
array, null
if null array input
*/
public static Double[] toObject(double[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_DOUBLE_OBJECT_ARRAY;
}
final Double[] result = new Double[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = new Double(array[i]);
}
return result;
}
// Float array converters
// ----------------------------------------------------------------------
/**
* Converts an array of object Floats to primitives.
* *This method returns null
for a null
input array.
Float
array, may be null
* @return a float
array, null
if null array input
* @throws NullPointerException if array content is null
*/
public static float[] toPrimitive(Float[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_FLOAT_ARRAY;
}
final float[] result = new float[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i].floatValue();
}
return result;
}
/**
* Converts an array of object Floats to primitives handling null
.
This method returns null
for a null
input array.
Float
array, may be null
* @param valueForNull the value to insert if null
found
* @return a float
array, null
if null array input
*/
public static float[] toPrimitive(Float[] array, float valueForNull) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_FLOAT_ARRAY;
}
final float[] result = new float[array.length];
for (int i = 0; i < array.length; i++) {
Float b = array[i];
result[i] = (b == null ? valueForNull : b.floatValue());
}
return result;
}
/**
* Converts an array of primitive floats to objects.
* *This method returns null
for a null
input array.
float
array
* @return a Float
array, null
if null array input
*/
public static Float[] toObject(float[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_FLOAT_OBJECT_ARRAY;
}
final Float[] result = new Float[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = new Float(array[i]);
}
return result;
}
// Boolean array converters
// ----------------------------------------------------------------------
/**
* Converts an array of object Booleans to primitives.
* *This method returns null
for a null
input array.
Boolean
array, may be null
* @return a boolean
array, null
if null array input
* @throws NullPointerException if array content is null
*/
public static boolean[] toPrimitive(Boolean[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_BOOLEAN_ARRAY;
}
final boolean[] result = new boolean[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i].booleanValue();
}
return result;
}
/**
* Converts an array of object Booleans to primitives handling null
.
This method returns null
for a null
input array.
Boolean
array, may be null
* @param valueForNull the value to insert if null
found
* @return a boolean
array, null
if null array input
*/
public static boolean[] toPrimitive(Boolean[] array, boolean valueForNull) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_BOOLEAN_ARRAY;
}
final boolean[] result = new boolean[array.length];
for (int i = 0; i < array.length; i++) {
Boolean b = array[i];
result[i] = (b == null ? valueForNull : b.booleanValue());
}
return result;
}
/**
* Converts an array of primitive booleans to objects.
* *This method returns null
for a null
input array.
boolean
array
* @return a Boolean
array, null
if null array input
*/
public static Boolean[] toObject(boolean[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_BOOLEAN_OBJECT_ARRAY;
}
final Boolean[] result = new Boolean[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = (array[i] ? Boolean.TRUE : Boolean.FALSE);
}
return result;
}
// ----------------------------------------------------------------------
/**
* Checks if an array of Objects is empty or null
.
true
if the array is empty or null
* @since 2.1
*/
public static boolean isEmpty(Object[] array) {
return array == null || array.length == 0;
}
/**
* Checks if an array of primitive longs is empty or null
.
true
if the array is empty or null
* @since 2.1
*/
public static boolean isEmpty(long[] array) {
return array == null || array.length == 0;
}
/**
* Checks if an array of primitive ints is empty or null
.
true
if the array is empty or null
* @since 2.1
*/
public static boolean isEmpty(int[] array) {
return array == null || array.length == 0;
}
/**
* Checks if an array of primitive shorts is empty or null
.
true
if the array is empty or null
* @since 2.1
*/
public static boolean isEmpty(short[] array) {
return array == null || array.length == 0;
}
/**
* Checks if an array of primitive chars is empty or null
.
true
if the array is empty or null
* @since 2.1
*/
public static boolean isEmpty(char[] array) {
return array == null || array.length == 0;
}
/**
* Checks if an array of primitive bytes is empty or null
.
true
if the array is empty or null
* @since 2.1
*/
public static boolean isEmpty(byte[] array) {
return array == null || array.length == 0;
}
/**
* Checks if an array of primitive doubles is empty or null
.
true
if the array is empty or null
* @since 2.1
*/
public static boolean isEmpty(double[] array) {
return array == null || array.length == 0;
}
/**
* Checks if an array of primitive floats is empty or null
.
true
if the array is empty or null
* @since 2.1
*/
public static boolean isEmpty(float[] array) {
return array == null || array.length == 0;
}
/**
* Checks if an array of primitive booleans is empty or null
.
true
if the array is empty or null
* @since 2.1
*/
public static boolean isEmpty(boolean[] array) {
return array == null || array.length == 0;
}
// ----------------------------------------------------------------------
/**
* Checks if an array of Objects is not empty or not null
.
true
if the array is not empty or not null
* @since 2.5
*/
public static boolean isNotEmpty(Object[] array) {
return (array != null && array.length != 0);
}
/**
* Checks if an array of primitive longs is not empty or not null
.
true
if the array is not empty or not null
* @since 2.5
*/
public static boolean isNotEmpty(long[] array) {
return (array != null && array.length != 0);
}
/**
* Checks if an array of primitive ints is not empty or not null
.
true
if the array is not empty or not null
* @since 2.5
*/
public static boolean isNotEmpty(int[] array) {
return (array != null && array.length != 0);
}
/**
* Checks if an array of primitive shorts is not empty or not null
.
true
if the array is not empty or not null
* @since 2.5
*/
public static boolean isNotEmpty(short[] array) {
return (array != null && array.length != 0);
}
/**
* Checks if an array of primitive chars is not empty or not null
.
true
if the array is not empty or not null
* @since 2.5
*/
public static boolean isNotEmpty(char[] array) {
return (array != null && array.length != 0);
}
/**
* Checks if an array of primitive bytes is not empty or not null
.
true
if the array is not empty or not null
* @since 2.5
*/
public static boolean isNotEmpty(byte[] array) {
return (array != null && array.length != 0);
}
/**
* Checks if an array of primitive doubles is not empty or not null
.
true
if the array is not empty or not null
* @since 2.5
*/
public static boolean isNotEmpty(double[] array) {
return (array != null && array.length != 0);
}
/**
* Checks if an array of primitive floats is not empty or not null
.
true
if the array is not empty or not null
* @since 2.5
*/
public static boolean isNotEmpty(float[] array) {
return (array != null && array.length != 0);
}
/**
* Checks if an array of primitive booleans is not empty or not null
.
true
if the array is not empty or not null
* @since 2.5
*/
public static boolean isNotEmpty(boolean[] array) {
return (array != null && array.length != 0);
}
/**
* Adds all the elements of the given arrays into a new array.
*The new array contains all of the element of array1
followed
* by all of the elements array2
. When an array is returned, it is always
* a new array.
* ArrayUtils.addAll(null, null) = null * ArrayUtils.addAll(array1, null) = cloned copy of array1 * ArrayUtils.addAll(null, array2) = cloned copy of array2 * ArrayUtils.addAll([], []) = [] * ArrayUtils.addAll([null], [null]) = [null, null] * ArrayUtils.addAll(["a", "b", "c"], ["1", "2", "3"]) = ["a", "b", "c", "1", "2", "3"] ** * @param array1 the first array whose elements are added to the new array, may be
null
* @param array2 the second array whose elements are added to the new array, may be null
* @return The new array, null
if both arrays are null
.
* The type of the new array is the type of the first array,
* unless the first array is null, in which case the type is the same as the second array.
* @since 2.1
* @throws IllegalArgumentException if the array types are incompatible
*/
public static Object[] addAll(Object[] array1, Object[] array2) {
if (array1 == null) {
return clone(array2);
} else if (array2 == null) {
return clone(array1);
}
Object[] joinedArray = (Object[]) Array.newInstance(array1.getClass().getComponentType(),
array1.length + array2.length);
System.arraycopy(array1, 0, joinedArray, 0, array1.length);
try {
System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
} catch (ArrayStoreException ase) {
// Check if problem was due to incompatible types
/*
* We do this here, rather than before the copy because:
* - it would be a wasted check most of the time
* - safer, in case check turns out to be too strict
*/
final Class type1 = array1.getClass().getComponentType();
final Class type2 = array2.getClass().getComponentType();
if (!type1.isAssignableFrom(type2)){
throw new IllegalArgumentException("Cannot store "+type2.getName()+" in an array of "+type1.getName());
}
throw ase; // No, so rethrow original
}
return joinedArray;
}
/**
* Adds all the elements of the given arrays into a new array.
*The new array contains all of the element of array1
followed
* by all of the elements array2
. When an array is returned, it is always
* a new array.
* ArrayUtils.addAll(array1, null) = cloned copy of array1 * ArrayUtils.addAll(null, array2) = cloned copy of array2 * ArrayUtils.addAll([], []) = [] ** * @param array1 the first array whose elements are added to the new array. * @param array2 the second array whose elements are added to the new array. * @return The new boolean[] array. * @since 2.1 */ public static boolean[] addAll(boolean[] array1, boolean[] array2) { if (array1 == null) { return clone(array2); } else if (array2 == null) { return clone(array1); } boolean[] joinedArray = new boolean[array1.length + array2.length]; System.arraycopy(array1, 0, joinedArray, 0, array1.length); System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); return joinedArray; } /** *
Adds all the elements of the given arrays into a new array.
*The new array contains all of the element of array1
followed
* by all of the elements array2
. When an array is returned, it is always
* a new array.
* ArrayUtils.addAll(array1, null) = cloned copy of array1 * ArrayUtils.addAll(null, array2) = cloned copy of array2 * ArrayUtils.addAll([], []) = [] ** * @param array1 the first array whose elements are added to the new array. * @param array2 the second array whose elements are added to the new array. * @return The new char[] array. * @since 2.1 */ public static char[] addAll(char[] array1, char[] array2) { if (array1 == null) { return clone(array2); } else if (array2 == null) { return clone(array1); } char[] joinedArray = new char[array1.length + array2.length]; System.arraycopy(array1, 0, joinedArray, 0, array1.length); System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); return joinedArray; } /** *
Adds all the elements of the given arrays into a new array.
*The new array contains all of the element of array1
followed
* by all of the elements array2
. When an array is returned, it is always
* a new array.
* ArrayUtils.addAll(array1, null) = cloned copy of array1 * ArrayUtils.addAll(null, array2) = cloned copy of array2 * ArrayUtils.addAll([], []) = [] ** * @param array1 the first array whose elements are added to the new array. * @param array2 the second array whose elements are added to the new array. * @return The new byte[] array. * @since 2.1 */ public static byte[] addAll(byte[] array1, byte[] array2) { if (array1 == null) { return clone(array2); } else if (array2 == null) { return clone(array1); } byte[] joinedArray = new byte[array1.length + array2.length]; System.arraycopy(array1, 0, joinedArray, 0, array1.length); System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); return joinedArray; } /** *
Adds all the elements of the given arrays into a new array.
*The new array contains all of the element of array1
followed
* by all of the elements array2
. When an array is returned, it is always
* a new array.
* ArrayUtils.addAll(array1, null) = cloned copy of array1 * ArrayUtils.addAll(null, array2) = cloned copy of array2 * ArrayUtils.addAll([], []) = [] ** * @param array1 the first array whose elements are added to the new array. * @param array2 the second array whose elements are added to the new array. * @return The new short[] array. * @since 2.1 */ public static short[] addAll(short[] array1, short[] array2) { if (array1 == null) { return clone(array2); } else if (array2 == null) { return clone(array1); } short[] joinedArray = new short[array1.length + array2.length]; System.arraycopy(array1, 0, joinedArray, 0, array1.length); System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); return joinedArray; } /** *
Adds all the elements of the given arrays into a new array.
*The new array contains all of the element of array1
followed
* by all of the elements array2
. When an array is returned, it is always
* a new array.
* ArrayUtils.addAll(array1, null) = cloned copy of array1 * ArrayUtils.addAll(null, array2) = cloned copy of array2 * ArrayUtils.addAll([], []) = [] ** * @param array1 the first array whose elements are added to the new array. * @param array2 the second array whose elements are added to the new array. * @return The new int[] array. * @since 2.1 */ public static int[] addAll(int[] array1, int[] array2) { if (array1 == null) { return clone(array2); } else if (array2 == null) { return clone(array1); } int[] joinedArray = new int[array1.length + array2.length]; System.arraycopy(array1, 0, joinedArray, 0, array1.length); System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); return joinedArray; } /** *
Adds all the elements of the given arrays into a new array.
*The new array contains all of the element of array1
followed
* by all of the elements array2
. When an array is returned, it is always
* a new array.
* ArrayUtils.addAll(array1, null) = cloned copy of array1 * ArrayUtils.addAll(null, array2) = cloned copy of array2 * ArrayUtils.addAll([], []) = [] ** * @param array1 the first array whose elements are added to the new array. * @param array2 the second array whose elements are added to the new array. * @return The new long[] array. * @since 2.1 */ public static long[] addAll(long[] array1, long[] array2) { if (array1 == null) { return clone(array2); } else if (array2 == null) { return clone(array1); } long[] joinedArray = new long[array1.length + array2.length]; System.arraycopy(array1, 0, joinedArray, 0, array1.length); System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); return joinedArray; } /** *
Adds all the elements of the given arrays into a new array.
*The new array contains all of the element of array1
followed
* by all of the elements array2
. When an array is returned, it is always
* a new array.
* ArrayUtils.addAll(array1, null) = cloned copy of array1 * ArrayUtils.addAll(null, array2) = cloned copy of array2 * ArrayUtils.addAll([], []) = [] ** * @param array1 the first array whose elements are added to the new array. * @param array2 the second array whose elements are added to the new array. * @return The new float[] array. * @since 2.1 */ public static float[] addAll(float[] array1, float[] array2) { if (array1 == null) { return clone(array2); } else if (array2 == null) { return clone(array1); } float[] joinedArray = new float[array1.length + array2.length]; System.arraycopy(array1, 0, joinedArray, 0, array1.length); System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); return joinedArray; } /** *
Adds all the elements of the given arrays into a new array.
*The new array contains all of the element of array1
followed
* by all of the elements array2
. When an array is returned, it is always
* a new array.
* ArrayUtils.addAll(array1, null) = cloned copy of array1 * ArrayUtils.addAll(null, array2) = cloned copy of array2 * ArrayUtils.addAll([], []) = [] ** * @param array1 the first array whose elements are added to the new array. * @param array2 the second array whose elements are added to the new array. * @return The new double[] array. * @since 2.1 */ public static double[] addAll(double[] array1, double[] array2) { if (array1 == null) { return clone(array2); } else if (array2 == null) { return clone(array1); } double[] joinedArray = new double[array1.length + array2.length]; System.arraycopy(array1, 0, joinedArray, 0, array1.length); System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); return joinedArray; } /** *
Copies the given array and adds the given element at the end of the new array.
* *The new array contains the same elements of the input * array plus the given element in the last position. The component type of * the new array is the same as that of the input array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element, unless the element itself is null,
* in which case the return type is Object[]
* ArrayUtils.add(null, null) = [null] * ArrayUtils.add(null, "a") = ["a"] * ArrayUtils.add(["a"], null) = ["a", null] * ArrayUtils.add(["a"], "b") = ["a", "b"] * ArrayUtils.add(["a", "b"], "c") = ["a", "b", "c"] ** * @param array the array to "add" the element to, may be
null
* @param element the object to add, may be null
* @return A new array containing the existing elements plus the new element
* The returned array type will be that of the input array (unless null),
* in which case it will have the same type as the element.
* @since 2.1
*/
public static Object[] add(Object[] array, Object element) {
Class type;
if (array != null){
type = array.getClass();
} else if (element != null) {
type = element.getClass();
} else {
type = Object.class;
}
Object[] newArray = (Object[]) copyArrayGrow1(array, type);
newArray[newArray.length - 1] = element;
return newArray;
}
/**
* Copies the given array and adds the given element at the end of the new array.
* *The new array contains the same elements of the input * array plus the given element in the last position. The component type of * the new array is the same as that of the input array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add(null, true) = [true] * ArrayUtils.add([true], false) = [true, false] * ArrayUtils.add([true, false], true) = [true, false, true] ** * @param array the array to copy and add the element to, may be
null
* @param element the object to add at the last index of the new array
* @return A new array containing the existing elements plus the new element
* @since 2.1
*/
public static boolean[] add(boolean[] array, boolean element) {
boolean[] newArray = (boolean[])copyArrayGrow1(array, Boolean.TYPE);
newArray[newArray.length - 1] = element;
return newArray;
}
/**
* Copies the given array and adds the given element at the end of the new array.
* *The new array contains the same elements of the input * array plus the given element in the last position. The component type of * the new array is the same as that of the input array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add(null, 0) = [0] * ArrayUtils.add([1], 0) = [1, 0] * ArrayUtils.add([1, 0], 1) = [1, 0, 1] ** * @param array the array to copy and add the element to, may be
null
* @param element the object to add at the last index of the new array
* @return A new array containing the existing elements plus the new element
* @since 2.1
*/
public static byte[] add(byte[] array, byte element) {
byte[] newArray = (byte[])copyArrayGrow1(array, Byte.TYPE);
newArray[newArray.length - 1] = element;
return newArray;
}
/**
* Copies the given array and adds the given element at the end of the new array.
* *The new array contains the same elements of the input * array plus the given element in the last position. The component type of * the new array is the same as that of the input array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add(null, '0') = ['0'] * ArrayUtils.add(['1'], '0') = ['1', '0'] * ArrayUtils.add(['1', '0'], '1') = ['1', '0', '1'] ** * @param array the array to copy and add the element to, may be
null
* @param element the object to add at the last index of the new array
* @return A new array containing the existing elements plus the new element
* @since 2.1
*/
public static char[] add(char[] array, char element) {
char[] newArray = (char[])copyArrayGrow1(array, Character.TYPE);
newArray[newArray.length - 1] = element;
return newArray;
}
/**
* Copies the given array and adds the given element at the end of the new array.
* *The new array contains the same elements of the input * array plus the given element in the last position. The component type of * the new array is the same as that of the input array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add(null, 0) = [0] * ArrayUtils.add([1], 0) = [1, 0] * ArrayUtils.add([1, 0], 1) = [1, 0, 1] ** * @param array the array to copy and add the element to, may be
null
* @param element the object to add at the last index of the new array
* @return A new array containing the existing elements plus the new element
* @since 2.1
*/
public static double[] add(double[] array, double element) {
double[] newArray = (double[])copyArrayGrow1(array, Double.TYPE);
newArray[newArray.length - 1] = element;
return newArray;
}
/**
* Copies the given array and adds the given element at the end of the new array.
* *The new array contains the same elements of the input * array plus the given element in the last position. The component type of * the new array is the same as that of the input array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add(null, 0) = [0] * ArrayUtils.add([1], 0) = [1, 0] * ArrayUtils.add([1, 0], 1) = [1, 0, 1] ** * @param array the array to copy and add the element to, may be
null
* @param element the object to add at the last index of the new array
* @return A new array containing the existing elements plus the new element
* @since 2.1
*/
public static float[] add(float[] array, float element) {
float[] newArray = (float[])copyArrayGrow1(array, Float.TYPE);
newArray[newArray.length - 1] = element;
return newArray;
}
/**
* Copies the given array and adds the given element at the end of the new array.
* *The new array contains the same elements of the input * array plus the given element in the last position. The component type of * the new array is the same as that of the input array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add(null, 0) = [0] * ArrayUtils.add([1], 0) = [1, 0] * ArrayUtils.add([1, 0], 1) = [1, 0, 1] ** * @param array the array to copy and add the element to, may be
null
* @param element the object to add at the last index of the new array
* @return A new array containing the existing elements plus the new element
* @since 2.1
*/
public static int[] add(int[] array, int element) {
int[] newArray = (int[])copyArrayGrow1(array, Integer.TYPE);
newArray[newArray.length - 1] = element;
return newArray;
}
/**
* Copies the given array and adds the given element at the end of the new array.
* *The new array contains the same elements of the input * array plus the given element in the last position. The component type of * the new array is the same as that of the input array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add(null, 0) = [0] * ArrayUtils.add([1], 0) = [1, 0] * ArrayUtils.add([1, 0], 1) = [1, 0, 1] ** * @param array the array to copy and add the element to, may be
null
* @param element the object to add at the last index of the new array
* @return A new array containing the existing elements plus the new element
* @since 2.1
*/
public static long[] add(long[] array, long element) {
long[] newArray = (long[])copyArrayGrow1(array, Long.TYPE);
newArray[newArray.length - 1] = element;
return newArray;
}
/**
* Copies the given array and adds the given element at the end of the new array.
* *The new array contains the same elements of the input * array plus the given element in the last position. The component type of * the new array is the same as that of the input array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add(null, 0) = [0] * ArrayUtils.add([1], 0) = [1, 0] * ArrayUtils.add([1, 0], 1) = [1, 0, 1] ** * @param array the array to copy and add the element to, may be
null
* @param element the object to add at the last index of the new array
* @return A new array containing the existing elements plus the new element
* @since 2.1
*/
public static short[] add(short[] array, short element) {
short[] newArray = (short[])copyArrayGrow1(array, Short.TYPE);
newArray[newArray.length - 1] = element;
return newArray;
}
/**
* Returns a copy of the given array of size 1 greater than the argument.
* The last value of the array is left to the default value.
*
* @param array The array to copy, must not be null
.
* @param newArrayComponentType If array
is null
, create a
* size 1 array of this type.
* @return A new copy of the array of size 1 greater than the input.
*/
private static Object copyArrayGrow1(Object array, Class newArrayComponentType) {
if (array != null) {
int arrayLength = Array.getLength(array);
Object newArray = Array.newInstance(array.getClass().getComponentType(), arrayLength + 1);
System.arraycopy(array, 0, newArray, 0, arrayLength);
return newArray;
}
return Array.newInstance(newArrayComponentType, 1);
}
/**
* Inserts the specified element at the specified position in the array. * Shifts the element currently at that position (if any) and any subsequent * elements to the right (adds one to their indices).
* *This method returns a new array with the same elements of the input * array plus the given element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add(null, 0, null) = [null] * ArrayUtils.add(null, 0, "a") = ["a"] * ArrayUtils.add(["a"], 1, null) = ["a", null] * ArrayUtils.add(["a"], 1, "b") = ["a", "b"] * ArrayUtils.add(["a", "b"], 3, "c") = ["a", "b", "c"] ** * @param array the array to add the element to, may be
null
* @param index the position of the new object
* @param element the object to add
* @return A new array containing the existing elements and the new element
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index > array.length).
*/
public static Object[] add(Object[] array, int index, Object element) {
Class clss = null;
if (array != null) {
clss = array.getClass().getComponentType();
} else if (element != null) {
clss = element.getClass();
} else {
return new Object[]{null};
}
return (Object[]) add(array, index, element, clss);
}
/**
* Inserts the specified element at the specified position in the array. * Shifts the element currently at that position (if any) and any subsequent * elements to the right (adds one to their indices).
* *This method returns a new array with the same elements of the input * array plus the given element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add(null, 0, true) = [true] * ArrayUtils.add([true], 0, false) = [false, true] * ArrayUtils.add([false], 1, true) = [false, true] * ArrayUtils.add([true, false], 1, true) = [true, true, false] ** * @param array the array to add the element to, may be
null
* @param index the position of the new object
* @param element the object to add
* @return A new array containing the existing elements and the new element
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index > array.length).
*/
public static boolean[] add(boolean[] array, int index, boolean element) {
return (boolean[]) add(array, index, BooleanUtils.toBooleanObject(element), Boolean.TYPE);
}
/**
* Inserts the specified element at the specified position in the array. * Shifts the element currently at that position (if any) and any subsequent * elements to the right (adds one to their indices).
* *This method returns a new array with the same elements of the input * array plus the given element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add(null, 0, 'a') = ['a'] * ArrayUtils.add(['a'], 0, 'b') = ['b', 'a'] * ArrayUtils.add(['a', 'b'], 0, 'c') = ['c', 'a', 'b'] * ArrayUtils.add(['a', 'b'], 1, 'k') = ['a', 'k', 'b'] * ArrayUtils.add(['a', 'b', 'c'], 1, 't') = ['a', 't', 'b', 'c'] ** * @param array the array to add the element to, may be
null
* @param index the position of the new object
* @param element the object to add
* @return A new array containing the existing elements and the new element
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index > array.length).
*/
public static char[] add(char[] array, int index, char element) {
return (char[]) add(array, index, new Character(element), Character.TYPE);
}
/**
* Inserts the specified element at the specified position in the array. * Shifts the element currently at that position (if any) and any subsequent * elements to the right (adds one to their indices).
* *This method returns a new array with the same elements of the input * array plus the given element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add([1], 0, 2) = [2, 1] * ArrayUtils.add([2, 6], 2, 3) = [2, 6, 3] * ArrayUtils.add([2, 6], 0, 1) = [1, 2, 6] * ArrayUtils.add([2, 6, 3], 2, 1) = [2, 6, 1, 3] ** * @param array the array to add the element to, may be
null
* @param index the position of the new object
* @param element the object to add
* @return A new array containing the existing elements and the new element
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index > array.length).
*/
public static byte[] add(byte[] array, int index, byte element) {
return (byte[]) add(array, index, new Byte(element), Byte.TYPE);
}
/**
* Inserts the specified element at the specified position in the array. * Shifts the element currently at that position (if any) and any subsequent * elements to the right (adds one to their indices).
* *This method returns a new array with the same elements of the input * array plus the given element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add([1], 0, 2) = [2, 1] * ArrayUtils.add([2, 6], 2, 10) = [2, 6, 10] * ArrayUtils.add([2, 6], 0, -4) = [-4, 2, 6] * ArrayUtils.add([2, 6, 3], 2, 1) = [2, 6, 1, 3] ** * @param array the array to add the element to, may be
null
* @param index the position of the new object
* @param element the object to add
* @return A new array containing the existing elements and the new element
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index > array.length).
*/
public static short[] add(short[] array, int index, short element) {
return (short[]) add(array, index, new Short(element), Short.TYPE);
}
/**
* Inserts the specified element at the specified position in the array. * Shifts the element currently at that position (if any) and any subsequent * elements to the right (adds one to their indices).
* *This method returns a new array with the same elements of the input * array plus the given element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add([1], 0, 2) = [2, 1] * ArrayUtils.add([2, 6], 2, 10) = [2, 6, 10] * ArrayUtils.add([2, 6], 0, -4) = [-4, 2, 6] * ArrayUtils.add([2, 6, 3], 2, 1) = [2, 6, 1, 3] ** * @param array the array to add the element to, may be
null
* @param index the position of the new object
* @param element the object to add
* @return A new array containing the existing elements and the new element
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index > array.length).
*/
public static int[] add(int[] array, int index, int element) {
return (int[]) add(array, index, new Integer(element), Integer.TYPE);
}
/**
* Inserts the specified element at the specified position in the array. * Shifts the element currently at that position (if any) and any subsequent * elements to the right (adds one to their indices).
* *This method returns a new array with the same elements of the input * array plus the given element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add([1L], 0, 2L) = [2L, 1L] * ArrayUtils.add([2L, 6L], 2, 10L) = [2L, 6L, 10L] * ArrayUtils.add([2L, 6L], 0, -4L) = [-4L, 2L, 6L] * ArrayUtils.add([2L, 6L, 3L], 2, 1L) = [2L, 6L, 1L, 3L] ** * @param array the array to add the element to, may be
null
* @param index the position of the new object
* @param element the object to add
* @return A new array containing the existing elements and the new element
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index > array.length).
*/
public static long[] add(long[] array, int index, long element) {
return (long[]) add(array, index, new Long(element), Long.TYPE);
}
/**
* Inserts the specified element at the specified position in the array. * Shifts the element currently at that position (if any) and any subsequent * elements to the right (adds one to their indices).
* *This method returns a new array with the same elements of the input * array plus the given element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add([1.1f], 0, 2.2f) = [2.2f, 1.1f] * ArrayUtils.add([2.3f, 6.4f], 2, 10.5f) = [2.3f, 6.4f, 10.5f] * ArrayUtils.add([2.6f, 6.7f], 0, -4.8f) = [-4.8f, 2.6f, 6.7f] * ArrayUtils.add([2.9f, 6.0f, 0.3f], 2, 1.0f) = [2.9f, 6.0f, 1.0f, 0.3f] ** * @param array the array to add the element to, may be
null
* @param index the position of the new object
* @param element the object to add
* @return A new array containing the existing elements and the new element
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index > array.length).
*/
public static float[] add(float[] array, int index, float element) {
return (float[]) add(array, index, new Float(element), Float.TYPE);
}
/**
* Inserts the specified element at the specified position in the array. * Shifts the element currently at that position (if any) and any subsequent * elements to the right (adds one to their indices).
* *This method returns a new array with the same elements of the input * array plus the given element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, a new one element array is returned
* whose component type is the same as the element.
* ArrayUtils.add([1.1], 0, 2.2) = [2.2, 1.1] * ArrayUtils.add([2.3, 6.4], 2, 10.5) = [2.3, 6.4, 10.5] * ArrayUtils.add([2.6, 6.7], 0, -4.8) = [-4.8, 2.6, 6.7] * ArrayUtils.add([2.9, 6.0, 0.3], 2, 1.0) = [2.9, 6.0, 1.0, 0.3] ** * @param array the array to add the element to, may be
null
* @param index the position of the new object
* @param element the object to add
* @return A new array containing the existing elements and the new element
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index > array.length).
*/
public static double[] add(double[] array, int index, double element) {
return (double[]) add(array, index, new Double(element), Double.TYPE);
}
/**
* Underlying implementation of add(array, index, element) methods.
* The last parameter is the class, which may not equal element.getClass
* for primitives.
*
* @param array the array to add the element to, may be null
* @param index the position of the new object
* @param element the object to add
* @param clss the type of the element being added
* @return A new array containing the existing elements and the new element
*/
private static Object add(Object array, int index, Object element, Class clss) {
if (array == null) {
if (index != 0) {
throw new IndexOutOfBoundsException("Index: " + index + ", Length: 0");
}
Object joinedArray = Array.newInstance(clss, 1);
Array.set(joinedArray, 0, element);
return joinedArray;
}
int length = Array.getLength(array);
if (index > length || index < 0) {
throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);
}
Object result = Array.newInstance(clss, length + 1);
System.arraycopy(array, 0, result, 0, index);
Array.set(result, index, element);
if (index < length) {
System.arraycopy(array, index, result, index + 1, length - index);
}
return result;
}
/**
* Removes the element at the specified position from the specified array. * All subsequent elements are shifted to the left (substracts one from * their indices).
* *This method returns a new array with the same elements of the input * array except the element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, an IndexOutOfBoundsException
* will be thrown, because in that case no valid index can be specified.
* ArrayUtils.remove(["a"], 0) = [] * ArrayUtils.remove(["a", "b"], 0) = ["b"] * ArrayUtils.remove(["a", "b"], 1) = ["a"] * ArrayUtils.remove(["a", "b", "c"], 1) = ["a", "c"] ** * @param array the array to remove the element from, may not be
null
* @param index the position of the element to be removed
* @return A new array containing the existing elements except the element
* at the specified position.
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index >= array.length), or if the array is null
.
* @since 2.1
*/
public static Object[] remove(Object[] array, int index) {
return (Object[]) remove((Object) array, index);
}
/**
* Removes the first occurrence of the specified element from the * specified array. All subsequent elements are shifted to the left * (substracts one from their indices). If the array doesn't contains * such an element, no elements are removed from the array.
* *This method returns a new array with the same elements of the input * array except the first occurrence of the specified element. The component * type of the returned array is always the same as that of the input * array.
* ** ArrayUtils.removeElement(null, "a") = null * ArrayUtils.removeElement([], "a") = [] * ArrayUtils.removeElement(["a"], "b") = ["a"] * ArrayUtils.removeElement(["a", "b"], "a") = ["b"] * ArrayUtils.removeElement(["a", "b", "a"], "a") = ["b", "a"] ** * @param array the array to remove the element from, may be
null
* @param element the element to be removed
* @return A new array containing the existing elements except the first
* occurrence of the specified element.
* @since 2.1
*/
public static Object[] removeElement(Object[] array, Object element) {
int index = indexOf(array, element);
if (index == INDEX_NOT_FOUND) {
return clone(array);
}
return remove(array, index);
}
/**
* Removes the element at the specified position from the specified array. * All subsequent elements are shifted to the left (substracts one from * their indices).
* *This method returns a new array with the same elements of the input * array except the element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, an IndexOutOfBoundsException
* will be thrown, because in that case no valid index can be specified.
* ArrayUtils.remove([true], 0) = [] * ArrayUtils.remove([true, false], 0) = [false] * ArrayUtils.remove([true, false], 1) = [true] * ArrayUtils.remove([true, true, false], 1) = [true, false] ** * @param array the array to remove the element from, may not be
null
* @param index the position of the element to be removed
* @return A new array containing the existing elements except the element
* at the specified position.
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index >= array.length), or if the array is null
.
* @since 2.1
*/
public static boolean[] remove(boolean[] array, int index) {
return (boolean[]) remove((Object) array, index);
}
/**
* Removes the first occurrence of the specified element from the * specified array. All subsequent elements are shifted to the left * (substracts one from their indices). If the array doesn't contains * such an element, no elements are removed from the array.
* *This method returns a new array with the same elements of the input * array except the first occurrence of the specified element. The component * type of the returned array is always the same as that of the input * array.
* ** ArrayUtils.removeElement(null, true) = null * ArrayUtils.removeElement([], true) = [] * ArrayUtils.removeElement([true], false) = [true] * ArrayUtils.removeElement([true, false], false) = [true] * ArrayUtils.removeElement([true, false, true], true) = [false, true] ** * @param array the array to remove the element from, may be
null
* @param element the element to be removed
* @return A new array containing the existing elements except the first
* occurrence of the specified element.
* @since 2.1
*/
public static boolean[] removeElement(boolean[] array, boolean element) {
int index = indexOf(array, element);
if (index == INDEX_NOT_FOUND) {
return clone(array);
}
return remove(array, index);
}
/**
* Removes the element at the specified position from the specified array. * All subsequent elements are shifted to the left (substracts one from * their indices).
* *This method returns a new array with the same elements of the input * array except the element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, an IndexOutOfBoundsException
* will be thrown, because in that case no valid index can be specified.
* ArrayUtils.remove([1], 0) = [] * ArrayUtils.remove([1, 0], 0) = [0] * ArrayUtils.remove([1, 0], 1) = [1] * ArrayUtils.remove([1, 0, 1], 1) = [1, 1] ** * @param array the array to remove the element from, may not be
null
* @param index the position of the element to be removed
* @return A new array containing the existing elements except the element
* at the specified position.
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index >= array.length), or if the array is null
.
* @since 2.1
*/
public static byte[] remove(byte[] array, int index) {
return (byte[]) remove((Object) array, index);
}
/**
* Removes the first occurrence of the specified element from the * specified array. All subsequent elements are shifted to the left * (substracts one from their indices). If the array doesn't contains * such an element, no elements are removed from the array.
* *This method returns a new array with the same elements of the input * array except the first occurrence of the specified element. The component * type of the returned array is always the same as that of the input * array.
* ** ArrayUtils.removeElement(null, 1) = null * ArrayUtils.removeElement([], 1) = [] * ArrayUtils.removeElement([1], 0) = [1] * ArrayUtils.removeElement([1, 0], 0) = [1] * ArrayUtils.removeElement([1, 0, 1], 1) = [0, 1] ** * @param array the array to remove the element from, may be
null
* @param element the element to be removed
* @return A new array containing the existing elements except the first
* occurrence of the specified element.
* @since 2.1
*/
public static byte[] removeElement(byte[] array, byte element) {
int index = indexOf(array, element);
if (index == INDEX_NOT_FOUND) {
return clone(array);
}
return remove(array, index);
}
/**
* Removes the element at the specified position from the specified array. * All subsequent elements are shifted to the left (substracts one from * their indices).
* *This method returns a new array with the same elements of the input * array except the element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, an IndexOutOfBoundsException
* will be thrown, because in that case no valid index can be specified.
* ArrayUtils.remove(['a'], 0) = [] * ArrayUtils.remove(['a', 'b'], 0) = ['b'] * ArrayUtils.remove(['a', 'b'], 1) = ['a'] * ArrayUtils.remove(['a', 'b', 'c'], 1) = ['a', 'c'] ** * @param array the array to remove the element from, may not be
null
* @param index the position of the element to be removed
* @return A new array containing the existing elements except the element
* at the specified position.
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index >= array.length), or if the array is null
.
* @since 2.1
*/
public static char[] remove(char[] array, int index) {
return (char[]) remove((Object) array, index);
}
/**
* Removes the first occurrence of the specified element from the * specified array. All subsequent elements are shifted to the left * (substracts one from their indices). If the array doesn't contains * such an element, no elements are removed from the array.
* *This method returns a new array with the same elements of the input * array except the first occurrence of the specified element. The component * type of the returned array is always the same as that of the input * array.
* ** ArrayUtils.removeElement(null, 'a') = null * ArrayUtils.removeElement([], 'a') = [] * ArrayUtils.removeElement(['a'], 'b') = ['a'] * ArrayUtils.removeElement(['a', 'b'], 'a') = ['b'] * ArrayUtils.removeElement(['a', 'b', 'a'], 'a') = ['b', 'a'] ** * @param array the array to remove the element from, may be
null
* @param element the element to be removed
* @return A new array containing the existing elements except the first
* occurrence of the specified element.
* @since 2.1
*/
public static char[] removeElement(char[] array, char element) {
int index = indexOf(array, element);
if (index == INDEX_NOT_FOUND) {
return clone(array);
}
return remove(array, index);
}
/**
* Removes the element at the specified position from the specified array. * All subsequent elements are shifted to the left (substracts one from * their indices).
* *This method returns a new array with the same elements of the input * array except the element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, an IndexOutOfBoundsException
* will be thrown, because in that case no valid index can be specified.
* ArrayUtils.remove([1.1], 0) = [] * ArrayUtils.remove([2.5, 6.0], 0) = [6.0] * ArrayUtils.remove([2.5, 6.0], 1) = [2.5] * ArrayUtils.remove([2.5, 6.0, 3.8], 1) = [2.5, 3.8] ** * @param array the array to remove the element from, may not be
null
* @param index the position of the element to be removed
* @return A new array containing the existing elements except the element
* at the specified position.
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index >= array.length), or if the array is null
.
* @since 2.1
*/
public static double[] remove(double[] array, int index) {
return (double[]) remove((Object) array, index);
}
/**
* Removes the first occurrence of the specified element from the * specified array. All subsequent elements are shifted to the left * (substracts one from their indices). If the array doesn't contains * such an element, no elements are removed from the array.
* *This method returns a new array with the same elements of the input * array except the first occurrence of the specified element. The component * type of the returned array is always the same as that of the input * array.
* ** ArrayUtils.removeElement(null, 1.1) = null * ArrayUtils.removeElement([], 1.1) = [] * ArrayUtils.removeElement([1.1], 1.2) = [1.1] * ArrayUtils.removeElement([1.1, 2.3], 1.1) = [2.3] * ArrayUtils.removeElement([1.1, 2.3, 1.1], 1.1) = [2.3, 1.1] ** * @param array the array to remove the element from, may be
null
* @param element the element to be removed
* @return A new array containing the existing elements except the first
* occurrence of the specified element.
* @since 2.1
*/
public static double[] removeElement(double[] array, double element) {
int index = indexOf(array, element);
if (index == INDEX_NOT_FOUND) {
return clone(array);
}
return remove(array, index);
}
/**
* Removes the element at the specified position from the specified array. * All subsequent elements are shifted to the left (substracts one from * their indices).
* *This method returns a new array with the same elements of the input * array except the element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, an IndexOutOfBoundsException
* will be thrown, because in that case no valid index can be specified.
* ArrayUtils.remove([1.1], 0) = [] * ArrayUtils.remove([2.5, 6.0], 0) = [6.0] * ArrayUtils.remove([2.5, 6.0], 1) = [2.5] * ArrayUtils.remove([2.5, 6.0, 3.8], 1) = [2.5, 3.8] ** * @param array the array to remove the element from, may not be
null
* @param index the position of the element to be removed
* @return A new array containing the existing elements except the element
* at the specified position.
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index >= array.length), or if the array is null
.
* @since 2.1
*/
public static float[] remove(float[] array, int index) {
return (float[]) remove((Object) array, index);
}
/**
* Removes the first occurrence of the specified element from the * specified array. All subsequent elements are shifted to the left * (substracts one from their indices). If the array doesn't contains * such an element, no elements are removed from the array.
* *This method returns a new array with the same elements of the input * array except the first occurrence of the specified element. The component * type of the returned array is always the same as that of the input * array.
* ** ArrayUtils.removeElement(null, 1.1) = null * ArrayUtils.removeElement([], 1.1) = [] * ArrayUtils.removeElement([1.1], 1.2) = [1.1] * ArrayUtils.removeElement([1.1, 2.3], 1.1) = [2.3] * ArrayUtils.removeElement([1.1, 2.3, 1.1], 1.1) = [2.3, 1.1] ** * @param array the array to remove the element from, may be
null
* @param element the element to be removed
* @return A new array containing the existing elements except the first
* occurrence of the specified element.
* @since 2.1
*/
public static float[] removeElement(float[] array, float element) {
int index = indexOf(array, element);
if (index == INDEX_NOT_FOUND) {
return clone(array);
}
return remove(array, index);
}
/**
* Removes the element at the specified position from the specified array. * All subsequent elements are shifted to the left (substracts one from * their indices).
* *This method returns a new array with the same elements of the input * array except the element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, an IndexOutOfBoundsException
* will be thrown, because in that case no valid index can be specified.
* ArrayUtils.remove([1], 0) = [] * ArrayUtils.remove([2, 6], 0) = [6] * ArrayUtils.remove([2, 6], 1) = [2] * ArrayUtils.remove([2, 6, 3], 1) = [2, 3] ** * @param array the array to remove the element from, may not be
null
* @param index the position of the element to be removed
* @return A new array containing the existing elements except the element
* at the specified position.
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index >= array.length), or if the array is null
.
* @since 2.1
*/
public static int[] remove(int[] array, int index) {
return (int[]) remove((Object) array, index);
}
/**
* Removes the first occurrence of the specified element from the * specified array. All subsequent elements are shifted to the left * (substracts one from their indices). If the array doesn't contains * such an element, no elements are removed from the array.
* *This method returns a new array with the same elements of the input * array except the first occurrence of the specified element. The component * type of the returned array is always the same as that of the input * array.
* ** ArrayUtils.removeElement(null, 1) = null * ArrayUtils.removeElement([], 1) = [] * ArrayUtils.removeElement([1], 2) = [1] * ArrayUtils.removeElement([1, 3], 1) = [3] * ArrayUtils.removeElement([1, 3, 1], 1) = [3, 1] ** * @param array the array to remove the element from, may be
null
* @param element the element to be removed
* @return A new array containing the existing elements except the first
* occurrence of the specified element.
* @since 2.1
*/
public static int[] removeElement(int[] array, int element) {
int index = indexOf(array, element);
if (index == INDEX_NOT_FOUND) {
return clone(array);
}
return remove(array, index);
}
/**
* Removes the element at the specified position from the specified array. * All subsequent elements are shifted to the left (substracts one from * their indices).
* *This method returns a new array with the same elements of the input * array except the element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, an IndexOutOfBoundsException
* will be thrown, because in that case no valid index can be specified.
* ArrayUtils.remove([1], 0) = [] * ArrayUtils.remove([2, 6], 0) = [6] * ArrayUtils.remove([2, 6], 1) = [2] * ArrayUtils.remove([2, 6, 3], 1) = [2, 3] ** * @param array the array to remove the element from, may not be
null
* @param index the position of the element to be removed
* @return A new array containing the existing elements except the element
* at the specified position.
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index >= array.length), or if the array is null
.
* @since 2.1
*/
public static long[] remove(long[] array, int index) {
return (long[]) remove((Object) array, index);
}
/**
* Removes the first occurrence of the specified element from the * specified array. All subsequent elements are shifted to the left * (substracts one from their indices). If the array doesn't contains * such an element, no elements are removed from the array.
* *This method returns a new array with the same elements of the input * array except the first occurrence of the specified element. The component * type of the returned array is always the same as that of the input * array.
* ** ArrayUtils.removeElement(null, 1) = null * ArrayUtils.removeElement([], 1) = [] * ArrayUtils.removeElement([1], 2) = [1] * ArrayUtils.removeElement([1, 3], 1) = [3] * ArrayUtils.removeElement([1, 3, 1], 1) = [3, 1] ** * @param array the array to remove the element from, may be
null
* @param element the element to be removed
* @return A new array containing the existing elements except the first
* occurrence of the specified element.
* @since 2.1
*/
public static long[] removeElement(long[] array, long element) {
int index = indexOf(array, element);
if (index == INDEX_NOT_FOUND) {
return clone(array);
}
return remove(array, index);
}
/**
* Removes the element at the specified position from the specified array. * All subsequent elements are shifted to the left (substracts one from * their indices).
* *This method returns a new array with the same elements of the input * array except the element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, an IndexOutOfBoundsException
* will be thrown, because in that case no valid index can be specified.
* ArrayUtils.remove([1], 0) = [] * ArrayUtils.remove([2, 6], 0) = [6] * ArrayUtils.remove([2, 6], 1) = [2] * ArrayUtils.remove([2, 6, 3], 1) = [2, 3] ** * @param array the array to remove the element from, may not be
null
* @param index the position of the element to be removed
* @return A new array containing the existing elements except the element
* at the specified position.
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index >= array.length), or if the array is null
.
* @since 2.1
*/
public static short[] remove(short[] array, int index) {
return (short[]) remove((Object) array, index);
}
/**
* Removes the first occurrence of the specified element from the * specified array. All subsequent elements are shifted to the left * (substracts one from their indices). If the array doesn't contains * such an element, no elements are removed from the array.
* *This method returns a new array with the same elements of the input * array except the first occurrence of the specified element. The component * type of the returned array is always the same as that of the input * array.
* ** ArrayUtils.removeElement(null, 1) = null * ArrayUtils.removeElement([], 1) = [] * ArrayUtils.removeElement([1], 2) = [1] * ArrayUtils.removeElement([1, 3], 1) = [3] * ArrayUtils.removeElement([1, 3, 1], 1) = [3, 1] ** * @param array the array to remove the element from, may be
null
* @param element the element to be removed
* @return A new array containing the existing elements except the first
* occurrence of the specified element.
* @since 2.1
*/
public static short[] removeElement(short[] array, short element) {
int index = indexOf(array, element);
if (index == INDEX_NOT_FOUND) {
return clone(array);
}
return remove(array, index);
}
/**
* Removes the element at the specified position from the specified array. * All subsequent elements are shifted to the left (substracts one from * their indices).
* *This method returns a new array with the same elements of the input * array except the element on the specified position. The component * type of the returned array is always the same as that of the input * array.
* *If the input array is null
, an IndexOutOfBoundsException
* will be thrown, because in that case no valid index can be specified.
null
* @param index the position of the element to be removed
* @return A new array containing the existing elements except the element
* at the specified position.
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index >= array.length), or if the array is null
.
* @since 2.1
*/
private static Object remove(Object array, int index) {
int length = getLength(array);
if (index < 0 || index >= length) {
throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);
}
Object result = Array.newInstance(array.getClass().getComponentType(), length - 1);
System.arraycopy(array, 0, result, 0, index);
if (index < length - 1) {
System.arraycopy(array, index + 1, result, index, length - index - 1);
}
return result;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/BitField.java 100644 0 0 21772 11513702445 23307 0 ustar 0 0 /*
* 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.lang;
/**
* Operations on bit-mapped fields.
* * @author Apache Software Foundation * @author Apache Jakarta POI * @author Scott Sanders (sanders at apache dot org) * @author Marc Johnson (mjohnson at apache dot org) * @author Andrew C. Oliver (acoliver at apache dot org) * @author Pete Gieser * @author Gary Gregory * @since 2.0 * @version $Id: BitField.java 905636 2010-02-02 14:03:32Z niallp $ */ public class BitField { private final int _mask; private final int _shift_count; /** *Creates a BitField instance.
* * @param mask the mask specifying which bits apply to this * BitField. Bits that are set in this mask are the bits * that this BitField operates on */ public BitField(int mask) { _mask = mask; int count = 0; int bit_pattern = mask; if (bit_pattern != 0) { while ((bit_pattern & 1) == 0) { count++; bit_pattern >>= 1; } } _shift_count = count; } /** *Obtains the value for the specified BitField, appropriately * shifted right.
* *Many users of a BitField will want to treat the specified * bits as an int value, and will not want to be aware that the * value is stored as a BitField (and so shifted left so many * bits).
* * @see #setValue(int,int) * @param holder the int data containing the bits we're interested * in * @return the selected bits, shifted right appropriately */ public int getValue(int holder) { return getRawValue(holder) >> _shift_count; } /** *Obtains the value for the specified BitField, appropriately * shifted right, as a short.
* *Many users of a BitField will want to treat the specified * bits as an int value, and will not want to be aware that the * value is stored as a BitField (and so shifted left so many * bits).
* * @see #setShortValue(short,short) * @param holder the short data containing the bits we're * interested in * @return the selected bits, shifted right appropriately */ public short getShortValue(short holder) { return (short) getValue(holder); } /** *Obtains the value for the specified BitField, unshifted.
* * @param holder the int data containing the bits we're * interested in * @return the selected bits */ public int getRawValue(int holder) { return holder & _mask; } /** *Obtains the value for the specified BitField, unshifted.
* * @param holder the short data containing the bits we're * interested in * @return the selected bits */ public short getShortRawValue(short holder) { return (short) getRawValue(holder); } /** *Returns whether the field is set or not.
* *This is most commonly used for a single-bit field, which is * often used to represent a boolean value; the results of using * it for a multi-bit field is to determine whether *any* of its * bits are set.
* * @param holder the int data containing the bits we're interested * in * @returntrue
if any of the bits are set,
* else false
*/
public boolean isSet(int holder) {
return (holder & _mask) != 0;
}
/**
* Returns whether all of the bits are set or not.
* *This is a stricter test than {@link #isSet(int)},
* in that all of the bits in a multi-bit set must be set
* for this method to return true
.
true
if all of the bits are set,
* else false
*/
public boolean isAllSet(int holder) {
return (holder & _mask) == _mask;
}
/**
* Replaces the bits with new values.
* * @see #getValue(int) * @param holder the int data containing the bits we're * interested in * @param value the new value for the specified bits * @return the value of holder with the bits from the value * parameter replacing the old bits */ public int setValue(int holder, int value) { return (holder & ~_mask) | ((value << _shift_count) & _mask); } /** *Replaces the bits with new values.
* * @see #getShortValue(short) * @param holder the short data containing the bits we're * interested in * @param value the new value for the specified bits * @return the value of holder with the bits from the value * parameter replacing the old bits */ public short setShortValue(short holder, short value) { return (short) setValue(holder, value); } /** *Clears the bits.
* * @param holder the int data containing the bits we're * interested in * @return the value of holder with the specified bits cleared * (set to0
)
*/
public int clear(int holder) {
return holder & ~_mask;
}
/**
* Clears the bits.
* * @param holder the short data containing the bits we're * interested in * @return the value of holder with the specified bits cleared * (set to0
)
*/
public short clearShort(short holder) {
return (short) clear(holder);
}
/**
* Clears the bits.
* * @param holder the byte data containing the bits we're * interested in * * @return the value of holder with the specified bits cleared * (set to0
)
*/
public byte clearByte(byte holder) {
return (byte) clear(holder);
}
/**
* Sets the bits.
* * @param holder the int data containing the bits we're * interested in * @return the value of holder with the specified bits set * to1
*/
public int set(int holder) {
return holder | _mask;
}
/**
* Sets the bits.
* * @param holder the short data containing the bits we're * interested in * @return the value of holder with the specified bits set * to1
*/
public short setShort(short holder) {
return (short) set(holder);
}
/**
* Sets the bits.
* * @param holder the byte data containing the bits we're * interested in * * @return the value of holder with the specified bits set * to1
*/
public byte setByte(byte holder) {
return (byte) set(holder);
}
/**
* Sets a boolean BitField.
* * @param holder the int data containing the bits we're * interested in * @param flag indicating whether to set or clear the bits * @return the value of holder with the specified bits set or * cleared */ public int setBoolean(int holder, boolean flag) { return flag ? set(holder) : clear(holder); } /** *Sets a boolean BitField.
* * @param holder the short data containing the bits we're * interested in * @param flag indicating whether to set or clear the bits * @return the value of holder with the specified bits set or * cleared */ public short setShortBoolean(short holder, boolean flag) { return flag ? setShort(holder) : clearShort(holder); } /** *Sets a boolean BitField.
* * @param holder the byte data containing the bits we're * interested in * @param flag indicating whether to set or clear the bits * @return the value of holder with the specified bits set or * cleared */ public byte setByteBoolean(byte holder, boolean flag) { return flag ? setByte(holder) : clearByte(holder); } } commons-lang-2.6-src/src/main/java/org/apache/commons/lang/BooleanUtils.java 100644 0 0 111744 11513702445 24244 0 ustar 0 0 /* * 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.lang; import org.apache.commons.lang.math.NumberUtils; /** *Operations on boolean primitives and Boolean objects.
* *This class tries to handle null
input gracefully.
* An exception will not be thrown for a null
input.
* Each method documents its behaviour in more detail.
#ThreadSafe#
* @author Apache Software Foundation * @author Matthew Hawthorne * @author Gary Gregory * @since 2.0 * @version $Id: BooleanUtils.java 1057037 2011-01-09 21:35:32Z niallp $ */ public class BooleanUtils { /** *BooleanUtils
instances should NOT be constructed in standard programming.
* Instead, the class should be used as BooleanUtils.toBooleanObject(true);
.
This constructor is public to permit tools that require a JavaBean instance * to operate.
*/ public BooleanUtils() { super(); } // Boolean utilities //-------------------------------------------------------------------------- /** *Negates the specified boolean.
* *If null
is passed in, null
will be returned.
* BooleanUtils.negate(Boolean.TRUE) = Boolean.FALSE; * BooleanUtils.negate(Boolean.FALSE) = Boolean.TRUE; * BooleanUtils.negate(null) = null; ** * @param bool the Boolean to negate, may be null * @return the negated Boolean, or
null
if null
input
*/
public static Boolean negate(Boolean bool) {
if (bool == null) {
return null;
}
return (bool.booleanValue() ? Boolean.FALSE : Boolean.TRUE);
}
// boolean Boolean methods
//-----------------------------------------------------------------------
/**
* Checks if a Boolean
value is true
,
* handling null
by returning false
.
* BooleanUtils.isTrue(Boolean.TRUE) = true * BooleanUtils.isTrue(Boolean.FALSE) = false * BooleanUtils.isTrue(null) = false ** * @param bool the boolean to check, null returns
false
* @return true
only if the input is non-null and true
* @since 2.1
*/
public static boolean isTrue(Boolean bool) {
if (bool == null) {
return false;
}
return bool.booleanValue() ? true : false;
}
/**
* Checks if a Boolean
value is not true
,
* handling null
by returning true
.
* BooleanUtils.isNotTrue(Boolean.TRUE) = false * BooleanUtils.isNotTrue(Boolean.FALSE) = true * BooleanUtils.isNotTrue(null) = true ** * @param bool the boolean to check, null returns
true
* @return true
if the input is null or false
* @since 2.3
*/
public static boolean isNotTrue(Boolean bool) {
return !isTrue(bool);
}
/**
* Checks if a Boolean
value is false
,
* handling null
by returning false
.
* BooleanUtils.isFalse(Boolean.TRUE) = false * BooleanUtils.isFalse(Boolean.FALSE) = true * BooleanUtils.isFalse(null) = false ** * @param bool the boolean to check, null returns
false
* @return true
only if the input is non-null and false
* @since 2.1
*/
public static boolean isFalse(Boolean bool) {
if (bool == null) {
return false;
}
return bool.booleanValue() ? false : true;
}
/**
* Checks if a Boolean
value is not false
,
* handling null
by returning true
.
* BooleanUtils.isNotFalse(Boolean.TRUE) = true * BooleanUtils.isNotFalse(Boolean.FALSE) = false * BooleanUtils.isNotFalse(null) = true ** * @param bool the boolean to check, null returns
true
* @return true
if the input is null or true
* @since 2.3
*/
public static boolean isNotFalse(Boolean bool) {
return !isFalse(bool);
}
//-----------------------------------------------------------------------
/**
* Boolean factory that avoids creating new Boolean objecs all the time.
* *This method was added to JDK1.4 but is available here for earlier JDKs.
* ** BooleanUtils.toBooleanObject(false) = Boolean.FALSE * BooleanUtils.toBooleanObject(true) = Boolean.TRUE ** * @param bool the boolean to convert * @return Boolean.TRUE or Boolean.FALSE as appropriate */ public static Boolean toBooleanObject(boolean bool) { return bool ? Boolean.TRUE : Boolean.FALSE; } /** *
Converts a Boolean to a boolean handling null
* by returning false
.
* BooleanUtils.toBoolean(Boolean.TRUE) = true * BooleanUtils.toBoolean(Boolean.FALSE) = false * BooleanUtils.toBoolean(null) = false ** * @param bool the boolean to convert * @return
true
or false
,
* null
returns false
*/
public static boolean toBoolean(Boolean bool) {
if (bool == null) {
return false;
}
return bool.booleanValue() ? true : false;
}
/**
* Converts a Boolean to a boolean handling null
.
* BooleanUtils.toBooleanDefaultIfNull(Boolean.TRUE, false) = true * BooleanUtils.toBooleanDefaultIfNull(Boolean.FALSE, true) = false * BooleanUtils.toBooleanDefaultIfNull(null, true) = true ** * @param bool the boolean to convert * @param valueIfNull the boolean value to return if
null
* @return true
or false
*/
public static boolean toBooleanDefaultIfNull(Boolean bool, boolean valueIfNull) {
if (bool == null) {
return valueIfNull;
}
return bool.booleanValue() ? true : false;
}
// Integer to Boolean methods
//-----------------------------------------------------------------------
/**
* Converts an int to a boolean using the convention that zero
* is false
.
* BooleanUtils.toBoolean(0) = false * BooleanUtils.toBoolean(1) = true * BooleanUtils.toBoolean(2) = true ** * @param value the int to convert * @return
true
if non-zero, false
* if zero
*/
public static boolean toBoolean(int value) {
return value == 0 ? false : true;
}
/**
* Converts an int to a Boolean using the convention that zero
* is false
.
* BooleanUtils.toBoolean(0) = Boolean.FALSE * BooleanUtils.toBoolean(1) = Boolean.TRUE * BooleanUtils.toBoolean(2) = Boolean.TRUE ** * @param value the int to convert * @return Boolean.TRUE if non-zero, Boolean.FALSE if zero, *
null
if null
*/
public static Boolean toBooleanObject(int value) {
return value == 0 ? Boolean.FALSE : Boolean.TRUE;
}
/**
* Converts an Integer to a Boolean using the convention that zero
* is false
.
null
will be converted to null
.
* BooleanUtils.toBoolean(new Integer(0)) = Boolean.FALSE * BooleanUtils.toBoolean(new Integer(1)) = Boolean.TRUE * BooleanUtils.toBoolean(new Integer(null)) = null ** * @param value the Integer to convert * @return Boolean.TRUE if non-zero, Boolean.FALSE if zero, *
null
if null
input
*/
public static Boolean toBooleanObject(Integer value) {
if (value == null) {
return null;
}
return value.intValue() == 0 ? Boolean.FALSE : Boolean.TRUE;
}
/**
* Converts an int to a boolean specifying the conversion values.
* ** BooleanUtils.toBoolean(0, 1, 0) = false * BooleanUtils.toBoolean(1, 1, 0) = true * BooleanUtils.toBoolean(2, 1, 2) = false * BooleanUtils.toBoolean(2, 2, 0) = true ** * @param value the Integer to convert * @param trueValue the value to match for
true
* @param falseValue the value to match for false
* @return true
or false
* @throws IllegalArgumentException if no match
*/
public static boolean toBoolean(int value, int trueValue, int falseValue) {
if (value == trueValue) {
return true;
} else if (value == falseValue) {
return false;
}
// no match
throw new IllegalArgumentException("The Integer did not match either specified value");
}
/**
* Converts an Integer to a boolean specifying the conversion values.
* ** BooleanUtils.toBoolean(new Integer(0), new Integer(1), new Integer(0)) = false * BooleanUtils.toBoolean(new Integer(1), new Integer(1), new Integer(0)) = true * BooleanUtils.toBoolean(new Integer(2), new Integer(1), new Integer(2)) = false * BooleanUtils.toBoolean(new Integer(2), new Integer(2), new Integer(0)) = true * BooleanUtils.toBoolean(null, null, new Integer(0)) = true ** * @param value the Integer to convert * @param trueValue the value to match for
true
,
* may be null
* @param falseValue the value to match for false
,
* may be null
* @return true
or false
* @throws IllegalArgumentException if no match
*/
public static boolean toBoolean(Integer value, Integer trueValue, Integer falseValue) {
if (value == null) {
if (trueValue == null) {
return true;
} else if (falseValue == null) {
return false;
}
} else if (value.equals(trueValue)) {
return true;
} else if (value.equals(falseValue)) {
return false;
}
// no match
throw new IllegalArgumentException("The Integer did not match either specified value");
}
/**
* Converts an int to a Boolean specifying the conversion values.
* ** BooleanUtils.toBooleanObject(0, 0, 2, 3) = Boolean.TRUE * BooleanUtils.toBooleanObject(2, 1, 2, 3) = Boolean.FALSE * BooleanUtils.toBooleanObject(3, 1, 2, 3) = null ** * @param value the Integer to convert * @param trueValue the value to match for
true
* @param falseValue the value to match for false
* @param nullValue the value to to match for null
* @return Boolean.TRUE, Boolean.FALSE, or null
* @throws IllegalArgumentException if no match
*/
public static Boolean toBooleanObject(int value, int trueValue, int falseValue, int nullValue) {
if (value == trueValue) {
return Boolean.TRUE;
} else if (value == falseValue) {
return Boolean.FALSE;
} else if (value == nullValue) {
return null;
}
// no match
throw new IllegalArgumentException("The Integer did not match any specified value");
}
/**
* Converts an Integer to a Boolean specifying the conversion values.
* ** BooleanUtils.toBooleanObject(new Integer(0), new Integer(0), new Integer(2), new Integer(3)) = Boolean.TRUE * BooleanUtils.toBooleanObject(new Integer(2), new Integer(1), new Integer(2), new Integer(3)) = Boolean.FALSE * BooleanUtils.toBooleanObject(new Integer(3), new Integer(1), new Integer(2), new Integer(3)) = null ** * @param value the Integer to convert * @param trueValue the value to match for
true
,
* may be null
* @param falseValue the value to match for false
,
* may be null
* @param nullValue the value to to match for null
,
* may be null
* @return Boolean.TRUE, Boolean.FALSE, or null
* @throws IllegalArgumentException if no match
*/
public static Boolean toBooleanObject(Integer value, Integer trueValue, Integer falseValue, Integer nullValue) {
if (value == null) {
if (trueValue == null) {
return Boolean.TRUE;
} else if (falseValue == null) {
return Boolean.FALSE;
} else if (nullValue == null) {
return null;
}
} else if (value.equals(trueValue)) {
return Boolean.TRUE;
} else if (value.equals(falseValue)) {
return Boolean.FALSE;
} else if (value.equals(nullValue)) {
return null;
}
// no match
throw new IllegalArgumentException("The Integer did not match any specified value");
}
// Boolean to Integer methods
//-----------------------------------------------------------------------
/**
* Converts a boolean to an int using the convention that
* zero
is false
.
* BooleanUtils.toInteger(true) = 1 * BooleanUtils.toInteger(false) = 0 ** * @param bool the boolean to convert * @return one if
true
, zero if false
*/
public static int toInteger(boolean bool) {
return bool ? 1 : 0;
}
/**
* Converts a boolean to an Integer using the convention that
* zero
is false
.
* BooleanUtils.toIntegerObject(true) = new Integer(1) * BooleanUtils.toIntegerObject(false) = new Integer(0) ** * @param bool the boolean to convert * @return one if
true
, zero if false
*/
public static Integer toIntegerObject(boolean bool) {
return bool ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO;
}
/**
* Converts a Boolean to a Integer using the convention that
* zero
is false
.
null
will be converted to null
.
* BooleanUtils.toIntegerObject(Boolean.TRUE) = new Integer(1) * BooleanUtils.toIntegerObject(Boolean.FALSE) = new Integer(0) ** * @param bool the Boolean to convert * @return one if Boolean.TRUE, zero if Boolean.FALSE,
null
if null
*/
public static Integer toIntegerObject(Boolean bool) {
if (bool == null) {
return null;
}
return bool.booleanValue() ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO;
}
/**
* Converts a boolean to an int specifying the conversion values.
* ** BooleanUtils.toInteger(true, 1, 0) = 1 * BooleanUtils.toInteger(false, 1, 0) = 0 ** * @param bool the to convert * @param trueValue the value to return if
true
* @param falseValue the value to return if false
* @return the appropriate value
*/
public static int toInteger(boolean bool, int trueValue, int falseValue) {
return bool ? trueValue : falseValue;
}
/**
* Converts a Boolean to an int specifying the conversion values.
* ** BooleanUtils.toInteger(Boolean.TRUE, 1, 0, 2) = 1 * BooleanUtils.toInteger(Boolean.FALSE, 1, 0, 2) = 0 * BooleanUtils.toInteger(null, 1, 0, 2) = 2 ** * @param bool the Boolean to convert * @param trueValue the value to return if
true
* @param falseValue the value to return if false
* @param nullValue the value to return if null
* @return the appropriate value
*/
public static int toInteger(Boolean bool, int trueValue, int falseValue, int nullValue) {
if (bool == null) {
return nullValue;
}
return bool.booleanValue() ? trueValue : falseValue;
}
/**
* Converts a boolean to an Integer specifying the conversion values.
* ** BooleanUtils.toIntegerObject(true, new Integer(1), new Integer(0)) = new Integer(1) * BooleanUtils.toIntegerObject(false, new Integer(1), new Integer(0)) = new Integer(0) ** * @param bool the to convert * @param trueValue the value to return if
true
,
* may be null
* @param falseValue the value to return if false
,
* may be null
* @return the appropriate value
*/
public static Integer toIntegerObject(boolean bool, Integer trueValue, Integer falseValue) {
return bool ? trueValue : falseValue;
}
/**
* Converts a Boolean to an Integer specifying the conversion values.
* ** BooleanUtils.toIntegerObject(Boolean.TRUE, new Integer(1), new Integer(0), new Integer(2)) = new Integer(1) * BooleanUtils.toIntegerObject(Boolean.FALSE, new Integer(1), new Integer(0), new Integer(2)) = new Integer(0) * BooleanUtils.toIntegerObject(null, new Integer(1), new Integer(0), new Integer(2)) = new Integer(2) ** * @param bool the Boolean to convert * @param trueValue the value to return if
true
,
* may be null
* @param falseValue the value to return if false
,
* may be null
* @param nullValue the value to return if null
,
* may be null
* @return the appropriate value
*/
public static Integer toIntegerObject(Boolean bool, Integer trueValue, Integer falseValue, Integer nullValue) {
if (bool == null) {
return nullValue;
}
return bool.booleanValue() ? trueValue : falseValue;
}
// String to Boolean methods
//-----------------------------------------------------------------------
/**
* Converts a String to a Boolean.
* *'true'
, 'on'
or 'yes'
* (case insensitive) will return true
.
* 'false'
, 'off'
or 'no'
* (case insensitive) will return false
.
* Otherwise, null
is returned.
* BooleanUtils.toBooleanObject(null) = null * BooleanUtils.toBooleanObject("true") = Boolean.TRUE * BooleanUtils.toBooleanObject("false") = Boolean.FALSE * BooleanUtils.toBooleanObject("on") = Boolean.TRUE * BooleanUtils.toBooleanObject("ON") = Boolean.TRUE * BooleanUtils.toBooleanObject("off") = Boolean.FALSE * BooleanUtils.toBooleanObject("oFf") = Boolean.FALSE * BooleanUtils.toBooleanObject("blue") = null ** * @param str the String to check * @return the Boolean value of the string, *
null
if no match or null
input
*/
public static Boolean toBooleanObject(String str) {
// Previously used equalsIgnoreCase, which was fast for interned 'true'.
// Non interned 'true' matched 15 times slower.
//
// Optimisation provides same performance as before for interned 'true'.
// Similar performance for null, 'false', and other strings not length 2/3/4.
// 'true'/'TRUE' match 4 times slower, 'tRUE'/'True' 7 times slower.
if (str == "true") {
return Boolean.TRUE;
}
if (str == null) {
return null;
}
switch (str.length()) {
case 1: {
char ch0 = str.charAt(0);
if ((ch0 == 'y' || ch0 == 'Y') ||
(ch0 == 't' || ch0 == 'T'))
{
return Boolean.TRUE;
}
if ((ch0 == 'n' || ch0 == 'N') ||
(ch0 == 'f' || ch0 == 'F'))
{
return Boolean.FALSE;
}
break;
}
case 2: {
char ch0 = str.charAt(0);
char ch1 = str.charAt(1);
if ((ch0 == 'o' || ch0 == 'O') &&
(ch1 == 'n' || ch1 == 'N') )
{
return Boolean.TRUE;
}
if ((ch0 == 'n' || ch0 == 'N') &&
(ch1 == 'o' || ch1 == 'O') )
{
return Boolean.FALSE;
}
break;
}
case 3: {
char ch0 = str.charAt(0);
char ch1 = str.charAt(1);
char ch2 = str.charAt(2);
if ((ch0 == 'y' || ch0 == 'Y') &&
(ch1 == 'e' || ch1 == 'E') &&
(ch2 == 's' || ch2 == 'S') )
{
return Boolean.TRUE;
}
if ((ch0 == 'o' || ch0 == 'O') &&
(ch1 == 'f' || ch1 == 'F') &&
(ch2 == 'f' || ch2 == 'F') )
{
return Boolean.FALSE;
}
break;
}
case 4: {
char ch0 = str.charAt(0);
char ch1 = str.charAt(1);
char ch2 = str.charAt(2);
char ch3 = str.charAt(3);
if ((ch0 == 't' || ch0 == 'T') &&
(ch1 == 'r' || ch1 == 'R') &&
(ch2 == 'u' || ch2 == 'U') &&
(ch3 == 'e' || ch3 == 'E') )
{
return Boolean.TRUE;
}
break;
}
case 5: {
char ch0 = str.charAt(0);
char ch1 = str.charAt(1);
char ch2 = str.charAt(2);
char ch3 = str.charAt(3);
char ch4 = str.charAt(4);
if ((ch0 == 'f' || ch0 == 'F') &&
(ch1 == 'a' || ch1 == 'A') &&
(ch2 == 'l' || ch2 == 'L') &&
(ch3 == 's' || ch3 == 'S') &&
(ch4 == 'e' || ch4 == 'E') )
{
return Boolean.FALSE;
}
break;
}
}
return null;
}
/**
* Converts a String to a Boolean throwing an exception if no match.
* ** BooleanUtils.toBooleanObject("true", "true", "false", "null") = Boolean.TRUE * BooleanUtils.toBooleanObject("false", "true", "false", "null") = Boolean.FALSE * BooleanUtils.toBooleanObject("null", "true", "false", "null") = null ** * @param str the String to check * @param trueString the String to match for
true
* (case sensitive), may be null
* @param falseString the String to match for false
* (case sensitive), may be null
* @param nullString the String to match for null
* (case sensitive), may be null
* @return the Boolean value of the string,
* null
if either the String matches nullString
* or if null
input and nullString
is
* null
* @throws IllegalArgumentException if the String doesn't match
*/
public static Boolean toBooleanObject(String str, String trueString, String falseString, String nullString) {
if (str == null) {
if (trueString == null) {
return Boolean.TRUE;
} else if (falseString == null) {
return Boolean.FALSE;
} else if (nullString == null) {
return null;
}
} else if (str.equals(trueString)) {
return Boolean.TRUE;
} else if (str.equals(falseString)) {
return Boolean.FALSE;
} else if (str.equals(nullString)) {
return null;
}
// no match
throw new IllegalArgumentException("The String did not match any specified value");
}
// String to boolean methods
//-----------------------------------------------------------------------
/**
* Converts a String to a boolean (optimised for performance).
* *'true'
, 'on'
or 'yes'
* (case insensitive) will return true
. Otherwise,
* false
is returned.
This method performs 4 times faster (JDK1.4) than
* Boolean.valueOf(String)
. However, this method accepts
* 'on' and 'yes' as true values.
*
*
* BooleanUtils.toBoolean(null) = false * BooleanUtils.toBoolean("true") = true * BooleanUtils.toBoolean("TRUE") = true * BooleanUtils.toBoolean("tRUe") = true * BooleanUtils.toBoolean("on") = true * BooleanUtils.toBoolean("yes") = true * BooleanUtils.toBoolean("false") = false * BooleanUtils.toBoolean("x gti") = false ** * @param str the String to check * @return the boolean value of the string,
false
if no match or the String is null
*/
public static boolean toBoolean(String str) {
return toBoolean(toBooleanObject(str));
}
/**
* Converts a String to a Boolean throwing an exception if no match found.
* *null is returned if there is no match.
* ** BooleanUtils.toBoolean("true", "true", "false") = true * BooleanUtils.toBoolean("false", "true", "false") = false ** * @param str the String to check * @param trueString the String to match for
true
* (case sensitive), may be null
* @param falseString the String to match for false
* (case sensitive), may be null
* @return the boolean value of the string
* @throws IllegalArgumentException if the String doesn't match
*/
public static boolean toBoolean(String str, String trueString, String falseString) {
if (str == null) {
if (trueString == null) {
return true;
} else if (falseString == null) {
return false;
}
} else if (str.equals(trueString)) {
return true;
} else if (str.equals(falseString)) {
return false;
}
// no match
throw new IllegalArgumentException("The String did not match either specified value");
}
// Boolean to String methods
//-----------------------------------------------------------------------
/**
* Converts a Boolean to a String returning 'true'
,
* 'false'
, or null
.
* BooleanUtils.toStringTrueFalse(Boolean.TRUE) = "true" * BooleanUtils.toStringTrueFalse(Boolean.FALSE) = "false" * BooleanUtils.toStringTrueFalse(null) = null; ** * @param bool the Boolean to check * @return
'true'
, 'false'
,
* or null
*/
public static String toStringTrueFalse(Boolean bool) {
return toString(bool, "true", "false", null);
}
/**
* Converts a Boolean to a String returning 'on'
,
* 'off'
, or null
.
* BooleanUtils.toStringOnOff(Boolean.TRUE) = "on" * BooleanUtils.toStringOnOff(Boolean.FALSE) = "off" * BooleanUtils.toStringOnOff(null) = null; ** * @param bool the Boolean to check * @return
'on'
, 'off'
,
* or null
*/
public static String toStringOnOff(Boolean bool) {
return toString(bool, "on", "off", null);
}
/**
* Converts a Boolean to a String returning 'yes'
,
* 'no'
, or null
.
* BooleanUtils.toStringYesNo(Boolean.TRUE) = "yes" * BooleanUtils.toStringYesNo(Boolean.FALSE) = "no" * BooleanUtils.toStringYesNo(null) = null; ** * @param bool the Boolean to check * @return
'yes'
, 'no'
,
* or null
*/
public static String toStringYesNo(Boolean bool) {
return toString(bool, "yes", "no", null);
}
/**
* Converts a Boolean to a String returning one of the input Strings.
* ** BooleanUtils.toString(Boolean.TRUE, "true", "false", null) = "true" * BooleanUtils.toString(Boolean.FALSE, "true", "false", null) = "false" * BooleanUtils.toString(null, "true", "false", null) = null; ** * @param bool the Boolean to check * @param trueString the String to return if
true
,
* may be null
* @param falseString the String to return if false
,
* may be null
* @param nullString the String to return if null
,
* may be null
* @return one of the three input Strings
*/
public static String toString(Boolean bool, String trueString, String falseString, String nullString) {
if (bool == null) {
return nullString;
}
return bool.booleanValue() ? trueString : falseString;
}
// boolean to String methods
//-----------------------------------------------------------------------
/**
* Converts a boolean to a String returning 'true'
* or 'false'
.
* BooleanUtils.toStringTrueFalse(true) = "true" * BooleanUtils.toStringTrueFalse(false) = "false" ** * @param bool the Boolean to check * @return
'true'
, 'false'
,
* or null
*/
public static String toStringTrueFalse(boolean bool) {
return toString(bool, "true", "false");
}
/**
* Converts a boolean to a String returning 'on'
* or 'off'
.
* BooleanUtils.toStringOnOff(true) = "on" * BooleanUtils.toStringOnOff(false) = "off" ** * @param bool the Boolean to check * @return
'on'
, 'off'
,
* or null
*/
public static String toStringOnOff(boolean bool) {
return toString(bool, "on", "off");
}
/**
* Converts a boolean to a String returning 'yes'
* or 'no'
.
* BooleanUtils.toStringYesNo(true) = "yes" * BooleanUtils.toStringYesNo(false) = "no" ** * @param bool the Boolean to check * @return
'yes'
, 'no'
,
* or null
*/
public static String toStringYesNo(boolean bool) {
return toString(bool, "yes", "no");
}
/**
* Converts a boolean to a String returning one of the input Strings.
* ** BooleanUtils.toString(true, "true", "false") = "true" * BooleanUtils.toString(false, "true", "false") = "false" ** * @param bool the Boolean to check * @param trueString the String to return if
true
,
* may be null
* @param falseString the String to return if false
,
* may be null
* @return one of the two input Strings
*/
public static String toString(boolean bool, String trueString, String falseString) {
return bool ? trueString : falseString;
}
// xor methods
// ----------------------------------------------------------------------
/**
* Performs an xor on a set of booleans.
* ** BooleanUtils.xor(new boolean[] { true, true }) = false * BooleanUtils.xor(new boolean[] { false, false }) = false * BooleanUtils.xor(new boolean[] { true, false }) = true ** * @param array an array of
booleans
* @return true
if the xor is successful.
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty.
*/
public static boolean xor(boolean[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array is empty");
}
// Loops through array, comparing each item
int trueCount = 0;
for (int i = 0; i < array.length; i++) {
// If item is true, and trueCount is < 1, increments count
// Else, xor fails
if (array[i]) {
if (trueCount < 1) {
trueCount++;
} else {
return false;
}
}
}
// Returns true if there was exactly 1 true item
return trueCount == 1;
}
/**
* Performs an xor on an array of Booleans.
*
*
* BooleanUtils.xor(new Boolean[] { Boolean.TRUE, Boolean.TRUE }) = Boolean.FALSE
* BooleanUtils.xor(new Boolean[] { Boolean.FALSE, Boolean.FALSE }) = Boolean.FALSE
* BooleanUtils.xor(new Boolean[] { Boolean.TRUE, Boolean.FALSE }) = Boolean.TRUE
*
*
* @param array an array of Booleans
* @return true
if the xor is successful.
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty.
* @throws IllegalArgumentException if array
contains a null
*/
public static Boolean xor(Boolean[] array) {
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array is empty");
}
boolean[] primitive = null;
try {
primitive = ArrayUtils.toPrimitive(array);
} catch (NullPointerException ex) {
throw new IllegalArgumentException("The array must not contain any null elements");
}
return xor(primitive) ? Boolean.TRUE : Boolean.FALSE;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/builder/CompareToBuilder.java 100644 0 0 114345 11513702444 26471 0 ustar 0 0 /*
* 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.lang.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.lang.ArrayUtils;
import org.apache.commons.lang.math.NumberUtils;
/**
* 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
* @author Apache Software Foundation
* @author Steve Downey
* @author Gary Gregory
* @author Pete Gieser
* @since 1.0
* @version $Id: CompareToBuilder.java 1056843 2011-01-09 00:29:01Z niallp $
*/
public class CompareToBuilder {
/**
* Current state of the comparison as appended fields are checked.
*/
private int comparison;
/**
* 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.
*/
public CompareToBuilder() {
super();
comparison = 0;
}
//-----------------------------------------------------------------------
/**
* Compares two Object
s 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.
*
*
* - Static fields will not be compared
* - Transient members will be not be compared, as they are likely derived
* fields
* - Superclass fields will be compared
*
*
* If both lhs
and rhs
are null
,
* they are considered equal.
*
* @param lhs left-hand object
* @param rhs right-hand object
* @return a negative integer, zero, or a positive integer as 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, null);
}
/**
* Compares two Object
s 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.
*
*
* - Static fields will not be compared
* - If
compareTransients
is true
,
* compares transient members. Otherwise ignores them, as they
* are likely derived fields.
* - Superclass fields will be compared
*
*
* If both lhs
and rhs
are null
,
* they are considered equal.
*
* @param lhs left-hand object
* @param rhs right-hand object
* @param compareTransients whether to compare transient fields
* @return a negative integer, zero, or a positive integer as 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, null);
}
/**
* Compares two Object
s 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.
*
*
* - Static fields will not be compared
* - If
compareTransients
is true
,
* compares transient members. Otherwise ignores them, as they
* are likely derived fields.
* - Superclass fields will be compared
*
*
* If both lhs
and rhs
are null
,
* they are considered equal.
*
* @param lhs left-hand object
* @param rhs right-hand object
* @param excludeFields Collection of String fields to exclude
* @return a negative integer, zero, or a positive integer as 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, Collection /*String*/ excludeFields) {
return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
}
/**
* Compares two Object
s 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.
*
*
* - Static fields will not be compared
* - If
compareTransients
is true
,
* compares transient members. Otherwise ignores them, as they
* are likely derived fields.
* - Superclass fields will be compared
*
*
* If both lhs
and rhs
are null
,
* they are considered equal.
*
* @param lhs left-hand object
* @param rhs right-hand object
* @param excludeFields array of fields to exclude
* @return a negative integer, zero, or a positive integer as 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 Object
s 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.
*
*
* - Static fields will not be compared
* - If the
compareTransients
is true
,
* compares transient members. Otherwise ignores them, as they
* are likely derived fields.
* - Compares superclass fields up to and including
reflectUpToClass
.
* If reflectUpToClass
is null
, compares all superclass fields.
*
*
* If both lhs
and rhs
are null
,
* they are considered equal.
*
* @param lhs left-hand object
* @param rhs right-hand object
* @param compareTransients whether to compare transient fields
* @param reflectUpToClass last superclass for which fields are compared
* @return a negative integer, zero, or a positive integer as 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.0
*/
public static int reflectionCompare(Object lhs, Object rhs, boolean compareTransients,
Class reflectUpToClass)
{
return reflectionCompare(lhs, rhs, compareTransients, reflectUpToClass, null);
}
/**
* Compares two Object
s 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.
*
*
* - Static fields will not be compared
* - If the
compareTransients
is true
,
* compares transient members. Otherwise ignores them, as they
* are likely derived fields.
* - Compares superclass fields up to and including
reflectUpToClass
.
* If reflectUpToClass
is null
, compares all superclass fields.
*
*
* If both lhs
and rhs
are null
,
* they are considered equal.
*
* @param lhs left-hand object
* @param rhs right-hand object
* @param compareTransients whether to compare transient fields
* @param reflectUpToClass last superclass for which fields are compared
* @param excludeFields fields to exclude
* @return a negative integer, zero, or a positive integer as 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,
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
.
*
* @param lhs left-hand object
* @param rhs right-hand object
* @param 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.
*
* @param superCompareTo result of calling 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 Object
s.
*
*
* - Check if
lhs == rhs
* - Check if either
lhs
or rhs
is null
,
* a null
object is less than a non-null
object
* - Check the object contents
*
*
* lhs
must either be an array or implement {@link Comparable}.
*
* @param lhs left-hand object
* @param rhs right-hand object
* @return this - used to chain append calls
* @throws ClassCastException if 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 Object
s.
*
*
* - Check if
lhs == rhs
* - Check if either
lhs
or rhs
is null
,
* a null
object is less than a non-null
object
* - Check the object contents
*
*
* If 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.
*
* @param lhs left-hand object
* @param rhs right-hand object
* @param comparator 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) {
comparison = ((Comparable) lhs).compareTo(rhs);
} else {
comparison = comparator.compare(lhs, rhs);
}
}
return this;
}
//-------------------------------------------------------------------------
/**
* Appends to the builder
the comparison of
* two long
s.
*
* @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 int
s.
*
* @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 short
s.
*
* @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 char
s.
*
* @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 byte
s.
*
* @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 double
s.
*
* This handles NaNs, Infinities, and -0.0
.
*
* It is compatible with the hash code generated by
* HashCodeBuilder
.
*
* @param lhs left-hand value
* @param rhs right-hand value
* @return this - used to chain append calls
*/
public CompareToBuilder append(double lhs, double rhs) {
if (comparison != 0) {
return this;
}
comparison = NumberUtils.compare(lhs, rhs);
return this;
}
/**
* Appends to the builder
the comparison of
* two float
s.
*
* This handles NaNs, Infinities, and -0.0
.
*
* It is compatible with the hash code generated by
* HashCodeBuilder
.
*
* @param lhs left-hand value
* @param rhs right-hand value
* @return this - used to chain append calls
*/
public CompareToBuilder append(float lhs, float rhs) {
if (comparison != 0) {
return this;
}
comparison = NumberUtils.compare(lhs, rhs);
return this;
}
/**
* Appends to the builder
the comparison of
* two booleans
s.
*
* @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.
*
*
* - Check if arrays are the same using
==
* - Check if for
null
, null
is less than non-null
* - Check array length, a short length array is less than a long length array
* - Check array contents element by element using {@link #append(Object, Object, Comparator)}
*
*
* This 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 if rhs
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.
*
*
* - Check if arrays are the same using
==
* - Check if for
null
, null
is less than non-null
* - Check array length, a short length array is less than a long length array
* - Check array contents element by element using {@link #append(Object, Object, Comparator)}
*
*
* This 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 comparator Comparator
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.
*
*
* - Check if arrays are the same using
==
* - Check if for
null
, null
is less than non-null
* - Check array length, a shorter length array is less than a longer length array
* - Check array contents element by element using {@link #append(long, long)}
*
*
* @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;
}
/**
* Appends to the builder
the deep comparison of
* two int
arrays.
*
*
* - Check if arrays are the same using
==
* - Check if for
null
, null
is less than non-null
* - Check array length, a shorter length array is less than a longer length array
* - Check array contents element by element using {@link #append(int, int)}
*
*
* @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;
}
/**
* Appends to the builder
the deep comparison of
* two short
arrays.
*
*
* - Check if arrays are the same using
==
* - Check if for
null
, null
is less than non-null
* - Check array length, a shorter length array is less than a longer length array
* - Check array contents element by element using {@link #append(short, short)}
*
*
* @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;
}
/**
* Appends to the builder
the deep comparison of
* two char
arrays.
*
*
* - Check if arrays are the same using
==
* - Check if for
null
, null
is less than non-null
* - Check array length, a shorter length array is less than a longer length array
* - Check array contents element by element using {@link #append(char, char)}
*
*
* @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;
}
/**
* Appends to the builder
the deep comparison of
* two byte
arrays.
*
*
* - Check if arrays are the same using
==
* - Check if for
null
, null
is less than non-null
* - Check array length, a shorter length array is less than a longer length array
* - Check array contents element by element using {@link #append(byte, byte)}
*
*
* @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;
}
/**
* Appends to the builder
the deep comparison of
* two double
arrays.
*
*
* - Check if arrays are the same using
==
* - Check if for
null
, null
is less than non-null
* - Check array length, a shorter length array is less than a longer length array
* - Check array contents element by element using {@link #append(double, double)}
*
*
* @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;
}
/**
* Appends to the builder
the deep comparison of
* two float
arrays.
*
*
* - Check if arrays are the same using
==
* - Check if for
null
, null
is less than non-null
* - Check array length, a shorter length array is less than a longer length array
* - Check array contents element by element using {@link #append(float, float)}
*
*
* @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;
}
/**
* Appends to the builder
the deep comparison of
* two boolean
arrays.
*
*
* - Check if arrays are the same using
==
* - Check if for
null
, null
is less than non-null
* - Check array length, a shorter length array is less than a longer length array
* - Check array contents element by element using {@link #append(boolean, boolean)}
*
*
* @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 builder
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;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/builder/EqualsBuilder.java 100644 0 0 74113 11513702444 26010 0 ustar 0 0 /*
* 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.lang.builder;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import org.apache.commons.lang.ArrayUtils;
/**
* 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);
* }
*
*
* @author Apache Software Foundation
* @author Steve Downey
* @author Gary Gregory
* @author Pete Gieser
* @author Arun Mammen Thomas
* @since 1.0
* @version $Id: EqualsBuilder.java 905707 2010-02-02 16:59:59Z niallp $
*/
public class EqualsBuilder {
/**
* If the fields tested are equals.
* The default value is true
.
*/
private boolean isEquals = true;
/**
* Constructor for EqualsBuilder.
*
* Starts off assuming that equals is true
.
* @see Object#equals(Object)
*/
public EqualsBuilder() {
// do nothing for now.
}
//-------------------------------------------------------------------------
/**
* This method uses reflection to determine if the two Object
s
* are equal.
*
* It uses 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.
*
* 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.
*
* @param lhs this
object
* @param rhs the other object
* @return true
if the two Objects have tested equals.
*/
public static boolean reflectionEquals(Object lhs, Object rhs) {
return reflectionEquals(lhs, rhs, false, null, null);
}
/**
* This method uses reflection to determine if the two Object
s
* are equal.
*
* It uses 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.
*
* 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.
*
* @param lhs 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, Collection /*String*/ excludeFields) {
return reflectionEquals(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
}
/**
* This method uses reflection to determine if the two Object
s
* are equal.
*
* It uses 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.
*
* 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.
*
* @param lhs 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);
}
/**
* This method uses reflection to determine if the two Object
s
* are equal.
*
* It uses 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.
*
* If the TestTransients parameter is set to 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
.
*
* Static fields will not be tested. Superclass fields will be included.
*
* @param lhs 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, null);
}
/**
* This method uses reflection to determine if the two Object
s
* are equal.
*
* It uses 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.
*
* If the testTransients parameter is set to 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
.
*
* 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.
*
* @param lhs 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
* @return true
if the two Objects have tested equals.
* @since 2.0
*/
public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class reflectUpToClass) {
return reflectionEquals(lhs, rhs, testTransients, reflectUpToClass, null);
}
/**
* This method uses reflection to determine if the two Object
s
* are equal.
*
* It uses 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.
*
* If the testTransients parameter is set to 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
.
*
* 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.
*
* @param lhs 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();
}
/**
* Appends the fields and values defined by the given object of the
* given Class.
*
* @param lhs the left hand object
* @param rhs the right hand object
* @param clazz the class to append details of
* @param builder the builder to append to
* @param useTransients whether to test transient fields
* @param excludeFields array of field names to exclude from testing
*/
private static void reflectionAppend(
Object lhs,
Object rhs,
Class clazz,
EqualsBuilder builder,
boolean useTransients,
String[] excludeFields) {
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (int i = 0; i < fields.length && builder.isEquals; 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");
}
}
}
}
//-------------------------------------------------------------------------
/**
* Adds the result of super.equals()
to this builder.
*
* @param superEquals the result of calling 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;
}
//-------------------------------------------------------------------------
/**
* Test if two Object
s are equal using their
* equals
method.
*
* @param lhs the left hand 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;
}
Class lhsClass = lhs.getClass();
if (!lhsClass.isArray()) {
// The simple case, not an array, just test the element
isEquals = lhs.equals(rhs);
} else if (lhs.getClass() != rhs.getClass()) {
// Here when we compare different dimensions, for example: a boolean[][] to a boolean[]
this.setEquals(false);
}
// 'Switch' on type of array, to dispatch to the correct handler
// This handles multi dimensional arrays of the same depth
else 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
append((Object[]) lhs, (Object[]) rhs);
}
return this;
}
/**
*
* Test if two long
s are equal.
*
*
* @param lhs
* the left hand 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;
}
/**
* Test if two int
s are equal.
*
* @param lhs the left hand 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;
}
/**
* Test if two short
s are equal.
*
* @param lhs the left hand 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;
}
/**
* Test if two char
s are equal.
*
* @param lhs the left hand 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;
}
/**
* Test if two byte
s are equal.
*
* @param lhs the left hand 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;
}
/**
* Test if two double
s are equal by testing that the
* pattern of bits returned by doubleToLong
are equal.
*
* This handles NaNs, Infinities, and -0.0
.
*
* It is compatible with the hash code generated by
* HashCodeBuilder
.
*
* @param lhs the left hand 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));
}
/**
* Test if two float
s are equal byt testing that the
* pattern of bits returned by doubleToLong are equal.
*
* This handles NaNs, Infinities, and -0.0
.
*
* It is compatible with the hash code generated by
* HashCodeBuilder
.
*
* @param lhs the left hand 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));
}
/**
* Test if two booleans
s are equal.
*
* @param lhs the left hand 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;
}
/**
* Performs a deep comparison of two Object
arrays.
*
* This also will be called for the top level of
* multi-dimensional, ragged, and multi-typed arrays.
*
* @param lhs the left hand 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;
}
/**
* Deep comparison of array of long
. Length and all
* values are compared.
*
* The method {@link #append(long, long)} is used.
*
* @param lhs the left hand 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;
}
/**
* Deep comparison of array of int
. Length and all
* values are compared.
*
* The method {@link #append(int, int)} is used.
*
* @param lhs the left hand 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;
}
/**
* Deep comparison of array of short
. Length and all
* values are compared.
*
* The method {@link #append(short, short)} is used.
*
* @param lhs the left hand 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;
}
/**
* Deep comparison of array of char
. Length and all
* values are compared.
*
* The method {@link #append(char, char)} is used.
*
* @param lhs the left hand 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;
}
/**
* Deep comparison of array of byte
. Length and all
* values are compared.
*
* The method {@link #append(byte, byte)} is used.
*
* @param lhs the left hand 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;
}
/**
* Deep comparison of array of double
. Length and all
* values are compared.
*
* The method {@link #append(double, double)} is used.
*
* @param lhs the left hand 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;
}
/**
* Deep comparison of array of float
. Length and all
* values are compared.
*
* The method {@link #append(float, float)} is used.
*
* @param lhs the left hand 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;
}
/**
* Deep comparison of array of boolean
. Length and all
* values are compared.
*
* The method {@link #append(boolean, boolean)} is used.
*
* @param lhs the left hand 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;
}
/**
* Returns true
if the fields that have been checked
* are all equal.
*
* @return boolean
*/
public boolean isEquals() {
return this.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;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/builder/HashCodeBuilder.java 100644 0 0 104421 11513702444 26250 0 ustar 0 0 /*
* 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.lang.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.lang.ArrayUtils;
/**
*
* Assists in implementing {@link Object#hashCode()} methods.
*
*
*
* This class enables a good 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.
*
*
*
* 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 hashCode
method. Derived fields may be
* excluded. In general, any field used in the equals
method must be used in the hashCode
* method.
*
*
*
* To use this class write code as follows:
*
*
*
* 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();
* }
* }
*
*
*
* If required, the superclass hashCode()
can be added using {@link #appendSuper}.
*
*
*
* Alternatively, there is a method that uses reflection to determine the fields to test. Because these fields are
* usually private, the method, 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.
*
*
*
* A typical invocation for this method would look like:
*
*
*
* public int hashCode() {
* return HashCodeBuilder.reflectionHashCode(this);
* }
*
*
* @author Apache Software Foundation
* @author Gary Gregory
* @author Pete Gieser
* @since 1.0
* @version $Id: HashCodeBuilder.java 1057009 2011-01-09 19:48:06Z niallp $
*/
public class HashCodeBuilder {
/**
*
* A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops.
*
*
* @since 2.3
*/
private static final ThreadLocal REGISTRY = new ThreadLocal();
/*
* N.B. we cannot store the actual objects in a HashSet, as that would use the very hashCode()
* we are in the process of calculating.
*
* So we generate a one-to-one mapping from the original object to a new object.
*
* Now HashSet uses equals() to determine if two elements with the same hashcode really
* are equal, so we also need to ensure that the replacement objects are only equal
* if the original objects are identical.
*
* The original implementation (2.4 and before) used the System.indentityHashCode()
* method - however this is not guaranteed to generate unique ids (e.g. LANG-459)
*
* We now use the IDKey helper class (adapted from org.apache.axis.utils.IDKey)
* to disambiguate the duplicate ids.
*/
/**
*
* Returns the registry of objects being traversed by the reflection methods in the current thread.
*
*
* @return Set the registry of objects being traversed
* @since 2.3
*/
static Set getRegistry() {
return (Set) REGISTRY.get();
}
/**
*
* Returns true
if the registry contains the given object. Used by the reflection methods to avoid
* infinite loops.
*
*
* @param value
* The object to lookup in the registry.
* @return boolean true
if the registry contains the given object.
* @since 2.3
*/
static boolean isRegistered(Object value) {
Set registry = getRegistry();
return registry != null && registry.contains(new IDKey(value));
}
/**
*
* Appends the fields and values defined by the given object of the given Class
.
*
*
* @param object
* the object to append details of
* @param clazz
* the class to append details of
* @param builder
* the builder to append to
* @param useTransients
* whether to use transient fields
* @param excludeFields
* Collection of String field names to exclude from use in calculation of hash code
*/
private static void reflectionAppend(Object object, Class clazz, HashCodeBuilder builder, boolean useTransients,
String[] excludeFields) {
if (isRegistered(object)) {
return;
}
try {
register(object);
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if (!ArrayUtils.contains(excludeFields, field.getName())
&& (field.getName().indexOf('$') == -1)
&& (useTransients || !Modifier.isTransient(field.getModifiers()))
&& (!Modifier.isStatic(field.getModifiers()))) {
try {
Object fieldValue = field.get(object);
builder.append(fieldValue);
} 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");
}
}
}
} finally {
unregister(object);
}
}
/**
*
* This method uses reflection to build a valid hash code.
*
*
*
* It uses 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.
*
*
*
* Transient members will be not be used, 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.
*
*
*
* 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.
*
*
* @param initialNonZeroOddNumber
* a non-zero, odd number used as the initial value
* @param multiplierNonZeroOddNumber
* a non-zero, odd number used as the multiplier
* @param object
* the Object to create a 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, null);
}
/**
*
* This method uses reflection to build a valid hash code.
*
*
*
* It uses 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.
*
*
*
* If the TestTransients parameter is set to 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
.
*
*
*
* 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.
*
*
* @param initialNonZeroOddNumber
* a non-zero, odd number used as the initial value
* @param multiplierNonZeroOddNumber
* a non-zero, odd number used as the multiplier
* @param object
* the Object to create a 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,
null);
}
/**
* Calls {@link #reflectionHashCode(int, int, Object, boolean, Class, String[])} with excludeFields set to
* null
.
*
* @param initialNonZeroOddNumber
* a non-zero, odd number used as the initial value
* @param multiplierNonZeroOddNumber
* a non-zero, odd number used as the multiplier
* @param object
* the Object to create a hashCode
for
* @param testTransients
* whether to include transient fields
* @param reflectUpToClass
* the superclass to reflect up to (inclusive), may be null
* @return int hash code
*/
public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object,
boolean testTransients, Class reflectUpToClass) {
return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients,
reflectUpToClass, null);
}
/**
*
* This method uses reflection to build a valid hash code.
*
*
*
* It uses 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.
*
*
*
* If the TestTransients parameter is set to 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
.
*
*
*
* 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.
*
*
* @param initialNonZeroOddNumber
* a non-zero, odd number used as the initial value
* @param multiplierNonZeroOddNumber
* a non-zero, odd number used as the multiplier
* @param object
* the Object to create a 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 int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object,
boolean testTransients, Class reflectUpToClass, String[] excludeFields) {
if (object == null) {
throw new IllegalArgumentException("The object to build a hash code for must not be null");
}
HashCodeBuilder builder = new HashCodeBuilder(initialNonZeroOddNumber, multiplierNonZeroOddNumber);
Class clazz = object.getClass();
reflectionAppend(object, clazz, builder, testTransients, excludeFields);
while (clazz.getSuperclass() != null && clazz != reflectUpToClass) {
clazz = clazz.getSuperclass();
reflectionAppend(object, clazz, builder, testTransients, excludeFields);
}
return builder.toHashCode();
}
/**
*
* 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 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.
*
*
*
* Transient members will be not be used, 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.
*
*
* @param object
* the Object to create a hashCode
for
* @return int hash code
* @throws IllegalArgumentException
* if the object is null
*/
public static int reflectionHashCode(Object object) {
return reflectionHashCode(17, 37, object, false, null, null);
}
/**
*
* 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 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.
*
*
*
* If the TestTransients parameter is set to 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
.
*
*
*
* Static fields will not be tested. Superclass fields will be included.
*
*
* @param object
* the Object to create a 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, null);
}
/**
*
* 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 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.
*
*
*
* Transient members will be not be used, 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.
*
*
* @param object
* the Object to create a 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, Collection /* String */excludeFields) {
return reflectionHashCode(object, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
}
// -------------------------------------------------------------------------
/**
*
* 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 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.
*
*
*
* Transient members will be not be used, 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.
*
*
* @param object
* the Object to create a 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);
}
/**
*
* Registers the given object. Used by the reflection methods to avoid infinite loops.
*
*
* @param value
* The object to register.
*/
static void register(Object value) {
synchronized (HashCodeBuilder.class) {
if (getRegistry() == null) {
REGISTRY.set(new HashSet());
}
}
getRegistry().add(new IDKey(value));
}
/**
*
* 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 registry = getRegistry();
if (registry != null) {
registry.remove(new IDKey(value));
synchronized (HashCodeBuilder.class) {
//read again
registry = getRegistry();
if (registry != null && registry.isEmpty()) {
REGISTRY.set(null);
}
}
}
}
/**
* Constant to use in building the hashCode.
*/
private final int iConstant;
/**
* Running total of the hashCode.
*/
private int iTotal = 0;
/**
*
* Uses two hard coded choices for the constants needed to build a hashCode
.
*
*/
public HashCodeBuilder() {
iConstant = 37;
iTotal = 17;
}
/**
*
* 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.
*
*
* @param initialNonZeroOddNumber
* a non-zero, odd number used as the initial value
* @param multiplierNonZeroOddNumber
* a non-zero, odd number used as the multiplier
* @throws IllegalArgumentException
* if the number is zero or even
*/
public HashCodeBuilder(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber) {
if (initialNonZeroOddNumber == 0) {
throw new IllegalArgumentException("HashCodeBuilder requires a non zero initial value");
}
if (initialNonZeroOddNumber % 2 == 0) {
throw new IllegalArgumentException("HashCodeBuilder requires an odd initial value");
}
if (multiplierNonZeroOddNumber == 0) {
throw new IllegalArgumentException("HashCodeBuilder requires a non zero multiplier");
}
if (multiplierNonZeroOddNumber % 2 == 0) {
throw new IllegalArgumentException("HashCodeBuilder requires an odd multiplier");
}
iConstant = multiplierNonZeroOddNumber;
iTotal = initialNonZeroOddNumber;
}
/**
*
* Append a hashCode
for a boolean
.
*
*
* This adds 1
when true, and 0
when false to the hashCode
.
*
*
* This is in contrast to the standard 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
.
*
*
* This is in accordance with the Effective Java
design.
*
*
* @param value
* the boolean to add to the hashCode
* @return this
*/
public HashCodeBuilder append(boolean value) {
iTotal = iTotal * iConstant + (value ? 0 : 1);
return this;
}
/**
*
* Append a hashCode
for a boolean
array.
*
*
* @param array
* the array to add to the hashCode
* @return this
*/
public HashCodeBuilder append(boolean[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (int i = 0; i < array.length; i++) {
append(array[i]);
}
}
return this;
}
// -------------------------------------------------------------------------
/**
*
* Append a hashCode
for a byte
.
*
*
* @param value
* the byte to add to the hashCode
* @return this
*/
public HashCodeBuilder append(byte value) {
iTotal = iTotal * iConstant + value;
return this;
}
// -------------------------------------------------------------------------
/**
*
* Append a hashCode
for a byte
array.
*
*
* @param array
* the array to add to the hashCode
* @return this
*/
public HashCodeBuilder append(byte[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (int i = 0; i < array.length; i++) {
append(array[i]);
}
}
return this;
}
/**
*
* Append a hashCode
for a char
.
*
*
* @param value
* the char to add to the hashCode
* @return this
*/
public HashCodeBuilder append(char value) {
iTotal = iTotal * iConstant + value;
return this;
}
/**
*
* Append a hashCode
for a char
array.
*
*
* @param array
* the array to add to the hashCode
* @return this
*/
public HashCodeBuilder append(char[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (int i = 0; i < array.length; i++) {
append(array[i]);
}
}
return this;
}
/**
*
* Append a hashCode
for a double
.
*
*
* @param value
* the double to add to the hashCode
* @return this
*/
public HashCodeBuilder append(double value) {
return append(Double.doubleToLongBits(value));
}
/**
*
* Append a hashCode
for a double
array.
*
*
* @param array
* the array to add to the hashCode
* @return this
*/
public HashCodeBuilder append(double[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (int i = 0; i < array.length; i++) {
append(array[i]);
}
}
return this;
}
/**
*
* Append a hashCode
for a float
.
*
*
* @param value
* the float to add to the hashCode
* @return this
*/
public HashCodeBuilder append(float value) {
iTotal = iTotal * iConstant + Float.floatToIntBits(value);
return this;
}
/**
*
* Append a hashCode
for a float
array.
*
*
* @param array
* the array to add to the hashCode
* @return this
*/
public HashCodeBuilder append(float[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (int i = 0; i < array.length; i++) {
append(array[i]);
}
}
return this;
}
/**
*
* Append a hashCode
for an int
.
*
*
* @param value
* the int to add to the hashCode
* @return this
*/
public HashCodeBuilder append(int value) {
iTotal = iTotal * iConstant + value;
return this;
}
/**
*
* Append a hashCode
for an int
array.
*
*
* @param array
* the array to add to the hashCode
* @return this
*/
public HashCodeBuilder append(int[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (int i = 0; i < array.length; i++) {
append(array[i]);
}
}
return this;
}
/**
*
* Append a hashCode
for a long
.
*
*
* @param value
* the long to add to the 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;
}
/**
*
* Append a hashCode
for a long
array.
*
*
* @param array
* the array to add to the hashCode
* @return this
*/
public HashCodeBuilder append(long[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (int i = 0; i < array.length; i++) {
append(array[i]);
}
}
return this;
}
/**
*
* Append a hashCode
for an Object
.
*
*
* @param object
* the Object to add to the 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;
}
/**
*
* Append a hashCode
for an Object
array.
*
*
* @param array
* the array to add to the hashCode
* @return this
*/
public HashCodeBuilder append(Object[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (int i = 0; i < array.length; i++) {
append(array[i]);
}
}
return this;
}
/**
*
* Append a hashCode
for a short
.
*
*
* @param value
* the short to add to the hashCode
* @return this
*/
public HashCodeBuilder append(short value) {
iTotal = iTotal * iConstant + value;
return this;
}
/**
*
* Append a hashCode
for a short
array.
*
*
* @param array
* the array to add to the hashCode
* @return this
*/
public HashCodeBuilder append(short[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (int i = 0; i < array.length; i++) {
append(array[i]);
}
}
return this;
}
/**
*
* Adds the result of super.hashCode() to this builder.
*
*
* @param superHashCode
* the result of calling super.hashCode()
* @return this HashCodeBuilder, used to chain calls.
* @since 2.0
*/
public HashCodeBuilder appendSuper(int superHashCode) {
iTotal = iTotal * iConstant + superHashCode;
return this;
}
/**
*
* Return the computed hashCode
.
*
*
* @return hashCode
based on the fields appended
*/
public int toHashCode() {
return iTotal;
}
/**
*
* The computed hashCode
from toHashCode() is returned due to the likelyhood
* of bugs in mis-calling toHashCode() and the unlikelyness of it mattering what the hashCode for
* HashCodeBuilder itself is.
*
* @return hashCode
based on the fields appended
* @since 2.5
*/
public int hashCode() {
return toHashCode();
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/builder/IDKey.java 100644 0 0 4714 11513702444 24174 0 ustar 0 0 /*
* 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.lang.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.
*
* @author Apache Software Foundation
*/
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
*/
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
*/
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;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/builder/package.html 100644 0 0 2231 11513702444 24635 0 ustar 0 0
Assists in creating consistent equals(Object)
, toString()
,
hashCode()
, and compareTo(Object)
methods.
@see java.lang.Object#equals(Object)
@see java.lang.Object#toString()
@see java.lang.Object#hashCode()
@see java.lang.Comparable#compareTo(Object)
@since 1.0
These classes are not thread-safe.
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/builder/ReflectionToStringBuilder.java 100644 0 0 65601 11513702444 30344 0 ustar 0 0 /*
* 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.lang.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 org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.ClassUtils;
/**
*
* 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:
*
*
*
* public String toString() {
* return ReflectionToStringBuilder.toString(this);
* }
*
*
*
*
* You can also use the builder to debug 3rd party objects:
*
*
*
* System.out.println("An object: " + ReflectionToStringBuilder.toString(anObject));
*
*
*
*
* A subclass can control field output by overriding the methods:
*
* - {@link #accept(java.lang.reflect.Field)}
* - {@link #getValue(java.lang.reflect.Field)}
*
*
*
* For example, this method does not include the 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();
* }
*
*
*
*
* The exact format of the toString
is determined by the {@link ToStringStyle} passed into the
* constructor.
*
*
* @author Apache Software Foundation
* @author Gary Gregory
* @author Pete Gieser
* @since 2.0
* @version $Id: ReflectionToStringBuilder.java 905636 2010-02-02 14:03:32Z niallp $
*/
public class ReflectionToStringBuilder extends ToStringBuilder {
/**
*
* Builds a toString
value using the default ToStringStyle
through reflection.
*
*
*
* It uses 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.
*
*
*
* Transient members will be not be included, as they are likely derived. Static fields will not be included.
* Superclass fields will be appended.
*
*
* @param object
* the Object to be output
* @return the String result
* @throws IllegalArgumentException
* if the Object is null
*/
public static String toString(Object object) {
return toString(object, null, false, false, null);
}
/**
*
* Builds a toString
value through reflection.
*
*
*
* It uses 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.
*
*
*
* 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 null
, the default ToStringStyle
is used.
*
*
* @param object
* the Object to be output
* @param style
* the style of the 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);
}
/**
*
* Builds a toString
value through reflection.
*
*
*
* It uses 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.
*
*
*
* If the 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.
*
*
*
* Static fields will not be included. Superclass fields will be appended.
*
*
*
* If the style is null
, the default ToStringStyle
is used.
*
*
* @param object
* the Object to be output
* @param style
* the style of the 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);
}
/**
*
* Builds a toString
value through reflection.
*
*
*
* It uses 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.
*
*
*
* If the 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.
*
*
*
* If the outputStatics
is true
, static fields will be output, otherwise they are
* ignored.
*
*
*
* Static fields will not be included. Superclass fields will be appended.
*
*
*
* If the style is null
, the default ToStringStyle
is used.
*
*
* @param object
* the Object to be output
* @param style
* the style of the 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);
}
/**
*
* Builds a toString
value through reflection.
*
*
*
* It uses 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.
*
*
*
* If the 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.
*
*
*
* If the outputStatics
is true
, static fields will be output, otherwise they are
* ignored.
*
*
*
* Superclass fields will be appended up to and including the specified superclass. A null superclass is treated as
* java.lang.Object
.
*
*
*
* If the style is null
, the default ToStringStyle
is used.
*
*
* @param object
* the Object to be output
* @param style
* the style of the 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 String toString(Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics,
Class reflectUpToClass) {
return new ReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients, outputStatics)
.toString();
}
/**
*
* Builds a toString
value through reflection.
*
*
*
* It uses 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.
*
*
*
* If the 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.
*
*
*
* 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
.
*
*
*
* If the style is null
, the default ToStringStyle
is used.
*
*
* @deprecated Use {@link #toString(Object,ToStringStyle,boolean,boolean,Class)}
*
* @param object
* the Object to be output
* @param style
* the style of the 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
* @throws IllegalArgumentException
* if the Object is null
* @since 2.0
*/
public static String toString(Object object, ToStringStyle style,
boolean outputTransients, Class reflectUpToClass)
{
return new ReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients).toString();
}
/**
* Builds a String for a toString method excluding the given field name.
*
* @param object
* The object to "toString".
* @param excludeFieldName
* The field name to exclude
* @return The toString value.
*/
public static String toStringExclude(Object object, final String excludeFieldName) {
return toStringExclude(object, new String[]{excludeFieldName});
}
/**
* Builds a String for a toString method excluding the given field names.
*
* @param object
* The object to "toString".
* @param excludeFieldNames
* The field names to exclude. Null excludes nothing.
* @return The toString value.
*/
public static String toStringExclude(Object object, Collection /*String*/ excludeFieldNames) {
return toStringExclude(object, toNoNullStringArray(excludeFieldNames));
}
/**
* Converts the given Collection into an array of Strings. The returned array does not contain 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(Collection collection) {
if (collection == null) {
return ArrayUtils.EMPTY_STRING_ARRAY;
}
return toNoNullStringArray(collection.toArray());
}
/**
* Returns a new array of Strings without null elements. Internal method used to normalize exclude lists
* (arrays and collections). Note that {@link Arrays#sort(Object[])} will throw an {@link NullPointerException}
* if an array element is null
.
*
* @param array
* The array to check
* @return The given array or a new array without null.
*/
static String[] toNoNullStringArray(Object[] array) {
ArrayList list = new ArrayList(array.length);
for (int i = 0; i < array.length; i++) {
Object e = array[i];
if (e != null) {
list.add(e.toString());
}
}
return (String[]) list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
}
/**
* Builds a String for a toString method excluding the given field names.
*
* @param object
* The object to "toString".
* @param excludeFieldNames
* The field names to exclude
* @return The toString value.
*/
public static String toStringExclude(Object object, String[] excludeFieldNames) {
return new ReflectionToStringBuilder(object).setExcludeFieldNames(excludeFieldNames).toString();
}
/**
* Whether or not to append static fields.
*/
private boolean appendStatics = false;
/**
* Whether or not to append transient fields.
*/
private boolean appendTransients = false;
/**
* Which field names to exclude from output. Intended for fields like "password"
.
*/
private String[] excludeFieldNames;
/**
* The last super class to stop appending fields for.
*/
private Class upToClass = null;
/**
*
* Constructor.
*
*
*
* This constructor outputs using the default style set with setDefaultStyle
.
*
*
* @param object
* the Object to build a toString
for, must not be null
* @throws IllegalArgumentException
* if the Object passed in is null
*/
public ReflectionToStringBuilder(Object object) {
super(object);
}
/**
*
* Constructor.
*
*
*
* If the style is null
, the default style is used.
*
*
* @param object
* the Object to build a 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);
}
/**
*
* Constructor.
*
*
*
* If the style is null
, the default style is used.
*
*
*
* If the buffer is null
, a new one is created.
*
*
* @param object
* the Object to build a 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.
*
* @deprecated Use {@link #ReflectionToStringBuilder(Object,ToStringStyle,StringBuffer,Class,boolean,boolean)}.
*
* @param object
* the Object to build a 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
*/
public ReflectionToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer, Class reflectUpToClass,
boolean outputTransients) {
super(object, style, buffer);
this.setUpToClass(reflectUpToClass);
this.setAppendTransients(outputTransients);
}
/**
* Constructor.
*
* @param object
* the Object to build a 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 ReflectionToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer, Class reflectUpToClass,
boolean outputTransients, boolean outputStatics) {
super(object, style, buffer);
this.setUpToClass(reflectUpToClass);
this.setAppendTransients(outputTransients);
this.setAppendStatics(outputStatics);
}
/**
* Returns whether or not to append the given Field
.
*
* - Transient fields are appended only if {@link #isAppendTransients()} returns
true
.
* - Static fields are appended only if {@link #isAppendStatics()} returns
true
.
* - Inner class fields are not appened.
*
*
* @param field
* The Field to test.
* @return Whether or not to append the given 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.getExcludeFieldNames() != null
&& Arrays.binarySearch(this.getExcludeFieldNames(), field.getName()) >= 0) {
// Reject fields from the getExcludeFieldNames list.
return false;
}
return true;
}
/**
*
* 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
* Object.toString()
had been called and not implemented by the object.
*
*
* @param clazz
* The class of object parameter
*/
protected void appendFieldsIn(Class clazz) {
if (clazz.isArray()) {
this.reflectionAppendArray(this.getObject());
return;
}
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
String fieldName = field.getName();
if (this.accept(field)) {
try {
// Warning: Field.get(Object) creates wrappers objects
// for primitive types.
Object fieldValue = this.getValue(field);
this.append(fieldName, fieldValue);
} catch (IllegalAccessException ex) {
//this can't happen. Would get a Security exception
// instead
//throw a runtime exception in case the impossible
// happens.
throw new InternalError("Unexpected IllegalAccessException: " + ex.getMessage());
}
}
}
}
/**
* @return Returns the excludeFieldNames.
*/
public String[] getExcludeFieldNames() {
return this.excludeFieldNames;
}
/**
*
* Gets the last super class to stop appending fields for.
*
*
* @return The last super class to stop appending fields for.
*/
public Class getUpToClass() {
return this.upToClass;
}
/**
*
* Calls java.lang.reflect.Field.get(Object)
.
*
*
* @param field
* The Field to query.
* @return The Object from the given Field.
*
* @throws IllegalArgumentException
* see {@link java.lang.reflect.Field#get(Object)}
* @throws IllegalAccessException
* see {@link java.lang.reflect.Field#get(Object)}
*
* @see java.lang.reflect.Field#get(Object)
*/
protected Object getValue(Field field) throws IllegalArgumentException, IllegalAccessException {
return field.get(this.getObject());
}
/**
*
* Gets whether or not to append static fields.
*
*
* @return Whether or not to append static fields.
* @since 2.1
*/
public boolean isAppendStatics() {
return this.appendStatics;
}
/**
*
* Gets whether or not to append transient fields.
*
*
* @return Whether or not to append transient fields.
*/
public boolean isAppendTransients() {
return this.appendTransients;
}
/**
*
* Append to the toString
an Object
array.
*
*
* @param array
* the array to add to the toString
* @return this
*/
public ToStringBuilder reflectionAppendArray(Object array) {
this.getStyle().reflectionAppendArrayDetail(this.getStringBuffer(), null, array);
return this;
}
/**
*
* Sets whether or not to append static fields.
*
*
* @param appendStatics
* Whether or not to append static fields.
* @since 2.1
*/
public void setAppendStatics(boolean appendStatics) {
this.appendStatics = appendStatics;
}
/**
*
* Sets whether or not to append transient fields.
*
*
* @param appendTransients
* Whether or not to append transient fields.
*/
public void setAppendTransients(boolean appendTransients) {
this.appendTransients = appendTransients;
}
/**
* Sets the field names to exclude.
*
* @param excludeFieldNamesParam
* The excludeFieldNames to excluding from toString or null
.
* @return this
*/
public ReflectionToStringBuilder setExcludeFieldNames(String[] excludeFieldNamesParam) {
if (excludeFieldNamesParam == null) {
this.excludeFieldNames = null;
} else {
this.excludeFieldNames = toNoNullStringArray(excludeFieldNamesParam);
Arrays.sort(this.excludeFieldNames);
}
return this;
}
/**
*
* Sets the last super class to stop appending fields for.
*
*
* @param clazz
* The last super class to stop appending fields for.
*/
public void setUpToClass(Class clazz) {
if (clazz != null) {
Object object = getObject();
if (object != null && clazz.isInstance(object) == false) {
throw new IllegalArgumentException("Specified class is not a superclass of the object");
}
}
this.upToClass = clazz;
}
/**
*
* Gets the String built by this builder.
*
*
* @return the built string
*/
public String toString() {
if (this.getObject() == null) {
return this.getStyle().getNullText();
}
Class clazz = this.getObject().getClass();
this.appendFieldsIn(clazz);
while (clazz.getSuperclass() != null && clazz != this.getUpToClass()) {
clazz = clazz.getSuperclass();
this.appendFieldsIn(clazz);
}
return super.toString();
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/builder/StandardToStringStyle.java 100644 0 0 40464 11513702444 27524 0 ustar 0 0 /*
* 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.lang.builder;
/**
* Works with {@link ToStringBuilder} to create a toString
.
*
* 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.
*
* @author Apache Software Foundation
* @author Pete Gieser
* @author Gary Gregory
* @since 1.0
* @version $Id: StandardToStringStyle.java 905636 2010-02-02 14:03:32Z niallp $
*/
public class StandardToStringStyle extends ToStringStyle {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 1L;
/**
* Constructor.
*/
public StandardToStringStyle() {
super();
}
//---------------------------------------------------------------------
/**
* Gets whether to use the class name.
*
* @return the current useClassName flag
*/
public boolean isUseClassName() {
return super.isUseClassName();
}
/**
* Sets whether to use the class name.
*
* @param useClassName the new useClassName flag
*/
public void setUseClassName(boolean useClassName) {
super.setUseClassName(useClassName);
}
//---------------------------------------------------------------------
/**
* Gets whether to output short or long class names.
*
* @return the current useShortClassName flag
* @since 2.0
*/
public boolean isUseShortClassName() {
return super.isUseShortClassName();
}
/**
* Gets whether to output short or long class names.
*
* @return the current shortClassName flag
* @deprecated Use {@link #isUseShortClassName()}
* Method will be removed in Commons Lang 3.0.
*/
public boolean isShortClassName() {
return super.isUseShortClassName();
}
/**
* Sets whether to output short or long class names.
*
* @param useShortClassName the new useShortClassName flag
* @since 2.0
*/
public void setUseShortClassName(boolean useShortClassName) {
super.setUseShortClassName(useShortClassName);
}
/**
* Sets whether to output short or long class names.
*
* @param shortClassName the new shortClassName flag
* @deprecated Use {@link #setUseShortClassName(boolean)}
* Method will be removed in Commons Lang 3.0.
*/
public void setShortClassName(boolean shortClassName) {
super.setUseShortClassName(shortClassName);
}
//---------------------------------------------------------------------
/**
* Gets whether to use the identity hash code.
* @return the current useIdentityHashCode flag
*/
public boolean isUseIdentityHashCode() {
return super.isUseIdentityHashCode();
}
/**
* Sets whether to use the identity hash code.
*
* @param useIdentityHashCode the new useIdentityHashCode flag
*/
public void setUseIdentityHashCode(boolean useIdentityHashCode) {
super.setUseIdentityHashCode(useIdentityHashCode);
}
//---------------------------------------------------------------------
/**
* Gets whether to use the field names passed in.
*
* @return the current useFieldNames flag
*/
public boolean isUseFieldNames() {
return super.isUseFieldNames();
}
/**
* Sets whether to use the field names passed in.
*
* @param useFieldNames the new useFieldNames flag
*/
public void setUseFieldNames(boolean useFieldNames) {
super.setUseFieldNames(useFieldNames);
}
//---------------------------------------------------------------------
/**
* Gets whether to use full detail when the caller doesn't
* specify.
*
* @return the current defaultFullDetail flag
*/
public boolean isDefaultFullDetail() {
return super.isDefaultFullDetail();
}
/**
* Sets whether to use full detail when the caller doesn't
* specify.
*
* @param defaultFullDetail the new defaultFullDetail flag
*/
public void setDefaultFullDetail(boolean defaultFullDetail) {
super.setDefaultFullDetail(defaultFullDetail);
}
//---------------------------------------------------------------------
/**
* Gets whether to output array content detail.
*
* @return the current array content detail setting
*/
public boolean isArrayContentDetail() {
return super.isArrayContentDetail();
}
/**
* Sets whether to output array content detail.
*
* @param arrayContentDetail the new arrayContentDetail flag
*/
public void setArrayContentDetail(boolean arrayContentDetail) {
super.setArrayContentDetail(arrayContentDetail);
}
//---------------------------------------------------------------------
/**
* Gets the array start text.
*
* @return the current array start text
*/
public String getArrayStart() {
return super.getArrayStart();
}
/**
* Sets the array start text.
*
* null
is accepted, but will be converted
* to an empty String.
*
* @param arrayStart the new array start text
*/
public void setArrayStart(String arrayStart) {
super.setArrayStart(arrayStart);
}
//---------------------------------------------------------------------
/**
* Gets the array end text.
*
* @return the current array end text
*/
public String getArrayEnd() {
return super.getArrayEnd();
}
/**
* Sets the array end text.
*
* null
is accepted, but will be converted
* to an empty String.
*
* @param arrayEnd the new array end text
*/
public void setArrayEnd(String arrayEnd) {
super.setArrayEnd(arrayEnd);
}
//---------------------------------------------------------------------
/**
* Gets the array separator text.
*
* @return the current array separator text
*/
public String getArraySeparator() {
return super.getArraySeparator();
}
/**
* Sets the array separator text.
*
* null
is accepted, but will be converted
* to an empty String.
*
* @param arraySeparator the new array separator text
*/
public void setArraySeparator(String arraySeparator) {
super.setArraySeparator(arraySeparator);
}
//---------------------------------------------------------------------
/**
* Gets the content start text.
*
* @return the current content start text
*/
public String getContentStart() {
return super.getContentStart();
}
/**
* Sets the content start text.
*
* null
is accepted, but will be converted
* to an empty String.
*
* @param contentStart the new content start text
*/
public void setContentStart(String contentStart) {
super.setContentStart(contentStart);
}
//---------------------------------------------------------------------
/**
* Gets the content end text.
*
* @return the current content end text
*/
public String getContentEnd() {
return super.getContentEnd();
}
/**
* Sets the content end text.
*
* null
is accepted, but will be converted
* to an empty String.
*
* @param contentEnd the new content end text
*/
public void setContentEnd(String contentEnd) {
super.setContentEnd(contentEnd);
}
//---------------------------------------------------------------------
/**
* Gets the field name value separator text.
*
* @return the current field name value separator text
*/
public String getFieldNameValueSeparator() {
return super.getFieldNameValueSeparator();
}
/**
* Sets the field name value separator text.
*
* null
is accepted, but will be converted
* to an empty String.
*
* @param fieldNameValueSeparator the new field name value separator text
*/
public void setFieldNameValueSeparator(String fieldNameValueSeparator) {
super.setFieldNameValueSeparator(fieldNameValueSeparator);
}
//---------------------------------------------------------------------
/**
* Gets the field separator text.
*
* @return the current field separator text
*/
public String getFieldSeparator() {
return super.getFieldSeparator();
}
/**
* Sets the field separator text.
*
* null
is accepted, but will be converted
* to an empty String.
*
* @param fieldSeparator the new field separator text
*/
public void setFieldSeparator(String fieldSeparator) {
super.setFieldSeparator(fieldSeparator);
}
//---------------------------------------------------------------------
/**
* Gets whether the field separator should be added at the start
* of each buffer.
*
* @return the fieldSeparatorAtStart flag
* @since 2.0
*/
public boolean isFieldSeparatorAtStart() {
return super.isFieldSeparatorAtStart();
}
/**
* Sets whether the field separator should be added at the start
* of each buffer.
*
* @param fieldSeparatorAtStart the fieldSeparatorAtStart flag
* @since 2.0
*/
public void setFieldSeparatorAtStart(boolean fieldSeparatorAtStart) {
super.setFieldSeparatorAtStart(fieldSeparatorAtStart);
}
//---------------------------------------------------------------------
/**
* Gets whether the field separator should be added at the end
* of each buffer.
*
* @return fieldSeparatorAtEnd flag
* @since 2.0
*/
public boolean isFieldSeparatorAtEnd() {
return super.isFieldSeparatorAtEnd();
}
/**
* Sets whether the field separator should be added at the end
* of each buffer.
*
* @param fieldSeparatorAtEnd the fieldSeparatorAtEnd flag
* @since 2.0
*/
public void setFieldSeparatorAtEnd(boolean fieldSeparatorAtEnd) {
super.setFieldSeparatorAtEnd(fieldSeparatorAtEnd);
}
//---------------------------------------------------------------------
/**
* Gets the text to output when null
found.
*
* @return the current text to output when null
found
*/
public String getNullText() {
return super.getNullText();
}
/**
* Sets the text to output when null
found.
*
* null
is accepted, but will be converted
* to an empty String.
*
* @param nullText the new text to output when null
found
*/
public void setNullText(String nullText) {
super.setNullText(nullText);
}
//---------------------------------------------------------------------
/**
* Gets the 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
*/
public String getSizeStartText() {
return super.getSizeStartText();
}
/**
* 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.
*
* @param sizeStartText the new start of size text
*/
public void setSizeStartText(String sizeStartText) {
super.setSizeStartText(sizeStartText);
}
//---------------------------------------------------------------------
/**
* 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
*/
public String getSizeEndText() {
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.
*
* @param sizeEndText the new end of size text
*/
public void setSizeEndText(String sizeEndText) {
super.setSizeEndText(sizeEndText);
}
//---------------------------------------------------------------------
/**
* 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
*/
public String getSummaryObjectStartText() {
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.
*
* @param summaryObjectStartText the new start of summary text
*/
public void setSummaryObjectStartText(String summaryObjectStartText) {
super.setSummaryObjectStartText(summaryObjectStartText);
}
//---------------------------------------------------------------------
/**
* 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
*/
public String getSummaryObjectEndText() {
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.
*
* @param summaryObjectEndText the new end of summary text
*/
public void setSummaryObjectEndText(String summaryObjectEndText) {
super.setSummaryObjectEndText(summaryObjectEndText);
}
//---------------------------------------------------------------------
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/builder/ToStringBuilder.java 100644 0 0 110171 11513702444 26342 0 ustar 0 0 /*
* 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.lang.builder;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.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:
*
* - allowing field names
* - handling all types consistently
* - handling nulls consistently
* - outputting arrays and multi-dimensional arrays
* - enabling the detail level to be controlled for Objects and Collections
* - handling class hierarchies
*
*
* 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.
*
* @author Apache Software Foundation
* @author Gary Gregory
* @author Pete Gieser
* @since 1.0
* @version $Id: ToStringBuilder.java 905636 2010-02-02 14:03:32Z niallp $
*/
public class ToStringBuilder {
/**
* The default style of output to use, not null.
*/
private static volatile ToStringStyle defaultStyle = ToStringStyle.DEFAULT_STYLE;
//----------------------------------------------------------------------------
/**
* 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 default ToStringStyle
, 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}.
*
* @param style the default 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.
*
* @param object the Object to be output
* @return the String result
* @see ReflectionToStringBuilder#toString(Object)
*/
public static String reflectionToString(Object object) {
return ReflectionToStringBuilder.toString(object);
}
/**
* Uses ReflectionToStringBuilder
to generate a
* toString
for the specified object.
*
* @param object the Object to be output
* @param style the style of the 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.
*
* @param object the Object to be output
* @param style the style of the 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.
*
* @param object the Object to be output
* @param style the style of the 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 String reflectionToString(
Object object,
ToStringStyle style,
boolean outputTransients,
Class reflectUpToClass) {
return ReflectionToStringBuilder.toString(object, style, outputTransients, false, reflectUpToClass);
}
//----------------------------------------------------------------------------
/**
* Current toString buffer, not null.
*/
private final StringBuffer buffer;
/**
* The object being output, may be null.
*/
private final Object object;
/**
* The style of output to use, not null.
*/
private final ToStringStyle style;
/**
* 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 a toString
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.
*
* @param object the Object to build a 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.
*
* @param object the Object to build a 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.
*
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(boolean value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
a boolean
* array.
*
* @param array the array to add to the toString
* @return this
*/
public ToStringBuilder append(boolean[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
a byte
* value.
*
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(byte value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
a byte
* array.
*
* @param array the array to add to the toString
* @return this
*/
public ToStringBuilder append(byte[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
a char
* value.
*
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(char value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
a char
* array.
*
* @param array the array to add to the toString
* @return this
*/
public ToStringBuilder append(char[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
a double
* value.
*
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(double value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
a double
* array.
*
* @param array the array to add to the toString
* @return this
*/
public ToStringBuilder append(double[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
a float
* value.
*
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(float value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
a float
* array.
*
* @param array the array to add to the toString
* @return this
*/
public ToStringBuilder append(float[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
an int
* value.
*
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(int value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
an int
* array.
*
* @param array the array to add to the toString
* @return this
*/
public ToStringBuilder append(int[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
a long
* value.
*
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(long value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
a long
* array.
*
* @param array the array to add to the toString
* @return this
*/
public ToStringBuilder append(long[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
an Object
* value.
*
* @param obj the value to add to the toString
* @return this
*/
public ToStringBuilder append(Object obj) {
style.append(buffer, null, obj, null);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
an Object
* array.
*
* @param array the array to add to the toString
* @return this
*/
public ToStringBuilder append(Object[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
a short
* value.
*
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(short value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* Append to the toString
a short
* array.
*
* @param array the array to add to the toString
* @return this
*/
public ToStringBuilder append(short[] array) {
style.append(buffer, null, array, null);
return this;
}
/**
* Append to the toString
a boolean
* value.
*
* @param fieldName the field name
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(String fieldName, boolean value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* Append to the toString
a boolean
* array.
*
* @param fieldName the field name
* @param array the array to add to the 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.
*
* @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, boolean[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
return this;
}
/**
* Append to the toString
an byte
* value.
*
* @param fieldName the field name
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(String fieldName, byte value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* Append to the toString
a byte
array.
*
* @param fieldName the field name
* @param array the array to add to the 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, BooleanUtils.toBooleanObject(fullDetail));
return this;
}
/**
*
Append to the toString
a char
* value.
*
* @param fieldName the field name
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(String fieldName, char value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* Append to the toString
a char
* array.
*
* @param fieldName the field name
* @param array the array to add to the 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.
*
* @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, char[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
return this;
}
/**
* Append to the toString
a double
* value.
*
* @param fieldName the field name
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(String fieldName, double value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* Append to the toString
a double
* array.
*
* @param fieldName the field name
* @param array the array to add to the 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.
*
* @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, double[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
return this;
}
/**
* Append to the toString
an float
* value.
*
* @param fieldName the field name
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(String fieldName, float value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* Append to the toString
a float
* array.
*
* @param fieldName the field name
* @param array the array to add to the 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.
*
* @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, float[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
return this;
}
/**
* Append to the toString
an int
* value.
*
* @param fieldName the field name
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(String fieldName, int value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* Append to the toString
an int
* array.
*
* @param fieldName the field name
* @param array the array to add to the 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.
*
* @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, int[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
return this;
}
/**
* Append to the toString
a long
* value.
*
* @param fieldName the field name
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(String fieldName, long value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* Append to the toString
a long
* array.
*
* @param fieldName the field name
* @param array the array to add to the 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.
*
* @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, long[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
return this;
}
/**
* Append to the toString
an Object
* value.
*
* @param fieldName the field name
* @param obj the value to add to the 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.
*
* @param fieldName the field name
* @param obj the value to add to the 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, BooleanUtils.toBooleanObject(fullDetail));
return this;
}
/**
* Append to the toString
an Object
* array.
*
* @param fieldName the field name
* @param array the array to add to the 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.
*
* @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, Object[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
return this;
}
/**
* Append to the toString
an short
* value.
*
* @param fieldName the field name
* @param value the value to add to the toString
* @return this
*/
public ToStringBuilder append(String fieldName, short value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* Append to the toString
a short
* array.
*
* @param fieldName the field name
* @param array the array to add to the 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, BooleanUtils.toBooleanObject(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)}.
*
* @param object the 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.
*
* @param superToString the result of 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.
*
* @param toString the result of 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.
*
* @return The object being output.
* @since 2.0
*/
public Object getObject() {
return object;
}
/**
* Gets the StringBuffer
being populated.
*
* @return the StringBuffer
being populated
*/
public StringBuffer getStringBuffer() {
return buffer;
}
//----------------------------------------------------------------------------
/**
* Gets the ToStringStyle
being used.
*
* @return the 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
*
* @return the String toString
*/
public String toString() {
if (this.getObject() == null) {
this.getStringBuffer().append(this.getStyle().getNullText());
} else {
style.appendEnd(this.getStringBuffer(), this.getObject());
}
return this.getStringBuffer().toString();
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/builder/ToStringStyle.java 100644 0 0 227674 11513702444 26075 0 ustar 0 0 /*
* 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.lang.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.lang.ClassUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.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);
* }
* }
*
*
*
* @author Apache Software Foundation
* @author Gary Gregory
* @author Pete Gieser
* @author Masato Tezuka
* @since 1.0
* @version $Id: ToStringStyle.java 907168 2010-02-06 03:33:50Z mbenson $
*/
public abstract class ToStringStyle implements Serializable {
/**
* 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.
*
*/
private static final ThreadLocal REGISTRY = new ThreadLocal();
/**
*
* Returns the registry of objects being traversed by the reflectionToString
* methods in the current thread.
*
*
* @return Set the registry of objects being traversed
*/
static Map getRegistry() {
return (Map) REGISTRY.get();
}
/**
*
* Returns true
if the registry contains the given object.
* Used by the reflection methods to avoid infinite loops.
*
*
* @param value
* The object to lookup in the registry.
* @return boolean true
if the registry contains the given
* object.
*/
static boolean isRegistered(Object value) {
Map m = getRegistry();
return m != null && m.containsKey(value);
}
/**
*
* 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 m = getRegistry();
if (m == null) {
m = new WeakHashMap();
REGISTRY.set(m);
}
m.put(value, null);
}
}
/**
*
* 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) {
Map m = getRegistry();
if (m != null) {
m.remove(value);
if (m.isEmpty()) {
REGISTRY.set(null);
}
}
}
}
/**
* Whether to use the field names, the default is true
.
*/
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 = "";
/**
* The summary size text start '.
*/
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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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 the StringBuffer
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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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
.
*
* @param buffer the 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
.
*
* @param buffer the 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.
*
* @param buffer the 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
.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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.
*
* @param buffer the 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 the StringBuffer
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.
*
* @param buffer the StringBuffer
to populate
*/
protected void appendContentStart(StringBuffer buffer) {
buffer.append(contentStart);
}
/**
* Append to the toString
the content end.
*
* @param buffer the StringBuffer
to populate
*/
protected void appendContentEnd(StringBuffer buffer) {
buffer.append(contentEnd);
}
/**
* Append to the toString
an indicator for null
.
*
* The default indicator is '<null>'
.
*
* @param buffer the 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.
*
* @param buffer the StringBuffer
to populate
*/
protected void appendFieldSeparator(StringBuffer buffer) {
buffer.append(fieldSeparator);
}
/**
* Append to the toString
the field start.
*
* @param buffer the 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.
*
* @param buffer the 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>'.
*
* @param buffer the 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.
*
* @param fullDetailRequest the detail level requested
* @return whether full detail is to be shown
*/
protected boolean isFullDetail(Boolean fullDetailRequest) {
if (fullDetailRequest == null) {
return defaultFullDetail;
}
return fullDetailRequest.booleanValue();
}
/**
* Gets the short class name for a class.
*
* The short class name is the classname excluding
* the package name.
*
* @param cls the Class
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;
}
/**
* Gets whether to output short or long class names.
*
* @return the current shortClassName flag
* @deprecated Use {@link #isUseShortClassName()}
* Method will be removed in Commons Lang 3.0.
*/
protected boolean isShortClassName() {
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;
}
/**
* Sets whether to output short or long class names.
*
* @param shortClassName the new shortClassName flag
* @deprecated Use {@link #setUseShortClassName(boolean)}
* Method will be removed in Commons Lang 3.0.
*/
protected void setShortClassName(boolean shortClassName) {
this.useShortClassName = shortClassName;
}
//---------------------------------------------------------------------
/**
* 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.
*
* @param arrayStart the new array start text
*/
protected void setArrayStart(String arrayStart) {
if (arrayStart == null) {
arrayStart = "";
}
this.arrayStart = arrayStart;
}
//---------------------------------------------------------------------
/**
* 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.
*
* @param arrayEnd the new array end text
*/
protected void setArrayEnd(String arrayEnd) {
if (arrayEnd == null) {
arrayEnd = "";
}
this.arrayEnd = arrayEnd;
}
//---------------------------------------------------------------------
/**
* 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.
*
* @param arraySeparator the new array separator text
*/
protected void setArraySeparator(String arraySeparator) {
if (arraySeparator == null) {
arraySeparator = "";
}
this.arraySeparator = arraySeparator;
}
//---------------------------------------------------------------------
/**
* 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.
*
* @param contentStart the new content start text
*/
protected void setContentStart(String contentStart) {
if (contentStart == null) {
contentStart = "";
}
this.contentStart = contentStart;
}
//---------------------------------------------------------------------
/**
* 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.
*
* @param contentEnd the new content end text
*/
protected void setContentEnd(String contentEnd) {
if (contentEnd == null) {
contentEnd = "";
}
this.contentEnd = contentEnd;
}
//---------------------------------------------------------------------
/**
* 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.
*
* @param fieldNameValueSeparator the new field name value separator text
*/
protected void setFieldNameValueSeparator(String fieldNameValueSeparator) {
if (fieldNameValueSeparator == null) {
fieldNameValueSeparator = "";
}
this.fieldNameValueSeparator = fieldNameValueSeparator;
}
//---------------------------------------------------------------------
/**
* 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.
*
* @param fieldSeparator the new field separator text
*/
protected void setFieldSeparator(String fieldSeparator) {
if (fieldSeparator == null) {
fieldSeparator = "";
}
this.fieldSeparator = fieldSeparator;
}
//---------------------------------------------------------------------
/**
* 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.
*
* @return the current text to output when null found
*/
protected String getNullText() {
return nullText;
}
/**
* Sets the text to output when null
found.
*
* null
is accepted, but will be converted to
* an empty String.
*
* @param nullText the new text to output when null found
*/
protected void setNullText(String nullText) {
if (nullText == null) {
nullText = "";
}
this.nullText = nullText;
}
//---------------------------------------------------------------------
/**
* 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.
*
* @param sizeStartText the new start of size text
*/
protected void setSizeStartText(String sizeStartText) {
if (sizeStartText == null) {
sizeStartText = "";
}
this.sizeStartText = sizeStartText;
}
//---------------------------------------------------------------------
/**
* 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.
*
* @param sizeEndText the new end of size text
*/
protected void setSizeEndText(String sizeEndText) {
if (sizeEndText == null) {
sizeEndText = "";
}
this.sizeEndText = sizeEndText;
}
//---------------------------------------------------------------------
/**
* 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.
*
* @param summaryObjectStartText the new start of summary text
*/
protected void setSummaryObjectStartText(String summaryObjectStartText) {
if (summaryObjectStartText == null) {
summaryObjectStartText = "";
}
this.summaryObjectStartText = summaryObjectStartText;
}
//---------------------------------------------------------------------
/**
* 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.
*
* @param summaryObjectEndText the new end of summary text
*/
protected void setSummaryObjectEndText(String summaryObjectEndText) {
if (summaryObjectEndText == null) {
summaryObjectEndText = "";
}
this.summaryObjectEndText = summaryObjectEndText;
}
//----------------------------------------------------------------------------
/**
* Default ToStringStyle
.
*
* This is an inner class rather than using
* StandardToStringStyle
to ensure its immutability.
*/
private static final class DefaultToStringStyle extends ToStringStyle {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 1L;
/**
* Constructor.
*
* Use the static constant rather than instantiating.
*/
DefaultToStringStyle() {
super();
}
/**
* Ensure Singleton
after serialization.
*
* @return the singleton
*/
private Object readResolve() {
return ToStringStyle.DEFAULT_STYLE;
}
}
//----------------------------------------------------------------------------
/**
* 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.
*
* @return the singleton
*/
private Object readResolve() {
return ToStringStyle.NO_FIELD_NAMES_STYLE;
}
}
//----------------------------------------------------------------------------
/**
* 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.
*/
private static final class ShortPrefixToStringStyle extends ToStringStyle {
private static final long serialVersionUID = 1L;
/**
* Constructor.
*
* Use the static constant rather than instantiating.
*/
ShortPrefixToStringStyle() {
super();
this.setUseShortClassName(true);
this.setUseIdentityHashCode(false);
}
/**
* Ensure Singleton after serialization.
* @return the singleton
*/
private Object readResolve() {
return ToStringStyle.SHORT_PREFIX_STYLE;
}
}
/**
* 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.
*/
private static final class SimpleToStringStyle extends ToStringStyle {
private static final long serialVersionUID = 1L;
/**
* 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.
* @return the singleton
*/
private Object readResolve() {
return ToStringStyle.SIMPLE_STYLE;
}
}
//----------------------------------------------------------------------------
/**
* ToStringStyle
that outputs on multiple lines.
*
* This is an inner class rather than using
* StandardToStringStyle
to ensure its immutability.
*/
private static final class MultiLineToStringStyle extends ToStringStyle {
private static final long serialVersionUID = 1L;
/**
* 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.
*
* @return the singleton
*/
private Object readResolve() {
return ToStringStyle.MULTI_LINE_STYLE;
}
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/CharEncoding.java 100644 0 0 12756 11513702445 24153 0 ustar 0 0 /*
* 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.lang;
import java.io.UnsupportedEncodingException;
/**
*
* Character encoding names required of every implementation of the Java platform.
*
*
*
* According to JRE character
* encoding names:
*
* Every implementation of the Java platform is required to support the following character encodings. Consult the
* release documentation for your implementation to see if any other encodings are supported.
*
*
*
* @see JRE character encoding
* names
* @author Apache Software Foundation
* @since 2.1
* @version $Id: CharEncoding.java 437554 2006-08-28 06:21:41Z bayard $
*/
public class CharEncoding {
/**
*
* ISO Latin Alphabet #1, also known as ISO-LATIN-1.
*
*
* Every implementation of the Java platform is required to support this character encoding.
*
*
* @see JRE character
* encoding names
*/
public static final String ISO_8859_1 = "ISO-8859-1";
/**
*
* Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set.
*
*
* Every implementation of the Java platform is required to support this character encoding.
*
*
* @see JRE character
* encoding names
*/
public static final String US_ASCII = "US-ASCII";
/**
*
* Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark (either
* order accepted on input, big-endian used on output).
*
*
* Every implementation of the Java platform is required to support this character encoding.
*
*
* @see JRE character
* encoding names
*/
public static final String UTF_16 = "UTF-16";
/**
*
* Sixteen-bit Unicode Transformation Format, big-endian byte order.
*
*
* Every implementation of the Java platform is required to support this character encoding.
*
*
* @see JRE character
* encoding names
*/
public static final String UTF_16BE = "UTF-16BE";
/**
*
* Sixteen-bit Unicode Transformation Format, little-endian byte order.
*
*
* Every implementation of the Java platform is required to support this character encoding.
*
*
* @see JRE character
* encoding names
*/
public static final String UTF_16LE = "UTF-16LE";
/**
*
* Eight-bit Unicode Transformation Format.
*
*
* Every implementation of the Java platform is required to support this character encoding.
*
*
* @see JRE character
* encoding names
*/
public static final String UTF_8 = "UTF-8";
/**
*
* Returns whether the named charset is supported.
*
*
* This is similar to
* java.nio.charset.Charset.isSupported(String)
*
*
* @param name
* the name of the requested charset; may be either a canonical name or an alias
* @return true
if, and only if, support for the named charset is available in the current Java
* virtual machine
*
* @see JRE character
* encoding names
*/
public static boolean isSupported(String name) {
if (name == null) {
return false;
}
try {
new String(ArrayUtils.EMPTY_BYTE_ARRAY, name);
} catch (UnsupportedEncodingException e) {
return false;
}
return true;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/CharRange.java 100644 0 0 30413 11513702445 23447 0 ustar 0 0 /*
* 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.lang;
import java.io.Serializable;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.commons.lang.text.StrBuilder;
/**
* A contiguous range of characters, optionally negated.
*
* Instances are immutable.
*
* #ThreadSafe#
* @author Apache Software Foundation
* @author Chris Feldhacker
* @author Gary Gregory
* @since 1.0
* @version $Id: CharRange.java 1057072 2011-01-10 01:55:57Z niallp $
*/
public final class CharRange implements Serializable {
/**
* Required for serialization support. Lang version 2.0.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 8270183163158333422L;
/** The first character, inclusive, in the range. */
private final char start;
/** The last character, inclusive, in the range. */
private final char end;
/** True if the range is everything except the characters specified. */
private final boolean negated;
/** Cached toString. */
private transient String iToString;
// Static
//-----------------------------------------------------------------------
/**
* Constructs a CharRange
over a single character.
*
* @param ch only character in this range
* @return the new CharRange object
* @see CharRange#CharRange(char, char, boolean)
* @since 2.5
*/
public static CharRange is(char ch) {
return new CharRange(ch, ch, false);
}
/**
* Constructs a negated CharRange
over a single character.
*
* @param ch only character in this range
* @return the new CharRange object
* @see CharRange#CharRange(char, char, boolean)
* @since 2.5
*/
public static CharRange isNot(char ch) {
return new CharRange(ch, ch, true);
}
/**
* Constructs a CharRange
over a set of characters.
*
* @param start first character, inclusive, in this range
* @param end last character, inclusive, in this range
* @return the new CharRange object
* @see CharRange#CharRange(char, char, boolean)
* @since 2.5
*/
public static CharRange isIn(char start, char end) {
return new CharRange(start, end, false);
}
/**
* Constructs a negated CharRange
over a set of characters.
*
* @param start first character, inclusive, in this range
* @param end last character, inclusive, in this range
* @return the new CharRange object
* @see CharRange#CharRange(char, char, boolean)
* @since 2.5
*/
public static CharRange isNotIn(char start, char end) {
return new CharRange(start, end, true);
}
//-----------------------------------------------------------------------
/**
* Constructs a CharRange
over a single character.
*
* @param ch only character in this range
*/
public CharRange(char ch) {
this(ch, ch, false);
}
/**
* Constructs a CharRange
over a single character,
* optionally negating the range.
*
* A negated range includes everything except the specified char.
*
* @param ch only character in this range
* @param negated true to express everything except the range
*/
public CharRange(char ch, boolean negated) {
this(ch, ch, negated);
}
/**
* Constructs a CharRange
over a set of characters.
*
* @param start first character, inclusive, in this range
* @param end last character, inclusive, in this range
*/
public CharRange(char start, char end) {
this(start, end, false);
}
/**
* Constructs a CharRange
over a set of characters,
* optionally negating the range.
*
* A negated range includes everything except that defined by the
* start and end characters.
*
* If start and end are in the wrong order, they are reversed.
* Thus a-e
is the same as e-a
.
*
* @param start first character, inclusive, in this range
* @param end last character, inclusive, in this range
* @param negated true to express everything except the range
*/
public CharRange(char start, char end, boolean negated) {
super();
if (start > end) {
char temp = start;
start = end;
end = temp;
}
this.start = start;
this.end = end;
this.negated = negated;
}
// Accessors
//-----------------------------------------------------------------------
/**
* Gets the start character for this character range.
*
* @return the start char (inclusive)
*/
public char getStart() {
return this.start;
}
/**
* Gets the end character for this character range.
*
* @return the end char (inclusive)
*/
public char getEnd() {
return this.end;
}
/**
* Is this CharRange
negated.
*
* A negated range includes everything except that defined by the
* start and end characters.
*
* @return true
is negated
*/
public boolean isNegated() {
return negated;
}
// Contains
//-----------------------------------------------------------------------
/**
* Is the character specified contained in this range.
*
* @param ch the character to check
* @return true
if this range contains the input character
*/
public boolean contains(char ch) {
return (ch >= start && ch <= end) != negated;
}
/**
* Are all the characters of the passed in range contained in
* this range.
*
* @param range the range to check against
* @return true
if this range entirely contains the input range
* @throws IllegalArgumentException if null
input
*/
public boolean contains(CharRange range) {
if (range == null) {
throw new IllegalArgumentException("The Range must not be null");
}
if (negated) {
if (range.negated) {
return start >= range.start && end <= range.end;
}
return range.end < start || range.start > end;
}
if (range.negated) {
return start == 0 && end == Character.MAX_VALUE;
}
return start <= range.start && end >= range.end;
}
// Basics
//-----------------------------------------------------------------------
/**
* Compares two CharRange objects, returning true if they represent
* exactly the same range of characters defined in the same way.
*
* @param obj the object to compare to
* @return true if equal
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof CharRange == false) {
return false;
}
CharRange other = (CharRange) obj;
return start == other.start && end == other.end && negated == other.negated;
}
/**
* Gets a hashCode compatible with the equals method.
*
* @return a suitable hashCode
*/
public int hashCode() {
return 83 + start + 7 * end + (negated ? 1 : 0);
}
/**
* Gets a string representation of the character range.
*
* @return string representation of this range
*/
public String toString() {
if (iToString == null) {
StrBuilder buf = new StrBuilder(4);
if (isNegated()) {
buf.append('^');
}
buf.append(start);
if (start != end) {
buf.append('-');
buf.append(end);
}
iToString = buf.toString();
}
return iToString;
}
// Expansions
//-----------------------------------------------------------------------
/**
* Returns an iterator which can be used to walk through the characters described by this range.
*
* #NotThreadSafe# the iterator is not threadsafe
* @return an iterator to the chars represented by this range
* @since 2.5
*/
public Iterator iterator() {
return new CharacterIterator(this);
}
/**
* Character {@link Iterator}.
* #NotThreadSafe#
*/
private static class CharacterIterator implements Iterator {
/** The current character */
private char current;
private final CharRange range;
private boolean hasNext;
/**
* Construct a new iterator for the character range.
*
* @param r The character range
*/
private CharacterIterator(CharRange r) {
range = r;
hasNext = true;
if (range.negated) {
if (range.start == 0) {
if (range.end == Character.MAX_VALUE) {
// This range is an empty set
hasNext = false;
} else {
current = (char) (range.end + 1);
}
} else {
current = 0;
}
} else {
current = range.start;
}
}
/**
* Prepare the next character in the range.
*/
private void prepareNext() {
if (range.negated) {
if (current == Character.MAX_VALUE) {
hasNext = false;
} else if (current + 1 == range.start) {
if (range.end == Character.MAX_VALUE) {
hasNext = false;
} else {
current = (char) (range.end + 1);
}
} else {
current = (char) (current + 1);
}
} else if (current < range.end) {
current = (char) (current + 1);
} else {
hasNext = false;
}
}
/**
* Has the iterator not reached the end character yet?
*
* @return true
if the iterator has yet to reach the character date
*/
public boolean hasNext() {
return hasNext;
}
/**
* Return the next character in the iteration
*
* @return Character
for the next character
*/
public Object next() {
if (hasNext == false) {
throw new NoSuchElementException();
}
char cur = current;
prepareNext();
return new Character(cur);
}
/**
* Always throws UnsupportedOperationException.
*
* @throws UnsupportedOperationException
* @see java.util.Iterator#remove()
*/
public void remove() {
throw new UnsupportedOperationException();
}
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/CharSet.java 100644 0 0 23263 11513702445 23153 0 ustar 0 0 /*
* 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.lang;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* A set of characters.
*
* Instances are immutable, but instances of subclasses may not be.
*
* #ThreadSafe#
* @author Apache Software Foundation
* @author Phil Steitz
* @author Pete Gieser
* @author Gary Gregory
* @since 1.0
* @version $Id: CharSet.java 1056988 2011-01-09 17:58:53Z niallp $
*/
public class CharSet implements Serializable {
/**
* Required for serialization support. Lang version 2.0.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 5947847346149275958L;
/**
* A CharSet defining no characters.
* @since 2.0
*/
public static final CharSet EMPTY = new CharSet((String) null);
/**
* A CharSet defining ASCII alphabetic characters "a-zA-Z".
* @since 2.0
*/
public static final CharSet ASCII_ALPHA = new CharSet("a-zA-Z");
/**
* A CharSet defining ASCII alphabetic characters "a-z".
* @since 2.0
*/
public static final CharSet ASCII_ALPHA_LOWER = new CharSet("a-z");
/**
* A CharSet defining ASCII alphabetic characters "A-Z".
* @since 2.0
*/
public static final CharSet ASCII_ALPHA_UPPER = new CharSet("A-Z");
/**
* A CharSet defining ASCII alphabetic characters "0-9".
* @since 2.0
*/
public static final CharSet ASCII_NUMERIC = new CharSet("0-9");
/**
* A Map of the common cases used in the factory.
* Subclasses can add more common patterns if desired
* @since 2.0
*/
protected static final Map COMMON = Collections.synchronizedMap(new HashMap());
static {
COMMON.put(null, EMPTY);
COMMON.put("", EMPTY);
COMMON.put("a-zA-Z", ASCII_ALPHA);
COMMON.put("A-Za-z", ASCII_ALPHA);
COMMON.put("a-z", ASCII_ALPHA_LOWER);
COMMON.put("A-Z", ASCII_ALPHA_UPPER);
COMMON.put("0-9", ASCII_NUMERIC);
}
/** The set of CharRange objects. */
private final Set set = Collections.synchronizedSet(new HashSet());
//-----------------------------------------------------------------------
/**
* Factory method to create a new CharSet using a special syntax.
*
*
* null
or empty string ("")
* - set containing no characters
* - Single character, such as "a"
* - set containing just that character
* - Multi character, such as "a-e"
* - set containing characters from one character to the other
* - Negated, such as "^a" or "^a-e"
* - set containing all characters except those defined
* - Combinations, such as "abe-g"
* - set containing all the characters from the individual sets
*
*
* The matching order is:
*
* - Negated multi character range, such as "^a-e"
*
- Ordinary multi character range, such as "a-e"
*
- Negated single character, such as "^a"
*
- Ordinary single character, such as "a"
*
* Matching works left to right. Once a match is found the
* search starts again from the next character.
*
* If the same range is defined twice using the same syntax, only
* one range will be kept.
* Thus, "a-ca-c" creates only one range of "a-c".
*
* If the start and end of a range are in the wrong order,
* they are reversed. Thus "a-e" is the same as "e-a".
* As a result, "a-ee-a" would create only one range,
* as the "a-e" and "e-a" are the same.
*
* The set of characters represented is the union of the specified ranges.
*
* All CharSet objects returned by this method will be immutable.
*
* @param setStr the String describing the set, may be null
* @return a CharSet instance
* @since 2.0
*/
public static CharSet getInstance(String setStr) {
Object set = COMMON.get(setStr);
if (set != null) {
return (CharSet) set;
}
return new CharSet(setStr);
}
/**
* Constructs a new CharSet using the set syntax.
* Each string is merged in with the set.
*
* @param setStrs Strings to merge into the initial set, may be null
* @return a CharSet instance
* @since 2.4
*/
public static CharSet getInstance(String[] setStrs) {
if (setStrs == null) {
return null;
}
return new CharSet(setStrs);
}
//-----------------------------------------------------------------------
/**
* Constructs a new CharSet using the set syntax.
*
* @param setStr the String describing the set, may be null
* @since 2.0
*/
protected CharSet(String setStr) {
super();
add(setStr);
}
/**
* Constructs a new CharSet using the set syntax.
* Each string is merged in with the set.
*
* @param set Strings to merge into the initial set
* @throws NullPointerException if set is null
*/
protected CharSet(String[] set) {
super();
int sz = set.length;
for (int i = 0; i < sz; i++) {
add(set[i]);
}
}
//-----------------------------------------------------------------------
/**
* Add a set definition string to the CharSet
.
*
* @param str set definition string
*/
protected void add(String str) {
if (str == null) {
return;
}
int len = str.length();
int pos = 0;
while (pos < len) {
int remainder = (len - pos);
if (remainder >= 4 && str.charAt(pos) == '^' && str.charAt(pos + 2) == '-') {
// negated range
set.add(CharRange.isNotIn(str.charAt(pos + 1), str.charAt(pos + 3)));
pos += 4;
} else if (remainder >= 3 && str.charAt(pos + 1) == '-') {
// range
set.add(CharRange.isIn(str.charAt(pos), str.charAt(pos + 2)));
pos += 3;
} else if (remainder >= 2 && str.charAt(pos) == '^') {
// negated char
set.add(CharRange.isNot(str.charAt(pos + 1)));
pos += 2;
} else {
// char
set.add(CharRange.is(str.charAt(pos)));
pos += 1;
}
}
}
//-----------------------------------------------------------------------
/**
* Gets the internal set as an array of CharRange objects.
*
* @return an array of immutable CharRange objects
* @since 2.0
*/
public CharRange[] getCharRanges() {
return (CharRange[]) set.toArray(new CharRange[set.size()]);
}
//-----------------------------------------------------------------------
/**
* Does the CharSet
contain the specified
* character ch
.
*
* @param ch the character to check for
* @return true
if the set contains the characters
*/
public boolean contains(char ch) {
for (Iterator it = set.iterator(); it.hasNext();) {
CharRange range = (CharRange) it.next();
if (range.contains(ch)) {
return true;
}
}
return false;
}
// Basics
//-----------------------------------------------------------------------
/**
* Compares two CharSet objects, returning true if they represent
* exactly the same set of characters defined in the same way.
*
* The two sets abc
and a-c
are not
* equal according to this method.
*
* @param obj the object to compare to
* @return true if equal
* @since 2.0
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof CharSet == false) {
return false;
}
CharSet other = (CharSet) obj;
return set.equals(other.set);
}
/**
* Gets a hashCode compatible with the equals method.
*
* @return a suitable hashCode
* @since 2.0
*/
public int hashCode() {
return 89 + set.hashCode();
}
/**
* Gets a string representation of the set.
*
* @return string representation of the set
*/
public String toString() {
return set.toString();
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/CharSetUtils.java 100644 0 0 34664 11513702445 24203 0 ustar 0 0 /*
* 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.lang;
import org.apache.commons.lang.text.StrBuilder;
/**
* Operations on CharSet
s.
*
* This class handles null
input gracefully.
* An exception will not be thrown for a null
input.
* Each method documents its behaviour in more detail.
*
* #ThreadSafe#
* @see CharSet
* @author Apache Software Foundation
* @author Phil Steitz
* @author Gary Gregory
* @since 1.0
* @version $Id: CharSetUtils.java 1057072 2011-01-10 01:55:57Z niallp $
*/
public class CharSetUtils {
/**
* CharSetUtils instances should NOT be constructed in standard programming.
* Instead, the class should be used as CharSetUtils.evaluateSet(null);
.
*
* This constructor is public to permit tools that require a JavaBean instance
* to operate.
*/
public CharSetUtils() {
super();
}
// Factory
//-----------------------------------------------------------------------
/**
* Creates a CharSet
instance which allows a certain amount of
* set logic to be performed.
* The syntax is:
*
* - "aeio" which implies 'a','e',..
* - "^e" implies not e.
* - "ej-m" implies e,j->m. e,j,k,l,m.
*
*
*
* CharSetUtils.evaluateSet(null) = null
* CharSetUtils.evaluateSet([]) = CharSet matching nothing
* CharSetUtils.evaluateSet(["a-e"]) = CharSet matching a,b,c,d,e
*
*
* @param set the set, may be null
* @return a CharSet instance, null
if null input
* @deprecated Use {@link CharSet#getInstance(String[])}.
* Method will be removed in Commons Lang 3.0.
*/
public static CharSet evaluateSet(String[] set) {
if (set == null) {
return null;
}
return new CharSet(set);
}
// Squeeze
//-----------------------------------------------------------------------
/**
* Squeezes any repetitions of a character that is mentioned in the
* supplied set.
*
*
* CharSetUtils.squeeze(null, *) = null
* CharSetUtils.squeeze("", *) = ""
* CharSetUtils.squeeze(*, null) = *
* CharSetUtils.squeeze(*, "") = *
* CharSetUtils.squeeze("hello", "k-p") = "helo"
* CharSetUtils.squeeze("hello", "a-e") = "hello"
*
*
* @see CharSet#getInstance(java.lang.String) for set-syntax.
* @param str the string to squeeze, may be null
* @param set the character set to use for manipulation, may be null
* @return modified String, null
if null string input
*/
public static String squeeze(String str, String set) {
if (StringUtils.isEmpty(str) || StringUtils.isEmpty(set)) {
return str;
}
String[] strs = new String[1];
strs[0] = set;
return squeeze(str, strs);
}
/**
* Squeezes any repetitions of a character that is mentioned in the
* supplied set.
*
* An example is:
*
* - squeeze("hello", {"el"}) => "helo"
*
*
* @see CharSet#getInstance(java.lang.String) for set-syntax.
* @param str the string to squeeze, may be null
* @param set the character set to use for manipulation, may be null
* @return modified String, null
if null string input
*/
public static String squeeze(String str, String[] set) {
if (StringUtils.isEmpty(str) || ArrayUtils.isEmpty(set)) {
return str;
}
CharSet chars = CharSet.getInstance(set);
StrBuilder buffer = new StrBuilder(str.length());
char[] chrs = str.toCharArray();
int sz = chrs.length;
char lastChar = ' ';
char ch = ' ';
for (int i = 0; i < sz; i++) {
ch = chrs[i];
if (chars.contains(ch)) {
if ((ch == lastChar) && (i != 0)) {
continue;
}
}
buffer.append(ch);
lastChar = ch;
}
return buffer.toString();
}
// Count
//-----------------------------------------------------------------------
/**
* Takes an argument in set-syntax, see evaluateSet,
* and returns the number of characters present in the specified string.
*
*
* CharSetUtils.count(null, *) = 0
* CharSetUtils.count("", *) = 0
* CharSetUtils.count(*, null) = 0
* CharSetUtils.count(*, "") = 0
* CharSetUtils.count("hello", "k-p") = 3
* CharSetUtils.count("hello", "a-e") = 1
*
*
* @see CharSet#getInstance(java.lang.String) for set-syntax.
* @param str String to count characters in, may be null
* @param set String set of characters to count, may be null
* @return character count, zero if null string input
*/
public static int count(String str, String set) {
if (StringUtils.isEmpty(str) || StringUtils.isEmpty(set)) {
return 0;
}
String[] strs = new String[1];
strs[0] = set;
return count(str, strs);
}
/**
* Takes an argument in set-syntax, see evaluateSet,
* and returns the number of characters present in the specified string.
*
* An example would be:
*
* - count("hello", {"c-f", "o"}) returns 2.
*
*
* @see CharSet#getInstance(java.lang.String) for set-syntax.
* @param str String to count characters in, may be null
* @param set String[] set of characters to count, may be null
* @return character count, zero if null string input
*/
public static int count(String str, String[] set) {
if (StringUtils.isEmpty(str) || ArrayUtils.isEmpty(set)) {
return 0;
}
CharSet chars = CharSet.getInstance(set);
int count = 0;
char[] chrs = str.toCharArray();
int sz = chrs.length;
for(int i=0; iTakes an argument in set-syntax, see evaluateSet,
* and keeps any of characters present in the specified string.
*
*
* CharSetUtils.keep(null, *) = null
* CharSetUtils.keep("", *) = ""
* CharSetUtils.keep(*, null) = ""
* CharSetUtils.keep(*, "") = ""
* CharSetUtils.keep("hello", "hl") = "hll"
* CharSetUtils.keep("hello", "le") = "ell"
*
*
* @see CharSet#getInstance(java.lang.String) for set-syntax.
* @param str String to keep characters from, may be null
* @param set String set of characters to keep, may be null
* @return modified String, null
if null string input
* @since 2.0
*/
public static String keep(String str, String set) {
if (str == null) {
return null;
}
if (str.length() == 0 || StringUtils.isEmpty(set)) {
return "";
}
String[] strs = new String[1];
strs[0] = set;
return keep(str, strs);
}
/**
* Takes an argument in set-syntax, see evaluateSet,
* and keeps any of characters present in the specified string.
*
* An example would be:
*
* - keep("hello", {"c-f", "o"})
* returns "eo"
*
*
* @see CharSet#getInstance(java.lang.String) for set-syntax.
* @param str String to keep characters from, may be null
* @param set String[] set of characters to keep, may be null
* @return modified String, null
if null string input
* @since 2.0
*/
public static String keep(String str, String[] set) {
if (str == null) {
return null;
}
if (str.length() == 0 || ArrayUtils.isEmpty(set)) {
return "";
}
return modify(str, set, true);
}
// Delete
//-----------------------------------------------------------------------
/**
* Takes an argument in set-syntax, see evaluateSet,
* and deletes any of characters present in the specified string.
*
*
* CharSetUtils.delete(null, *) = null
* CharSetUtils.delete("", *) = ""
* CharSetUtils.delete(*, null) = *
* CharSetUtils.delete(*, "") = *
* CharSetUtils.delete("hello", "hl") = "eo"
* CharSetUtils.delete("hello", "le") = "ho"
*
*
* @see CharSet#getInstance(java.lang.String) for set-syntax.
* @param str String to delete characters from, may be null
* @param set String set of characters to delete, may be null
* @return modified String, null
if null string input
*/
public static String delete(String str, String set) {
if (StringUtils.isEmpty(str) || StringUtils.isEmpty(set)) {
return str;
}
String[] strs = new String[1];
strs[0] = set;
return delete(str, strs);
}
/**
* Takes an argument in set-syntax, see evaluateSet,
* and deletes any of characters present in the specified string.
*
* An example would be:
*
* - delete("hello", {"c-f", "o"}) returns
* "hll"
*
*
* @see CharSet#getInstance(java.lang.String) for set-syntax.
* @param str String to delete characters from, may be null
* @param set String[] set of characters to delete, may be null
* @return modified String, null
if null string input
*/
public static String delete(String str, String[] set) {
if (StringUtils.isEmpty(str) || ArrayUtils.isEmpty(set)) {
return str;
}
return modify(str, set, false);
}
//-----------------------------------------------------------------------
/**
* Implementation of delete and keep
*
* @param str String to modify characters within
* @param set String[] set of characters to modify
* @param expect whether to evaluate on match, or non-match
* @return modified String
*/
private static String modify(String str, String[] set, boolean expect) {
CharSet chars = CharSet.getInstance(set);
StrBuilder buffer = new StrBuilder(str.length());
char[] chrs = str.toCharArray();
int sz = chrs.length;
for(int i=0; iTranslate characters in a String.
* This is a multi character search and replace routine.
*
* An example is:
*
* - translate("hello", "ho", "jy")
* => jelly
*
*
* If the length of characters to search for is greater than the
* length of characters to replace, then the last character is
* used.
*
*
* CharSetUtils.translate(null, *, *) = null
* CharSetUtils.translate("", *, *) = ""
*
*
* @param str String to replace characters in, may be null
* @param searchChars a set of characters to search for, must not be null
* @param replaceChars a set of characters to replace, must not be null or empty ("")
* @return translated String, null
if null string input
* @throws NullPointerException if searchChars
or replaceChars
* is null
* @throws ArrayIndexOutOfBoundsException if replaceChars
is empty ("")
* @deprecated Use {@link StringUtils#replaceChars(String, String, String)}.
* Method will be removed in Commons Lang 3.0.
* NOTE: StringUtils#replaceChars behaves differently when 'searchChars' is longer
* than 'replaceChars'. CharSetUtils#translate will use the last char of the replacement
* string whereas StringUtils#replaceChars will delete
*/
public static String translate(String str, String searchChars, String replaceChars) {
if (StringUtils.isEmpty(str)) {
return str;
}
StrBuilder buffer = new StrBuilder(str.length());
char[] chrs = str.toCharArray();
char[] withChrs = replaceChars.toCharArray();
int sz = chrs.length;
int withMax = replaceChars.length() - 1;
for(int i=0; i withMax) {
idx = withMax;
}
buffer.append(withChrs[idx]);
} else {
buffer.append(chrs[i]);
}
}
return buffer.toString();
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/CharUtils.java 100644 0 0 47722 11513702446 23527 0 ustar 0 0 /*
* 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.lang;
/**
* Operations on char primitives and Character objects.
*
* This class tries to handle null
input gracefully.
* An exception will not be thrown for a null
input.
* Each method documents its behaviour in more detail.
*
* #ThreadSafe#
* @author Apache Software Foundation
* @since 2.1
* @version $Id: CharUtils.java 1056988 2011-01-09 17:58:53Z niallp $
*/
public class CharUtils {
private static final String CHAR_STRING =
"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007" +
"\b\t\n\u000b\f\r\u000e\u000f" +
"\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017" +
"\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f" +
"\u0020\u0021\"\u0023\u0024\u0025\u0026\u0027" +
"\u0028\u0029\u002a\u002b\u002c\u002d\u002e\u002f" +
"\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037" +
"\u0038\u0039\u003a\u003b\u003c\u003d\u003e\u003f" +
"\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047" +
"\u0048\u0049\u004a\u004b\u004c\u004d\u004e\u004f" +
"\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057" +
"\u0058\u0059\u005a\u005b\\\u005d\u005e\u005f" +
"\u0060\u0061\u0062\u0063\u0064\u0065\u0066\u0067" +
"\u0068\u0069\u006a\u006b\u006c\u006d\u006e\u006f" +
"\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077" +
"\u0078\u0079\u007a\u007b\u007c\u007d\u007e\u007f";
private static final String[] CHAR_STRING_ARRAY = new String[128];
private static final Character[] CHAR_ARRAY = new Character[128];
/**
* \u000a
linefeed LF ('\n').
*
* @see JLF: Escape Sequences
* for Character and String Literals
* @since 2.2
*/
public static final char LF = '\n';
/**
* \u000d
carriage return CR ('\r').
*
* @see JLF: Escape Sequences
* for Character and String Literals
* @since 2.2
*/
public static final char CR = '\r';
static {
for (int i = 127; i >= 0; i--) {
CHAR_STRING_ARRAY[i] = CHAR_STRING.substring(i, i + 1);
CHAR_ARRAY[i] = new Character((char) i);
}
}
/**
* CharUtils
instances should NOT be constructed in standard programming.
* Instead, the class should be used as CharUtils.toString('c');
.
*
* This constructor is public to permit tools that require a JavaBean instance
* to operate.
*/
public CharUtils() {
super();
}
//-----------------------------------------------------------------------
/**
* Converts the character to a Character.
*
* For ASCII 7 bit characters, this uses a cache that will return the
* same Character object each time.
*
*
* CharUtils.toCharacterObject(' ') = ' '
* CharUtils.toCharacterObject('A') = 'A'
*
*
* @param ch the character to convert
* @return a Character of the specified character
*/
public static Character toCharacterObject(char ch) {
if (ch < CHAR_ARRAY.length) {
return CHAR_ARRAY[ch];
}
return new Character(ch);
}
/**
* Converts the String to a Character using the first character, returning
* null for empty Strings.
*
* For ASCII 7 bit characters, this uses a cache that will return the
* same Character object each time.
*
*
* CharUtils.toCharacterObject(null) = null
* CharUtils.toCharacterObject("") = null
* CharUtils.toCharacterObject("A") = 'A'
* CharUtils.toCharacterObject("BA") = 'B'
*
*
* @param str the character to convert
* @return the Character value of the first letter of the String
*/
public static Character toCharacterObject(String str) {
if (StringUtils.isEmpty(str)) {
return null;
}
return toCharacterObject(str.charAt(0));
}
//-----------------------------------------------------------------------
/**
* Converts the Character to a char throwing an exception for null
.
*
*
* CharUtils.toChar(null) = IllegalArgumentException
* CharUtils.toChar(' ') = ' '
* CharUtils.toChar('A') = 'A'
*
*
* @param ch the character to convert
* @return the char value of the Character
* @throws IllegalArgumentException if the Character is null
*/
public static char toChar(Character ch) {
if (ch == null) {
throw new IllegalArgumentException("The Character must not be null");
}
return ch.charValue();
}
/**
* Converts the Character to a char handling null
.
*
*
* CharUtils.toChar(null, 'X') = 'X'
* CharUtils.toChar(' ', 'X') = ' '
* CharUtils.toChar('A', 'X') = 'A'
*
*
* @param ch the character to convert
* @param defaultValue the value to use if the Character is null
* @return the char value of the Character or the default if null
*/
public static char toChar(Character ch, char defaultValue) {
if (ch == null) {
return defaultValue;
}
return ch.charValue();
}
//-----------------------------------------------------------------------
/**
* Converts the String to a char using the first character, throwing
* an exception on empty Strings.
*
*
* CharUtils.toChar(null) = IllegalArgumentException
* CharUtils.toChar("") = IllegalArgumentException
* CharUtils.toChar("A") = 'A'
* CharUtils.toChar("BA") = 'B'
*
*
* @param str the character to convert
* @return the char value of the first letter of the String
* @throws IllegalArgumentException if the String is empty
*/
public static char toChar(String str) {
if (StringUtils.isEmpty(str)) {
throw new IllegalArgumentException("The String must not be empty");
}
return str.charAt(0);
}
/**
* Converts the String to a char using the first character, defaulting
* the value on empty Strings.
*
*
* CharUtils.toChar(null, 'X') = 'X'
* CharUtils.toChar("", 'X') = 'X'
* CharUtils.toChar("A", 'X') = 'A'
* CharUtils.toChar("BA", 'X') = 'B'
*
*
* @param str the character to convert
* @param defaultValue the value to use if the Character is null
* @return the char value of the first letter of the String or the default if null
*/
public static char toChar(String str, char defaultValue) {
if (StringUtils.isEmpty(str)) {
return defaultValue;
}
return str.charAt(0);
}
//-----------------------------------------------------------------------
/**
* Converts the character to the Integer it represents, throwing an
* exception if the character is not numeric.
*
* This method coverts the char '1' to the int 1 and so on.
*
*
* CharUtils.toIntValue('3') = 3
* CharUtils.toIntValue('A') = IllegalArgumentException
*
*
* @param ch the character to convert
* @return the int value of the character
* @throws IllegalArgumentException if the character is not ASCII numeric
*/
public static int toIntValue(char ch) {
if (isAsciiNumeric(ch) == false) {
throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'");
}
return ch - 48;
}
/**
* Converts the character to the Integer it represents, throwing an
* exception if the character is not numeric.
*
* This method coverts the char '1' to the int 1 and so on.
*
*
* CharUtils.toIntValue('3', -1) = 3
* CharUtils.toIntValue('A', -1) = -1
*
*
* @param ch the character to convert
* @param defaultValue the default value to use if the character is not numeric
* @return the int value of the character
*/
public static int toIntValue(char ch, int defaultValue) {
if (isAsciiNumeric(ch) == false) {
return defaultValue;
}
return ch - 48;
}
/**
* Converts the character to the Integer it represents, throwing an
* exception if the character is not numeric.
*
* This method coverts the char '1' to the int 1 and so on.
*
*
* CharUtils.toIntValue(null) = IllegalArgumentException
* CharUtils.toIntValue('3') = 3
* CharUtils.toIntValue('A') = IllegalArgumentException
*
*
* @param ch the character to convert, not null
* @return the int value of the character
* @throws IllegalArgumentException if the Character is not ASCII numeric or is null
*/
public static int toIntValue(Character ch) {
if (ch == null) {
throw new IllegalArgumentException("The character must not be null");
}
return toIntValue(ch.charValue());
}
/**
* Converts the character to the Integer it represents, throwing an
* exception if the character is not numeric.
*
* This method coverts the char '1' to the int 1 and so on.
*
*
* CharUtils.toIntValue(null, -1) = -1
* CharUtils.toIntValue('3', -1) = 3
* CharUtils.toIntValue('A', -1) = -1
*
*
* @param ch the character to convert
* @param defaultValue the default value to use if the character is not numeric
* @return the int value of the character
*/
public static int toIntValue(Character ch, int defaultValue) {
if (ch == null) {
return defaultValue;
}
return toIntValue(ch.charValue(), defaultValue);
}
//-----------------------------------------------------------------------
/**
* Converts the character to a String that contains the one character.
*
* For ASCII 7 bit characters, this uses a cache that will return the
* same String object each time.
*
*
* CharUtils.toString(' ') = " "
* CharUtils.toString('A') = "A"
*
*
* @param ch the character to convert
* @return a String containing the one specified character
*/
public static String toString(char ch) {
if (ch < 128) {
return CHAR_STRING_ARRAY[ch];
}
return new String(new char[] {ch});
}
/**
* Converts the character to a String that contains the one character.
*
* For ASCII 7 bit characters, this uses a cache that will return the
* same String object each time.
*
* If null
is passed in, null
will be returned.
*
*
* CharUtils.toString(null) = null
* CharUtils.toString(' ') = " "
* CharUtils.toString('A') = "A"
*
*
* @param ch the character to convert
* @return a String containing the one specified character
*/
public static String toString(Character ch) {
if (ch == null) {
return null;
}
return toString(ch.charValue());
}
//--------------------------------------------------------------------------
/**
* Converts the string to the unicode format '\u0020'.
*
* This format is the Java source code format.
*
*
* CharUtils.unicodeEscaped(' ') = "\u0020"
* CharUtils.unicodeEscaped('A') = "\u0041"
*
*
* @param ch the character to convert
* @return the escaped unicode string
*/
public static String unicodeEscaped(char ch) {
if (ch < 0x10) {
return "\\u000" + Integer.toHexString(ch);
} else if (ch < 0x100) {
return "\\u00" + Integer.toHexString(ch);
} else if (ch < 0x1000) {
return "\\u0" + Integer.toHexString(ch);
}
return "\\u" + Integer.toHexString(ch);
}
/**
* Converts the string to the unicode format '\u0020'.
*
* This format is the Java source code format.
*
* If null
is passed in, null
will be returned.
*
*
* CharUtils.unicodeEscaped(null) = null
* CharUtils.unicodeEscaped(' ') = "\u0020"
* CharUtils.unicodeEscaped('A') = "\u0041"
*
*
* @param ch the character to convert, may be null
* @return the escaped unicode string, null if null input
*/
public static String unicodeEscaped(Character ch) {
if (ch == null) {
return null;
}
return unicodeEscaped(ch.charValue());
}
//--------------------------------------------------------------------------
/**
* Checks whether the character is ASCII 7 bit.
*
*
* CharUtils.isAscii('a') = true
* CharUtils.isAscii('A') = true
* CharUtils.isAscii('3') = true
* CharUtils.isAscii('-') = true
* CharUtils.isAscii('\n') = true
* CharUtils.isAscii('©') = false
*
*
* @param ch the character to check
* @return true if less than 128
*/
public static boolean isAscii(char ch) {
return ch < 128;
}
/**
* Checks whether the character is ASCII 7 bit printable.
*
*
* CharUtils.isAsciiPrintable('a') = true
* CharUtils.isAsciiPrintable('A') = true
* CharUtils.isAsciiPrintable('3') = true
* CharUtils.isAsciiPrintable('-') = true
* CharUtils.isAsciiPrintable('\n') = false
* CharUtils.isAsciiPrintable('©') = false
*
*
* @param ch the character to check
* @return true if between 32 and 126 inclusive
*/
public static boolean isAsciiPrintable(char ch) {
return ch >= 32 && ch < 127;
}
/**
* Checks whether the character is ASCII 7 bit control.
*
*
* CharUtils.isAsciiControl('a') = false
* CharUtils.isAsciiControl('A') = false
* CharUtils.isAsciiControl('3') = false
* CharUtils.isAsciiControl('-') = false
* CharUtils.isAsciiControl('\n') = true
* CharUtils.isAsciiControl('©') = false
*
*
* @param ch the character to check
* @return true if less than 32 or equals 127
*/
public static boolean isAsciiControl(char ch) {
return ch < 32 || ch == 127;
}
/**
* Checks whether the character is ASCII 7 bit alphabetic.
*
*
* CharUtils.isAsciiAlpha('a') = true
* CharUtils.isAsciiAlpha('A') = true
* CharUtils.isAsciiAlpha('3') = false
* CharUtils.isAsciiAlpha('-') = false
* CharUtils.isAsciiAlpha('\n') = false
* CharUtils.isAsciiAlpha('©') = false
*
*
* @param ch the character to check
* @return true if between 65 and 90 or 97 and 122 inclusive
*/
public static boolean isAsciiAlpha(char ch) {
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
}
/**
* Checks whether the character is ASCII 7 bit alphabetic upper case.
*
*
* CharUtils.isAsciiAlphaUpper('a') = false
* CharUtils.isAsciiAlphaUpper('A') = true
* CharUtils.isAsciiAlphaUpper('3') = false
* CharUtils.isAsciiAlphaUpper('-') = false
* CharUtils.isAsciiAlphaUpper('\n') = false
* CharUtils.isAsciiAlphaUpper('©') = false
*
*
* @param ch the character to check
* @return true if between 65 and 90 inclusive
*/
public static boolean isAsciiAlphaUpper(char ch) {
return ch >= 'A' && ch <= 'Z';
}
/**
* Checks whether the character is ASCII 7 bit alphabetic lower case.
*
*
* CharUtils.isAsciiAlphaLower('a') = true
* CharUtils.isAsciiAlphaLower('A') = false
* CharUtils.isAsciiAlphaLower('3') = false
* CharUtils.isAsciiAlphaLower('-') = false
* CharUtils.isAsciiAlphaLower('\n') = false
* CharUtils.isAsciiAlphaLower('©') = false
*
*
* @param ch the character to check
* @return true if between 97 and 122 inclusive
*/
public static boolean isAsciiAlphaLower(char ch) {
return ch >= 'a' && ch <= 'z';
}
/**
* Checks whether the character is ASCII 7 bit numeric.
*
*
* CharUtils.isAsciiNumeric('a') = false
* CharUtils.isAsciiNumeric('A') = false
* CharUtils.isAsciiNumeric('3') = true
* CharUtils.isAsciiNumeric('-') = false
* CharUtils.isAsciiNumeric('\n') = false
* CharUtils.isAsciiNumeric('©') = false
*
*
* @param ch the character to check
* @return true if between 48 and 57 inclusive
*/
public static boolean isAsciiNumeric(char ch) {
return ch >= '0' && ch <= '9';
}
/**
* Checks whether the character is ASCII 7 bit numeric.
*
*
* CharUtils.isAsciiAlphanumeric('a') = true
* CharUtils.isAsciiAlphanumeric('A') = true
* CharUtils.isAsciiAlphanumeric('3') = true
* CharUtils.isAsciiAlphanumeric('-') = false
* CharUtils.isAsciiAlphanumeric('\n') = false
* CharUtils.isAsciiAlphanumeric('©') = false
*
*
* @param ch the character to check
* @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive
*/
public static boolean isAsciiAlphanumeric(char ch) {
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9');
}
// ----------------- Following code copied from Apache Harmony (Character class)
/**
* Indicates whether {@code ch} is a high- (or leading-) surrogate code unit
* that is used for representing supplementary characters in UTF-16
* encoding.
*
* @param ch
* the character to test.
* @return {@code true} if {@code ch} is a high-surrogate code unit;
* {@code false} otherwise.
*/
static boolean isHighSurrogate(char ch) {
return ('\uD800' <= ch && '\uDBFF' >= ch);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/ClassUtils.java 100644 0 0 125602 11513702445 23730 0 ustar 0 0 /*
* 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.lang;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.text.StrBuilder;
/**
* Operates on classes without using reflection.
*
* This class handles invalid null
inputs as best it can.
* Each method documents its behaviour in more detail.
*
* The notion of a canonical name
includes the human
* readable name for the type, for example int[]
. The
* non-canonical method variants work with the JVM names, such as
* [I
.
*
* @author Apache Software Foundation
* @author Gary Gregory
* @author Norm Deane
* @author Alban Peignier
* @author Tomasz Blachowicz
* @since 2.0
* @version $Id: ClassUtils.java 1057072 2011-01-10 01:55:57Z niallp $
*/
public class ClassUtils {
/**
* The package separator character: '.' == {@value}
.
*/
public static final char PACKAGE_SEPARATOR_CHAR = '.';
/**
* The package separator String: "."
.
*/
public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR);
/**
* The inner class separator character: '$' == {@value}
.
*/
public static final char INNER_CLASS_SEPARATOR_CHAR = '$';
/**
* The inner class separator String: "$"
.
*/
public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR);
/**
* Maps primitive Class
es to their corresponding wrapper Class
.
*/
private static final Map primitiveWrapperMap = new HashMap();
static {
primitiveWrapperMap.put(Boolean.TYPE, Boolean.class);
primitiveWrapperMap.put(Byte.TYPE, Byte.class);
primitiveWrapperMap.put(Character.TYPE, Character.class);
primitiveWrapperMap.put(Short.TYPE, Short.class);
primitiveWrapperMap.put(Integer.TYPE, Integer.class);
primitiveWrapperMap.put(Long.TYPE, Long.class);
primitiveWrapperMap.put(Double.TYPE, Double.class);
primitiveWrapperMap.put(Float.TYPE, Float.class);
primitiveWrapperMap.put(Void.TYPE, Void.TYPE);
}
/**
* Maps wrapper Class
es to their corresponding primitive types.
*/
private static final Map wrapperPrimitiveMap = new HashMap();
static {
for (Iterator it = primitiveWrapperMap.keySet().iterator(); it.hasNext();) {
Class primitiveClass = (Class) it.next();
Class wrapperClass = (Class) primitiveWrapperMap.get(primitiveClass);
if (!primitiveClass.equals(wrapperClass)) {
wrapperPrimitiveMap.put(wrapperClass, primitiveClass);
}
}
}
/**
* Maps a primitive class name to its corresponding abbreviation used in array class names.
*/
private static final Map abbreviationMap = new HashMap();
/**
* Maps an abbreviation used in array class names to corresponding primitive class name.
*/
private static final Map reverseAbbreviationMap = new HashMap();
/**
* Add primitive type abbreviation to maps of abbreviations.
*
* @param primitive Canonical name of primitive type
* @param abbreviation Corresponding abbreviation of primitive type
*/
private static void addAbbreviation(String primitive, String abbreviation) {
abbreviationMap.put(primitive, abbreviation);
reverseAbbreviationMap.put(abbreviation, primitive);
}
/**
* Feed abbreviation maps
*/
static {
addAbbreviation("int", "I");
addAbbreviation("boolean", "Z");
addAbbreviation("float", "F");
addAbbreviation("long", "J");
addAbbreviation("short", "S");
addAbbreviation("byte", "B");
addAbbreviation("double", "D");
addAbbreviation("char", "C");
}
/**
* ClassUtils instances should NOT be constructed in standard programming.
* Instead, the class should be used as
* 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 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 Class
.
*
* @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.
*
* @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;
}
StrBuilder arrayPrefix = new StrBuilder();
// 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 = (String)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;
}
// Package name
// ----------------------------------------------------------------------
/**
* Gets the package name of an 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 Class
.
*
* @param cls the class to get the package name for, may be 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 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 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 List
of superclasses for the given class.
*
* @param cls the class to look up, may be null
* @return the List
of superclasses in order going up from this one
* null
if null input
*/
public static List getAllSuperclasses(Class cls) {
if (cls == null) {
return null;
}
List classes = new ArrayList();
Class superclass = cls.getSuperclass();
while (superclass != null) {
classes.add(superclass);
superclass = superclass.getSuperclass();
}
return classes;
}
/**
* Gets a 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 null
* @return the List
of interfaces in order,
* null
if null input
*/
public static List getAllInterfaces(Class cls) {
if (cls == null) {
return null;
}
List interfacesFound = new ArrayList();
getAllInterfaces(cls, interfacesFound);
return interfacesFound;
}
/**
* Get the interfaces for the specified class.
*
* @param cls the class to look up, may be null
* @param interfacesFound the Set
of interfaces for the class
*/
private static void getAllInterfaces(Class cls, List interfacesFound) {
while (cls != null) {
Class[] interfaces = cls.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
if (!interfacesFound.contains(interfaces[i])) {
interfacesFound.add(interfaces[i]);
getAllInterfaces(interfaces[i], interfacesFound);
}
}
cls = cls.getSuperclass();
}
}
// Convert list
// ----------------------------------------------------------------------
/**
* Given a List
of class names, this method converts them into classes.
*
* A new List
is returned. If the class name cannot be found, null
* is stored in the List
. If the class name in the List
is
* null
, null
is stored in the output List
.
*
* @param classNames the classNames to change
* @return a List
of Class objects corresponding to the class names,
* null
if null input
* @throws ClassCastException if classNames contains a non String entry
*/
public static List convertClassNamesToClasses(List classNames) {
if (classNames == null) {
return null;
}
List classes = new ArrayList(classNames.size());
for (Iterator it = classNames.iterator(); it.hasNext();) {
String className = (String) it.next();
try {
classes.add(Class.forName(className));
} catch (Exception ex) {
classes.add(null);
}
}
return classes;
}
/**
* Given a List
of Class
objects, this method converts
* them into class names.
*
* A new List
is returned. null
objects will be copied into
* the returned list as null
.
*
* @param classes the classes to change
* @return a List
of class names corresponding to the Class objects,
* null
if null input
* @throws ClassCastException if classes
contains a non-Class
entry
*/
public static List convertClassesToClassNames(List classes) {
if (classes == null) {
return null;
}
List classNames = new ArrayList(classes.size());
for (Iterator it = classes.iterator(); it.hasNext();) {
Class cls = (Class) it.next();
if (cls == null) {
classNames.add(null);
} else {
classNames.add(cls.getName());
}
}
return classNames;
}
// Is assignable
// ----------------------------------------------------------------------
/**
* 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
* 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.
*
* Null
may be assigned to any reference type. This method will
* return true
if null
is passed in and the toClass is
* non-primitive.
*
* Specifically, this method tests whether the type represented by the
* specified Class
parameter can be converted to the type
* represented by this 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 null
* @param toClassArray the array of Classes to try to assign into, may be null
* @return true
if assignment possible
*/
public static boolean isAssignable(Class[] classArray, Class[] toClassArray) {
return isAssignable(classArray, toClassArray, false);
}
/**
* 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
* 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.
*
* Null
may be assigned to any reference type. This method will
* return true
if null
is passed in and the toClass is
* non-primitive.
*
* Specifically, this method tests whether the type represented by the
* specified Class
parameter can be converted to the type
* represented by this 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 null
* @param toClassArray the array of Classes to try to assign into, may be null
* @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers
* @return true
if assignment possible
* @since 2.5
*/
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 Class
can be assigned to a variable of
* another Class
.
*
* Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
* this method takes into account widenings of primitive classes and
* 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.
*
* Null
may be assigned to any reference type. This method
* will return true
if null
is passed in and the
* toClass is non-primitive.
*
* Specifically, this method tests whether the type represented by the
* specified Class
parameter can be converted to the type
* represented by this 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
* @return true
if assignment possible
*/
public static boolean isAssignable(Class cls, Class toClass) {
return isAssignable(cls, toClass, false);
}
/**
* Checks if one Class
can be assigned to a variable of
* another Class
.
*
* Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
* this method takes into account widenings of primitive classes and
* 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.
*
* Null
may be assigned to any reference type. This method
* will return true
if null
is passed in and the
* toClass is non-primitive.
*
* Specifically, this method tests whether the type represented by the
* specified Class
parameter can be converted to the type
* represented by this 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 true
if assignment possible
* @since 2.5
*/
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 Void.TYPE
,
* returning Void.TYPE
.
*
* @param cls the class to convert, may be null
* @return the wrapper class for cls
or cls
if
* cls
is not a primitive. null
if null input.
* @since 2.1
*/
public static Class primitiveToWrapper(Class cls) {
Class convertedClass = cls;
if (cls != null && cls.isPrimitive()) {
convertedClass = (Class) 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. 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 primitiveToWrapper()
.
* If the passed in class is a wrapper class for a primitive type, this
* primitive type will be returned (e.g. Integer.TYPE
for
* 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 cls
is a
* wrapper class, null otherwise
* @see #primitiveToWrapper(Class)
* @since 2.4
*/
public static Class wrapperToPrimitive(Class cls) {
return (Class) wrapperPrimitiveMap.get(cls);
}
/**
* Converts the specified array of wrapper Class objects to an array of
* its corresponding primitive Class objects.
*
* This method invokes 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. 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 true
if the class is an inner or static nested class,
* false if not or null
*/
public static boolean isInnerClass(Class cls) {
if (cls == null) {
return false;
}
return cls.getName().indexOf(INNER_CLASS_SEPARATOR_CHAR) >= 0;
}
// Class loading
// ----------------------------------------------------------------------
/**
* Returns the class represented by className
using the
* classLoader
. This implementation supports the syntaxes
* "java.util.Map.Entry[]
", "java.util.Map$Entry[]
",
* "[Ljava.util.Map.Entry;
", and "[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 className
using the 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) {
}
}
throw ex;
}
}
/**
* Returns the (initialized) class represented by className
* using the classLoader
. This implementation supports
* the syntaxes "java.util.Map.Entry[]
",
* "java.util.Map$Entry[]
", "[Ljava.util.Map.Entry;
",
* and "[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 className
using the 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 className
* using the current thread's context class loader. This implementation
* supports the syntaxes "java.util.Map.Entry[]
",
* "java.util.Map$Entry[]
", "[Ljava.util.Map.Entry;
",
* and "[Ljava.util.Map$Entry;
".
*
* @param className the class name
* @return the class represented by 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 className
using the
* current thread's context class loader. This implementation supports the
* syntaxes "java.util.Map.Entry[]
", "java.util.Map$Entry[]
",
* "[Ljava.util.Map.Entry;
", and "[Ljava.util.Map$Entry;
".
*
* @param className the class name
* @param initialize whether the class must be initialized
* @return the class represented by 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 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[]);
*
*
* @param cls the class to check, not null
* @param methodName the name of the method
* @param parameterTypes the list of parameters
* @return the method
* @throws NullPointerException if the class is null
* @throws SecurityException if a a security violation occured
* @throws NoSuchMethodException if the method is not found in the given class
* or if the metothod doen't conform with the requirements
*/
public static Method getPublicMethod(Class cls, String methodName, Class parameterTypes[])
throws SecurityException, NoSuchMethodException {
Method declaredMethod = cls.getMethod(methodName, parameterTypes);
if (Modifier.isPublic(declaredMethod.getDeclaringClass().getModifiers())) {
return declaredMethod;
}
List candidateClasses = new ArrayList();
candidateClasses.addAll(getAllInterfaces(cls));
candidateClasses.addAll(getAllSuperclasses(cls));
for (Iterator it = candidateClasses.iterator(); it.hasNext(); ) {
Class candidateClass = (Class) it.next();
if (!Modifier.isPublic(candidateClass.getModifiers())) {
continue;
}
Method candidateMethod;
try {
candidateMethod = candidateClass.getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException ex) {
continue;
}
if (Modifier.isPublic(candidateMethod.getDeclaringClass().getModifiers())) {
return candidateMethod;
}
}
throw new NoSuchMethodException("Can't find a public method for " +
methodName + " " + ArrayUtils.toString(parameterTypes));
}
// ----------------------------------------------------------------------
/**
* Converts a class name to a JLS style class name.
*
* @param className the class name
* @return the converted name
*/
private static String toCanonicalName(String className) {
className = StringUtils.deleteWhitespace(className);
if (className == null) {
throw new NullArgumentException("className");
} else if (className.endsWith("[]")) {
StrBuilder classNameBuffer = new StrBuilder();
while (className.endsWith("[]")) {
className = className.substring(0, className.length() - 2);
classNameBuffer.append("[");
}
String abbreviation = (String) abbreviationMap.get(className);
if (abbreviation != null) {
classNameBuffer.append(abbreviation);
} else {
classNameBuffer.append("L").append(className).append(";");
}
className = classNameBuffer.toString();
}
return className;
}
/**
* Converts an array of Object
in to an array of Class
objects.
* If any of these objects is null, a null element will be inserted into the array.
*
* This method returns null
for a null
input array.
*
* @param array an Object
array
* @return a Class
array, 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 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 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 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 Class
.
*
* @param cls the class to get the package name for, may be 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 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:
*
* getCanonicalName("[I") = "int[]"
* getCanonicalName("[Ljava.lang.String;") = "java.lang.String[]"
* getCanonicalName("java.lang.String") = "java.lang.String"
*
*
*
* @param className the name of class
* @return canonical form of class name
* @since 2.4
*/
private static String getCanonicalName(String className) {
className = StringUtils.deleteWhitespace(className);
if (className == null) {
return null;
} else {
int dim = 0;
while (className.startsWith("[")) {
dim++;
className = className.substring(1);
}
if (dim < 1) {
return className;
} else {
if (className.startsWith("L")) {
className = className.substring(
1,
className.endsWith(";")
? className.length() - 1
: className.length());
} else {
if (className.length() > 0) {
className = (String) reverseAbbreviationMap.get(
className.substring(0, 1));
}
}
StrBuilder canonicalClassNameBuffer = new StrBuilder(className);
for (int i = 0; i < dim; i++) {
canonicalClassNameBuffer.append("[]");
}
return canonicalClassNameBuffer.toString();
}
}
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/Entities.java 100644 0 0 123266 11513702446 23433 0 ustar 0 0 /*
* 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.lang;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
/**
*
* Provides HTML and XML entity utilities.
*
*
* @see ISO Entities
* @see HTML 3.2 Character Entities for ISO Latin-1
* @see HTML 4.0 Character entity references
* @see HTML 4.01 Character References
* @see HTML 4.01 Code positions
*
* @author Alexander Day Chaffee
* @author Gary Gregory
* @since 2.0
* @version $Id: Entities.java 1057037 2011-01-09 21:35:32Z niallp $
*/
class Entities {
private static final String[][] BASIC_ARRAY = {{"quot", "34"}, // " - double-quote
{"amp", "38"}, // & - ampersand
{"lt", "60"}, // < - less-than
{"gt", "62"}, // > - greater-than
};
private static final String[][] APOS_ARRAY = {{"apos", "39"}, // XML apostrophe
};
// package scoped for testing
static final String[][] ISO8859_1_ARRAY = {{"nbsp", "160"}, // non-breaking space
{"iexcl", "161"}, // inverted exclamation mark
{"cent", "162"}, // cent sign
{"pound", "163"}, // pound sign
{"curren", "164"}, // currency sign
{"yen", "165"}, // yen sign = yuan sign
{"brvbar", "166"}, // broken bar = broken vertical bar
{"sect", "167"}, // section sign
{"uml", "168"}, // diaeresis = spacing diaeresis
{"copy", "169"}, // © - copyright sign
{"ordf", "170"}, // feminine ordinal indicator
{"laquo", "171"}, // left-pointing double angle quotation mark = left pointing guillemet
{"not", "172"}, // not sign
{"shy", "173"}, // soft hyphen = discretionary hyphen
{"reg", "174"}, // ® - registered trademark sign
{"macr", "175"}, // macron = spacing macron = overline = APL overbar
{"deg", "176"}, // degree sign
{"plusmn", "177"}, // plus-minus sign = plus-or-minus sign
{"sup2", "178"}, // superscript two = superscript digit two = squared
{"sup3", "179"}, // superscript three = superscript digit three = cubed
{"acute", "180"}, // acute accent = spacing acute
{"micro", "181"}, // micro sign
{"para", "182"}, // pilcrow sign = paragraph sign
{"middot", "183"}, // middle dot = Georgian comma = Greek middle dot
{"cedil", "184"}, // cedilla = spacing cedilla
{"sup1", "185"}, // superscript one = superscript digit one
{"ordm", "186"}, // masculine ordinal indicator
{"raquo", "187"}, // right-pointing double angle quotation mark = right pointing guillemet
{"frac14", "188"}, // vulgar fraction one quarter = fraction one quarter
{"frac12", "189"}, // vulgar fraction one half = fraction one half
{"frac34", "190"}, // vulgar fraction three quarters = fraction three quarters
{"iquest", "191"}, // inverted question mark = turned question mark
{"Agrave", "192"}, // À - uppercase A, grave accent
{"Aacute", "193"}, // Á - uppercase A, acute accent
{"Acirc", "194"}, // Â - uppercase A, circumflex accent
{"Atilde", "195"}, // Ã - uppercase A, tilde
{"Auml", "196"}, // Ä - uppercase A, umlaut
{"Aring", "197"}, // Å - uppercase A, ring
{"AElig", "198"}, // Æ - uppercase AE
{"Ccedil", "199"}, // Ç - uppercase C, cedilla
{"Egrave", "200"}, // È - uppercase E, grave accent
{"Eacute", "201"}, // É - uppercase E, acute accent
{"Ecirc", "202"}, // Ê - uppercase E, circumflex accent
{"Euml", "203"}, // Ë - uppercase E, umlaut
{"Igrave", "204"}, // Ì - uppercase I, grave accent
{"Iacute", "205"}, // Í - uppercase I, acute accent
{"Icirc", "206"}, // Î - uppercase I, circumflex accent
{"Iuml", "207"}, // Ï - uppercase I, umlaut
{"ETH", "208"}, // Ð - uppercase Eth, Icelandic
{"Ntilde", "209"}, // Ñ - uppercase N, tilde
{"Ograve", "210"}, // Ò - uppercase O, grave accent
{"Oacute", "211"}, // Ó - uppercase O, acute accent
{"Ocirc", "212"}, // Ô - uppercase O, circumflex accent
{"Otilde", "213"}, // Õ - uppercase O, tilde
{"Ouml", "214"}, // Ö - uppercase O, umlaut
{"times", "215"}, // multiplication sign
{"Oslash", "216"}, // Ø - uppercase O, slash
{"Ugrave", "217"}, // Ù - uppercase U, grave accent
{"Uacute", "218"}, // Ú - uppercase U, acute accent
{"Ucirc", "219"}, // Û - uppercase U, circumflex accent
{"Uuml", "220"}, // Ü - uppercase U, umlaut
{"Yacute", "221"}, // Ý - uppercase Y, acute accent
{"THORN", "222"}, // Þ - uppercase THORN, Icelandic
{"szlig", "223"}, // ß - lowercase sharps, German
{"agrave", "224"}, // à - lowercase a, grave accent
{"aacute", "225"}, // á - lowercase a, acute accent
{"acirc", "226"}, // â - lowercase a, circumflex accent
{"atilde", "227"}, // ã - lowercase a, tilde
{"auml", "228"}, // ä - lowercase a, umlaut
{"aring", "229"}, // å - lowercase a, ring
{"aelig", "230"}, // æ - lowercase ae
{"ccedil", "231"}, // ç - lowercase c, cedilla
{"egrave", "232"}, // è - lowercase e, grave accent
{"eacute", "233"}, // é - lowercase e, acute accent
{"ecirc", "234"}, // ê - lowercase e, circumflex accent
{"euml", "235"}, // ë - lowercase e, umlaut
{"igrave", "236"}, // ì - lowercase i, grave accent
{"iacute", "237"}, // í - lowercase i, acute accent
{"icirc", "238"}, // î - lowercase i, circumflex accent
{"iuml", "239"}, // ï - lowercase i, umlaut
{"eth", "240"}, // ð - lowercase eth, Icelandic
{"ntilde", "241"}, // ñ - lowercase n, tilde
{"ograve", "242"}, // ò - lowercase o, grave accent
{"oacute", "243"}, // ó - lowercase o, acute accent
{"ocirc", "244"}, // ô - lowercase o, circumflex accent
{"otilde", "245"}, // õ - lowercase o, tilde
{"ouml", "246"}, // ö - lowercase o, umlaut
{"divide", "247"}, // division sign
{"oslash", "248"}, // ø - lowercase o, slash
{"ugrave", "249"}, // ù - lowercase u, grave accent
{"uacute", "250"}, // ú - lowercase u, acute accent
{"ucirc", "251"}, // û - lowercase u, circumflex accent
{"uuml", "252"}, // ü - lowercase u, umlaut
{"yacute", "253"}, // ý - lowercase y, acute accent
{"thorn", "254"}, // þ - lowercase thorn, Icelandic
{"yuml", "255"}, // ÿ - lowercase y, umlaut
};
// http://www.w3.org/TR/REC-html40/sgml/entities.html
// package scoped for testing
static final String[][] HTML40_ARRAY = {
//
{"fnof", "402"}, // latin small f with hook = function= florin, U+0192 ISOtech -->
//
{"Alpha", "913"}, // greek capital letter alpha, U+0391 -->
{"Beta", "914"}, // greek capital letter beta, U+0392 -->
{"Gamma", "915"}, // greek capital letter gamma,U+0393 ISOgrk3 -->
{"Delta", "916"}, // greek capital letter delta,U+0394 ISOgrk3 -->
{"Epsilon", "917"}, // greek capital letter epsilon, U+0395 -->
{"Zeta", "918"}, // greek capital letter zeta, U+0396 -->
{"Eta", "919"}, // greek capital letter eta, U+0397 -->
{"Theta", "920"}, // greek capital letter theta,U+0398 ISOgrk3 -->
{"Iota", "921"}, // greek capital letter iota, U+0399 -->
{"Kappa", "922"}, // greek capital letter kappa, U+039A -->
{"Lambda", "923"}, // greek capital letter lambda,U+039B ISOgrk3 -->
{"Mu", "924"}, // greek capital letter mu, U+039C -->
{"Nu", "925"}, // greek capital letter nu, U+039D -->
{"Xi", "926"}, // greek capital letter xi, U+039E ISOgrk3 -->
{"Omicron", "927"}, // greek capital letter omicron, U+039F -->
{"Pi", "928"}, // greek capital letter pi, U+03A0 ISOgrk3 -->
{"Rho", "929"}, // greek capital letter rho, U+03A1 -->
//
{"Sigma", "931"}, // greek capital letter sigma,U+03A3 ISOgrk3 -->
{"Tau", "932"}, // greek capital letter tau, U+03A4 -->
{"Upsilon", "933"}, // greek capital letter upsilon,U+03A5 ISOgrk3 -->
{"Phi", "934"}, // greek capital letter phi,U+03A6 ISOgrk3 -->
{"Chi", "935"}, // greek capital letter chi, U+03A7 -->
{"Psi", "936"}, // greek capital letter psi,U+03A8 ISOgrk3 -->
{"Omega", "937"}, // greek capital letter omega,U+03A9 ISOgrk3 -->
{"alpha", "945"}, // greek small letter alpha,U+03B1 ISOgrk3 -->
{"beta", "946"}, // greek small letter beta, U+03B2 ISOgrk3 -->
{"gamma", "947"}, // greek small letter gamma,U+03B3 ISOgrk3 -->
{"delta", "948"}, // greek small letter delta,U+03B4 ISOgrk3 -->
{"epsilon", "949"}, // greek small letter epsilon,U+03B5 ISOgrk3 -->
{"zeta", "950"}, // greek small letter zeta, U+03B6 ISOgrk3 -->
{"eta", "951"}, // greek small letter eta, U+03B7 ISOgrk3 -->
{"theta", "952"}, // greek small letter theta,U+03B8 ISOgrk3 -->
{"iota", "953"}, // greek small letter iota, U+03B9 ISOgrk3 -->
{"kappa", "954"}, // greek small letter kappa,U+03BA ISOgrk3 -->
{"lambda", "955"}, // greek small letter lambda,U+03BB ISOgrk3 -->
{"mu", "956"}, // greek small letter mu, U+03BC ISOgrk3 -->
{"nu", "957"}, // greek small letter nu, U+03BD ISOgrk3 -->
{"xi", "958"}, // greek small letter xi, U+03BE ISOgrk3 -->
{"omicron", "959"}, // greek small letter omicron, U+03BF NEW -->
{"pi", "960"}, // greek small letter pi, U+03C0 ISOgrk3 -->
{"rho", "961"}, // greek small letter rho, U+03C1 ISOgrk3 -->
{"sigmaf", "962"}, // greek small letter final sigma,U+03C2 ISOgrk3 -->
{"sigma", "963"}, // greek small letter sigma,U+03C3 ISOgrk3 -->
{"tau", "964"}, // greek small letter tau, U+03C4 ISOgrk3 -->
{"upsilon", "965"}, // greek small letter upsilon,U+03C5 ISOgrk3 -->
{"phi", "966"}, // greek small letter phi, U+03C6 ISOgrk3 -->
{"chi", "967"}, // greek small letter chi, U+03C7 ISOgrk3 -->
{"psi", "968"}, // greek small letter psi, U+03C8 ISOgrk3 -->
{"omega", "969"}, // greek small letter omega,U+03C9 ISOgrk3 -->
{"thetasym", "977"}, // greek small letter theta symbol,U+03D1 NEW -->
{"upsih", "978"}, // greek upsilon with hook symbol,U+03D2 NEW -->
{"piv", "982"}, // greek pi symbol, U+03D6 ISOgrk3 -->
//
{"bull", "8226"}, // bullet = black small circle,U+2022 ISOpub -->
//
{"hellip", "8230"}, // horizontal ellipsis = three dot leader,U+2026 ISOpub -->
{"prime", "8242"}, // prime = minutes = feet, U+2032 ISOtech -->
{"Prime", "8243"}, // double prime = seconds = inches,U+2033 ISOtech -->
{"oline", "8254"}, // overline = spacing overscore,U+203E NEW -->
{"frasl", "8260"}, // fraction slash, U+2044 NEW -->
//
{"weierp", "8472"}, // script capital P = power set= Weierstrass p, U+2118 ISOamso -->
{"image", "8465"}, // blackletter capital I = imaginary part,U+2111 ISOamso -->
{"real", "8476"}, // blackletter capital R = real part symbol,U+211C ISOamso -->
{"trade", "8482"}, // trade mark sign, U+2122 ISOnum -->
{"alefsym", "8501"}, // alef symbol = first transfinite cardinal,U+2135 NEW -->
//
//
{"larr", "8592"}, // leftwards arrow, U+2190 ISOnum -->
{"uarr", "8593"}, // upwards arrow, U+2191 ISOnum-->
{"rarr", "8594"}, // rightwards arrow, U+2192 ISOnum -->
{"darr", "8595"}, // downwards arrow, U+2193 ISOnum -->
{"harr", "8596"}, // left right arrow, U+2194 ISOamsa -->
{"crarr", "8629"}, // downwards arrow with corner leftwards= carriage return, U+21B5 NEW -->
{"lArr", "8656"}, // leftwards double arrow, U+21D0 ISOtech -->
//
{"uArr", "8657"}, // upwards double arrow, U+21D1 ISOamsa -->
{"rArr", "8658"}, // rightwards double arrow,U+21D2 ISOtech -->
//
{"dArr", "8659"}, // downwards double arrow, U+21D3 ISOamsa -->
{"hArr", "8660"}, // left right double arrow,U+21D4 ISOamsa -->
//
{"forall", "8704"}, // for all, U+2200 ISOtech -->
{"part", "8706"}, // partial differential, U+2202 ISOtech -->
{"exist", "8707"}, // there exists, U+2203 ISOtech -->
{"empty", "8709"}, // empty set = null set = diameter,U+2205 ISOamso -->
{"nabla", "8711"}, // nabla = backward difference,U+2207 ISOtech -->
{"isin", "8712"}, // element of, U+2208 ISOtech -->
{"notin", "8713"}, // not an element of, U+2209 ISOtech -->
{"ni", "8715"}, // contains as member, U+220B ISOtech -->
//
{"prod", "8719"}, // n-ary product = product sign,U+220F ISOamsb -->
//
{"sum", "8721"}, // n-ary summation, U+2211 ISOamsb -->
//
{"minus", "8722"}, // minus sign, U+2212 ISOtech -->
{"lowast", "8727"}, // asterisk operator, U+2217 ISOtech -->
{"radic", "8730"}, // square root = radical sign,U+221A ISOtech -->
{"prop", "8733"}, // proportional to, U+221D ISOtech -->
{"infin", "8734"}, // infinity, U+221E ISOtech -->
{"ang", "8736"}, // angle, U+2220 ISOamso -->
{"and", "8743"}, // logical and = wedge, U+2227 ISOtech -->
{"or", "8744"}, // logical or = vee, U+2228 ISOtech -->
{"cap", "8745"}, // intersection = cap, U+2229 ISOtech -->
{"cup", "8746"}, // union = cup, U+222A ISOtech -->
{"int", "8747"}, // integral, U+222B ISOtech -->
{"there4", "8756"}, // therefore, U+2234 ISOtech -->
{"sim", "8764"}, // tilde operator = varies with = similar to,U+223C ISOtech -->
//
{"cong", "8773"}, // approximately equal to, U+2245 ISOtech -->
{"asymp", "8776"}, // almost equal to = asymptotic to,U+2248 ISOamsr -->
{"ne", "8800"}, // not equal to, U+2260 ISOtech -->
{"equiv", "8801"}, // identical to, U+2261 ISOtech -->
{"le", "8804"}, // less-than or equal to, U+2264 ISOtech -->
{"ge", "8805"}, // greater-than or equal to,U+2265 ISOtech -->
{"sub", "8834"}, // subset of, U+2282 ISOtech -->
{"sup", "8835"}, // superset of, U+2283 ISOtech -->
//
{"sube", "8838"}, // subset of or equal to, U+2286 ISOtech -->
{"supe", "8839"}, // superset of or equal to,U+2287 ISOtech -->
{"oplus", "8853"}, // circled plus = direct sum,U+2295 ISOamsb -->
{"otimes", "8855"}, // circled times = vector product,U+2297 ISOamsb -->
{"perp", "8869"}, // up tack = orthogonal to = perpendicular,U+22A5 ISOtech -->
{"sdot", "8901"}, // dot operator, U+22C5 ISOamsb -->
//
//
{"lceil", "8968"}, // left ceiling = apl upstile,U+2308 ISOamsc -->
{"rceil", "8969"}, // right ceiling, U+2309 ISOamsc -->
{"lfloor", "8970"}, // left floor = apl downstile,U+230A ISOamsc -->
{"rfloor", "8971"}, // right floor, U+230B ISOamsc -->
{"lang", "9001"}, // left-pointing angle bracket = bra,U+2329 ISOtech -->
//
{"rang", "9002"}, // right-pointing angle bracket = ket,U+232A ISOtech -->
//
//
{"loz", "9674"}, // lozenge, U+25CA ISOpub -->
//
{"spades", "9824"}, // black spade suit, U+2660 ISOpub -->
//
{"clubs", "9827"}, // black club suit = shamrock,U+2663 ISOpub -->
{"hearts", "9829"}, // black heart suit = valentine,U+2665 ISOpub -->
{"diams", "9830"}, // black diamond suit, U+2666 ISOpub -->
//
{"OElig", "338"}, // -- latin capital ligature OE,U+0152 ISOlat2 -->
{"oelig", "339"}, // -- latin small ligature oe, U+0153 ISOlat2 -->
//
{"Scaron", "352"}, // -- latin capital letter S with caron,U+0160 ISOlat2 -->
{"scaron", "353"}, // -- latin small letter s with caron,U+0161 ISOlat2 -->
{"Yuml", "376"}, // -- latin capital letter Y with diaeresis,U+0178 ISOlat2 -->
//
{"circ", "710"}, // -- modifier letter circumflex accent,U+02C6 ISOpub -->
{"tilde", "732"}, // small tilde, U+02DC ISOdia -->
//
{"ensp", "8194"}, // en space, U+2002 ISOpub -->
{"emsp", "8195"}, // em space, U+2003 ISOpub -->
{"thinsp", "8201"}, // thin space, U+2009 ISOpub -->
{"zwnj", "8204"}, // zero width non-joiner,U+200C NEW RFC 2070 -->
{"zwj", "8205"}, // zero width joiner, U+200D NEW RFC 2070 -->
{"lrm", "8206"}, // left-to-right mark, U+200E NEW RFC 2070 -->
{"rlm", "8207"}, // right-to-left mark, U+200F NEW RFC 2070 -->
{"ndash", "8211"}, // en dash, U+2013 ISOpub -->
{"mdash", "8212"}, // em dash, U+2014 ISOpub -->
{"lsquo", "8216"}, // left single quotation mark,U+2018 ISOnum -->
{"rsquo", "8217"}, // right single quotation mark,U+2019 ISOnum -->
{"sbquo", "8218"}, // single low-9 quotation mark, U+201A NEW -->
{"ldquo", "8220"}, // left double quotation mark,U+201C ISOnum -->
{"rdquo", "8221"}, // right double quotation mark,U+201D ISOnum -->
{"bdquo", "8222"}, // double low-9 quotation mark, U+201E NEW -->
{"dagger", "8224"}, // dagger, U+2020 ISOpub -->
{"Dagger", "8225"}, // double dagger, U+2021 ISOpub -->
{"permil", "8240"}, // per mille sign, U+2030 ISOtech -->
{"lsaquo", "8249"}, // single left-pointing angle quotation mark,U+2039 ISO proposed -->
//
{"rsaquo", "8250"}, // single right-pointing angle quotation mark,U+203A ISO proposed -->
//
{"euro", "8364"}, // -- euro sign, U+20AC NEW -->
};
/**
*
* The set of entities supported by standard XML.
*
*/
public static final Entities XML;
/**
*
* The set of entities supported by HTML 3.2.
*
*/
public static final Entities HTML32;
/**
*
* The set of entities supported by HTML 4.0.
*
*/
public static final Entities HTML40;
static {
Entities xml = new Entities();
xml.addEntities(BASIC_ARRAY);
xml.addEntities(APOS_ARRAY);
XML = xml;
}
static {
Entities html32 = new Entities();
html32.addEntities(BASIC_ARRAY);
html32.addEntities(ISO8859_1_ARRAY);
HTML32 = html32;
}
static {
Entities html40 = new Entities();
fillWithHtml40Entities(html40);
HTML40 = html40;
}
/**
*
* Fills the specified entities instance with HTML 40 entities.
*
*
* @param entities
* the instance to be filled.
*/
static void fillWithHtml40Entities(Entities entities) {
entities.addEntities(BASIC_ARRAY);
entities.addEntities(ISO8859_1_ARRAY);
entities.addEntities(HTML40_ARRAY);
}
static interface EntityMap {
/**
*
* Add an entry to this entity map.
*
*
* @param name
* the entity name
* @param value
* the entity value
*/
void add(String name, int value);
/**
*
* Returns the name of the entity identified by the specified value.
*
*
* @param value
* the value to locate
* @return entity name associated with the specified value
*/
String name(int value);
/**
*
* Returns the value of the entity identified by the specified name.
*
*
* @param name
* the name to locate
* @return entity value associated with the specified name
*/
int value(String name);
}
static class PrimitiveEntityMap implements EntityMap {
private final Map mapNameToValue = new HashMap();
private final IntHashMap mapValueToName = new IntHashMap();
/**
* {@inheritDoc}
*/
// TODO not thread-safe as there is a window between changing the two maps
public void add(String name, int value) {
mapNameToValue.put(name, new Integer(value));
mapValueToName.put(value, name);
}
/**
* {@inheritDoc}
*/
public String name(int value) {
return (String) mapValueToName.get(value);
}
/**
* {@inheritDoc}
*/
public int value(String name) {
Object value = mapNameToValue.get(name);
if (value == null) {
return -1;
}
return ((Integer) value).intValue();
}
}
static abstract class MapIntMap implements Entities.EntityMap {
protected final Map mapNameToValue;
protected final Map mapValueToName;
/**
* Construct a new instance with specified maps.
*
* @param nameToValue name to value map
* @param valueToName value to namee map
*/
MapIntMap(Map nameToValue, Map valueToName){
mapNameToValue = nameToValue;
mapValueToName = valueToName;
}
/**
* {@inheritDoc}
*/
public void add(String name, int value) {
mapNameToValue.put(name, new Integer(value));
mapValueToName.put(new Integer(value), name);
}
/**
* {@inheritDoc}
*/
public String name(int value) {
return (String) mapValueToName.get(new Integer(value));
}
/**
* {@inheritDoc}
*/
public int value(String name) {
Object value = mapNameToValue.get(name);
if (value == null) {
return -1;
}
return ((Integer) value).intValue();
}
}
static class HashEntityMap extends MapIntMap {
/**
* Constructs a new instance of HashEntityMap
.
*/
public HashEntityMap() {
super(new HashMap(), new HashMap());
}
}
static class TreeEntityMap extends MapIntMap {
/**
* Constructs a new instance of TreeEntityMap
.
*/
public TreeEntityMap() {
super(new TreeMap(), new TreeMap());
}
}
static class LookupEntityMap extends PrimitiveEntityMap {
// TODO this class is not thread-safe
private String[] lookupTable;
private static final int LOOKUP_TABLE_SIZE = 256;
/**
* {@inheritDoc}
*/
public String name(int value) {
if (value < LOOKUP_TABLE_SIZE) {
return lookupTable()[value];
}
return super.name(value);
}
/**
*
* Returns the lookup table for this entity map. The lookup table is created if it has not been previously.
*
*
* @return the lookup table
*/
private String[] lookupTable() {
if (lookupTable == null) {
createLookupTable();
}
return lookupTable;
}
/**
*
* Creates an entity lookup table of LOOKUP_TABLE_SIZE elements, initialized with entity names.
*
*/
private void createLookupTable() {
lookupTable = new String[LOOKUP_TABLE_SIZE];
for (int i = 0; i < LOOKUP_TABLE_SIZE; ++i) {
lookupTable[i] = super.name(i);
}
}
}
static class ArrayEntityMap implements EntityMap {
// TODO this class is not thread-safe
protected final int growBy;
protected int size = 0;
protected String[] names;
protected int[] values;
/**
* Constructs a new instance of ArrayEntityMap
.
*/
public ArrayEntityMap() {
this.growBy = 100;
names = new String[growBy];
values = new int[growBy];
}
/**
* Constructs a new instance of ArrayEntityMap
specifying the size by which the array should
* grow.
*
* @param growBy
* array will be initialized to and will grow by this amount
*/
public ArrayEntityMap(int growBy) {
this.growBy = growBy;
names = new String[growBy];
values = new int[growBy];
}
/**
* {@inheritDoc}
*/
public void add(String name, int value) {
ensureCapacity(size + 1);
names[size] = name;
values[size] = value;
size++;
}
/**
* Verifies the capacity of the entity array, adjusting the size if necessary.
*
* @param capacity
* size the array should be
*/
protected void ensureCapacity(int capacity) {
if (capacity > names.length) {
int newSize = Math.max(capacity, size + growBy);
String[] newNames = new String[newSize];
System.arraycopy(names, 0, newNames, 0, size);
names = newNames;
int[] newValues = new int[newSize];
System.arraycopy(values, 0, newValues, 0, size);
values = newValues;
}
}
/**
* {@inheritDoc}
*/
public String name(int value) {
for (int i = 0; i < size; ++i) {
if (values[i] == value) {
return names[i];
}
}
return null;
}
/**
* {@inheritDoc}
*/
public int value(String name) {
for (int i = 0; i < size; ++i) {
if (names[i].equals(name)) {
return values[i];
}
}
return -1;
}
}
static class BinaryEntityMap extends ArrayEntityMap {
// TODO - not thread-safe, because parent is not. Also references size.
/**
* Constructs a new instance of BinaryEntityMap
.
*/
public BinaryEntityMap() {
super();
}
/**
* Constructs a new instance of ArrayEntityMap
specifying the size by which the underlying array
* should grow.
*
* @param growBy
* array will be initialized to and will grow by this amount
*/
public BinaryEntityMap(int growBy) {
super(growBy);
}
/**
* Performs a binary search of the entity array for the specified key. This method is based on code in
* {@link java.util.Arrays}.
*
* @param key
* the key to be found
* @return the index of the entity array matching the specified key
*/
private int binarySearch(int key) {
int low = 0;
int high = size - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
int midVal = values[mid];
if (midVal < key) {
low = mid + 1;
} else if (midVal > key) {
high = mid - 1;
} else {
return mid; // key found
}
}
return -(low + 1); // key not found.
}
/**
* {@inheritDoc}
*/
public void add(String name, int value) {
ensureCapacity(size + 1);
int insertAt = binarySearch(value);
if (insertAt > 0) {
return; // note: this means you can't insert the same value twice
}
insertAt = -(insertAt + 1); // binarySearch returns it negative and off-by-one
System.arraycopy(values, insertAt, values, insertAt + 1, size - insertAt);
values[insertAt] = value;
System.arraycopy(names, insertAt, names, insertAt + 1, size - insertAt);
names[insertAt] = name;
size++;
}
/**
* {@inheritDoc}
*/
public String name(int value) {
int index = binarySearch(value);
if (index < 0) {
return null;
}
return names[index];
}
}
private final EntityMap map;
/**
* Default constructor.
*/
public Entities(){
map = new Entities.LookupEntityMap();
}
/**
* package scoped constructor for testing.
*
* @param emap entity map.
*/
Entities(EntityMap emap){
map = emap;
}
/**
*
* Adds entities to this entity.
*
*
* @param entityArray
* array of entities to be added
*/
public void addEntities(String[][] entityArray) {
for (int i = 0; i < entityArray.length; ++i) {
addEntity(entityArray[i][0], Integer.parseInt(entityArray[i][1]));
}
}
/**
*
* Add an entity to this entity.
*
*
* @param name
* name of the entity
* @param value
* vale of the entity
*/
public void addEntity(String name, int value) {
map.add(name, value);
}
/**
*
* Returns the name of the entity identified by the specified value.
*
*
* @param value
* the value to locate
* @return entity name associated with the specified value
*/
public String entityName(int value) {
return map.name(value);
}
/**
*
* Returns the value of the entity identified by the specified name.
*
*
* @param name
* the name to locate
* @return entity value associated with the specified name
*/
public int entityValue(String name) {
return map.value(name);
}
/**
*
* Escapes the characters in a String
.
*
*
*
* For example, if you have called addEntity("foo", 0xA1), escape("\u00A1") will return
* "&foo;"
*
*
* @param str
* The String
to escape.
* @return A new escaped String
.
*/
public String escape(String str) {
StringWriter stringWriter = createStringWriter(str);
try {
this.escape(stringWriter, str);
} catch (IOException e) {
// This should never happen because ALL the StringWriter methods called by #escape(Writer, String) do not
// throw IOExceptions.
throw new UnhandledException(e);
}
return stringWriter.toString();
}
/**
*
* Escapes the characters in the String
passed and writes the result to the Writer
* passed.
*
*
* @param writer
* The Writer
to write the results of the escaping to. Assumed to be a non-null value.
* @param str
* The String
to escape. Assumed to be a non-null value.
* @throws IOException
* when Writer
passed throws the exception from calls to the {@link Writer#write(int)}
* methods.
*
* @see #escape(String)
* @see Writer
*/
public void escape(Writer writer, String str) throws IOException {
int len = str.length();
for (int i = 0; i < len; i++) {
char c = str.charAt(i);
String entityName = this.entityName(c);
if (entityName == null) {
if (c > 0x7F) {
writer.write("");
writer.write(Integer.toString(c, 10));
writer.write(';');
} else {
writer.write(c);
}
} else {
writer.write('&');
writer.write(entityName);
writer.write(';');
}
}
}
/**
*
* Unescapes the entities in a String
.
*
*
*
* For example, if you have called addEntity("foo", 0xA1), unescape("&foo;") will return
* "\u00A1"
*
*
* @param str
* The String
to escape.
* @return A new escaped String
.
*/
public String unescape(String str) {
int firstAmp = str.indexOf('&');
if (firstAmp < 0) {
return str;
} else {
StringWriter stringWriter = createStringWriter(str);
try {
this.doUnescape(stringWriter, str, firstAmp);
} catch (IOException e) {
// This should never happen because ALL the StringWriter methods called by #escape(Writer, String)
// do not throw IOExceptions.
throw new UnhandledException(e);
}
return stringWriter.toString();
}
}
/**
* Make the StringWriter 10% larger than the source String to avoid growing the writer
*
* @param str The source string
* @return A newly created StringWriter
*/
private StringWriter createStringWriter(String str) {
return new StringWriter((int) (str.length() + (str.length() * 0.1)));
}
/**
*
* Unescapes the escaped entities in the String
passed and writes the result to the
* Writer
passed.
*
*
* @param writer
* The Writer
to write the results to; assumed to be non-null.
* @param str
* The source String
to unescape; assumed to be non-null.
* @throws IOException
* when Writer
passed throws the exception from calls to the {@link Writer#write(int)}
* methods.
*
* @see #escape(String)
* @see Writer
*/
public void unescape(Writer writer, String str) throws IOException {
int firstAmp = str.indexOf('&');
if (firstAmp < 0) {
writer.write(str);
return;
} else {
doUnescape(writer, str, firstAmp);
}
}
/**
* Underlying unescape method that allows the optimisation of not starting from the 0 index again.
*
* @param writer
* The Writer
to write the results to; assumed to be non-null.
* @param str
* The source String
to unescape; assumed to be non-null.
* @param firstAmp
* The int
index of the first ampersand in the source String.
* @throws IOException
* when Writer
passed throws the exception from calls to the {@link Writer#write(int)}
* methods.
*/
private void doUnescape(Writer writer, String str, int firstAmp) throws IOException {
writer.write(str, 0, firstAmp);
int len = str.length();
for (int i = firstAmp; i < len; i++) {
char c = str.charAt(i);
if (c == '&') {
int nextIdx = i + 1;
int semiColonIdx = str.indexOf(';', nextIdx);
if (semiColonIdx == -1) {
writer.write(c);
continue;
}
int amphersandIdx = str.indexOf('&', i + 1);
if (amphersandIdx != -1 && amphersandIdx < semiColonIdx) {
// Then the text looks like &...&...;
writer.write(c);
continue;
}
String entityContent = str.substring(nextIdx, semiColonIdx);
int entityValue = -1;
int entityContentLen = entityContent.length();
if (entityContentLen > 0) {
if (entityContent.charAt(0) == '#') { // escaped value content is an integer (decimal or
// hexidecimal)
if (entityContentLen > 1) {
char isHexChar = entityContent.charAt(1);
try {
switch (isHexChar) {
case 'X' :
case 'x' : {
entityValue = Integer.parseInt(entityContent.substring(2), 16);
break;
}
default : {
entityValue = Integer.parseInt(entityContent.substring(1), 10);
}
}
if (entityValue > 0xFFFF) {
entityValue = -1;
}
} catch (NumberFormatException e) {
entityValue = -1;
}
}
} else { // escaped value content is an entity name
entityValue = this.entityValue(entityContent);
}
}
if (entityValue == -1) {
writer.write('&');
writer.write(entityContent);
writer.write(';');
} else {
writer.write(entityValue);
}
i = semiColonIdx; // move index up to the semi-colon
} else {
writer.write(c);
}
}
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/enum/Enum.java 100644 0 0 56130 11513702445 23471 0 ustar 0 0 /*
* 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.lang.enum;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import org.apache.commons.lang.ClassUtils;
import org.apache.commons.lang.StringUtils;
/**
* Abstract superclass for type-safe enums.
*
* One feature of the C programming language lacking in Java is enumerations. The
* C implementation based on ints was poor and open to abuse. The original Java
* recommendation and most of the JDK also uses int constants. It has been recognised
* however that a more robust type-safe class-based solution can be designed. This
* class follows the basic Java type-safe enumeration pattern.
*
* NOTE:Due to the way in which Java ClassLoaders work, comparing
* Enum objects should always be done using equals()
, not ==
.
* The equals() method will try == first so in most cases the effect is the same.
*
* Of course, if you actually want (or don't mind) Enums in different class
* loaders being non-equal, then you can use ==
.
*
* Simple Enums
*
* To use this class, it must be subclassed. For example:
*
*
* public final class ColorEnum extends Enum {
* public static final ColorEnum RED = new ColorEnum("Red");
* public static final ColorEnum GREEN = new ColorEnum("Green");
* public static final ColorEnum BLUE = new ColorEnum("Blue");
*
* private ColorEnum(String color) {
* super(color);
* }
*
* public static ColorEnum getEnum(String color) {
* return (ColorEnum) getEnum(ColorEnum.class, color);
* }
*
* public static Map getEnumMap() {
* return getEnumMap(ColorEnum.class);
* }
*
* public static List getEnumList() {
* return getEnumList(ColorEnum.class);
* }
*
* public static Iterator iterator() {
* return iterator(ColorEnum.class);
* }
* }
*
*
* As shown, each enum has a name. This can be accessed using getName
.
*
* The getEnum
and iterator
methods are recommended.
* Unfortunately, Java restrictions require these to be coded as shown in each subclass.
* An alternative choice is to use the {@link EnumUtils} class.
*
* Subclassed Enums
* A hierarchy of Enum classes can be built. In this case, the superclass is
* unaffected by the addition of subclasses (as per normal Java). The subclasses
* may add additional Enum constants of the type of the superclass. The
* query methods on the subclass will return all of the Enum constants from the
* superclass and subclass.
*
*
* public final class ExtraColorEnum extends ColorEnum {
* // NOTE: Color enum declared above is final, change that to get this
* // example to compile.
* public static final ColorEnum YELLOW = new ExtraColorEnum("Yellow");
*
* private ExtraColorEnum(String color) {
* super(color);
* }
*
* public static ColorEnum getEnum(String color) {
* return (ColorEnum) getEnum(ExtraColorEnum.class, color);
* }
*
* public static Map getEnumMap() {
* return getEnumMap(ExtraColorEnum.class);
* }
*
* public static List getEnumList() {
* return getEnumList(ExtraColorEnum.class);
* }
*
* public static Iterator iterator() {
* return iterator(ExtraColorEnum.class);
* }
* }
*
*
* This example will return RED, GREEN, BLUE, YELLOW from the List and iterator
* methods in that order. The RED, GREEN and BLUE instances will be the same (==)
* as those from the superclass ColorEnum. Note that YELLOW is declared as a
* ColorEnum and not an ExtraColorEnum.
*
* Functional Enums
*
* The enums can have functionality by defining subclasses and
* overriding the getEnumClass()
method:
*
*
* public static final OperationEnum PLUS = new PlusOperation();
* private static final class PlusOperation extends OperationEnum {
* private PlusOperation() {
* super("Plus");
* }
* public int eval(int a, int b) {
* return a + b;
* }
* }
* public static final OperationEnum MINUS = new MinusOperation();
* private static final class MinusOperation extends OperationEnum {
* private MinusOperation() {
* super("Minus");
* }
* public int eval(int a, int b) {
* return a - b;
* }
* }
*
* private OperationEnum(String color) {
* super(color);
* }
*
* public final Class getEnumClass() { // NOTE: new method!
* return OperationEnum.class;
* }
*
* public abstract double eval(double a, double b);
*
* public static OperationEnum getEnum(String name) {
* return (OperationEnum) getEnum(OperationEnum.class, name);
* }
*
* public static Map getEnumMap() {
* return getEnumMap(OperationEnum.class);
* }
*
* public static List getEnumList() {
* return getEnumList(OperationEnum.class);
* }
*
* public static Iterator iterator() {
* return iterator(OperationEnum.class);
* }
* }
*
* The code above will work on JDK 1.2. If JDK1.3 and later is used,
* the subclasses may be defined as anonymous.
*
* Nested class Enums
*
* Care must be taken with class loading when defining a static nested class
* for enums. The static nested class can be loaded without the surrounding outer
* class being loaded. This can result in an empty list/map/iterator being returned.
* One solution is to define a static block that references the outer class where
* the constants are defined. For example:
*
*
* public final class Outer {
* public static final BWEnum BLACK = new BWEnum("Black");
* public static final BWEnum WHITE = new BWEnum("White");
*
* // static nested enum class
* public static final class BWEnum extends Enum {
*
* static {
* // explicitly reference BWEnum class to force constants to load
* Object obj = Outer.BLACK;
* }
*
* // ... other methods omitted
* }
* }
*
*
* Although the above solves the problem, it is not recommended. The best solution
* is to define the constants in the enum class, and hold references in the outer class:
*
*
* public final class Outer {
* public static final BWEnum BLACK = BWEnum.BLACK;
* public static final BWEnum WHITE = BWEnum.WHITE;
*
* // static nested enum class
* public static final class BWEnum extends Enum {
* // only define constants in enum classes - private if desired
* private static final BWEnum BLACK = new BWEnum("Black");
* private static final BWEnum WHITE = new BWEnum("White");
*
* // ... other methods omitted
* }
* }
*
*
* For more details, see the 'Nested' test cases.
*
* @deprecated Replaced by {@link org.apache.commons.lang.enums.Enum org.apache.commons.lang.enums.Enum}
* and will be removed in version 3.0. All classes in this package are deprecated and repackaged to
* {@link org.apache.commons.lang.enums} since enum
is a Java 1.5 keyword.
* @see org.apache.commons.lang.enums.Enum
* @author Apache Avalon project
* @author Apache Software Foundation
* @author Chris Webb
* @author Mike Bowler
* @since 1.0
* @version $Id: Enum.java 912394 2010-02-21 20:16:22Z niallp $
*/
public abstract class Enum implements Comparable, Serializable {
/**
* Required for serialization support. Lang version 1.0.1 serial compatibility.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = -487045951170455942L;
// After discussion, the default size for HashMaps is used, as the
// sizing algorithm changes across the JDK versions
/**
* An empty Map
, as JDK1.2 didn't have an empty map.
*/
private static final Map EMPTY_MAP = Collections.unmodifiableMap(new HashMap(0));
/**
* Map
, key of class name, value of Entry
.
*/
private static Map cEnumClasses
// LANG-334: To avoid exposing a mutating map,
// we copy it each time we add to it. This is cheaper than
// using a synchronized map since we are almost entirely reads
= new WeakHashMap();
/**
* The string representation of the Enum.
*/
private final String iName;
/**
* The hashcode representation of the Enum.
*/
private transient final int iHashCode;
/**
* The toString representation of the Enum.
* @since 2.0
*/
protected transient String iToString = null;
/**
*
Enable the iterator to retain the source code order.
*/
private static class Entry {
/**
* Map of Enum name to Enum.
*/
final Map map = new HashMap();
/**
* Map of Enum name to Enum.
*/
final Map unmodifiableMap = Collections.unmodifiableMap(map);
/**
* List of Enums in source code order.
*/
final List list = new ArrayList(25);
/**
* Map of Enum name to Enum.
*/
final List unmodifiableList = Collections.unmodifiableList(list);
/**
* Restrictive constructor.
*/
protected Entry() {
super();
}
}
/**
* Constructor to add a new named item to the enumeration.
*
* @param name the name of the enum object,
* must not be empty or null
* @throws IllegalArgumentException if the name is null
* or an empty string
* @throws IllegalArgumentException if the getEnumClass() method returns
* a null or invalid Class
*/
protected Enum(String name) {
super();
init(name);
iName = name;
iHashCode = 7 + getEnumClass().hashCode() + 3 * name.hashCode();
// cannot create toString here as subclasses may want to include other data
}
/**
* Initializes the enumeration.
*
* @param name the enum name
* @throws IllegalArgumentException if the name is null or empty or duplicate
* @throws IllegalArgumentException if the enumClass is null or invalid
*/
private void init(String name) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("The Enum name must not be empty or null");
}
Class enumClass = getEnumClass();
if (enumClass == null) {
throw new IllegalArgumentException("getEnumClass() must not be null");
}
Class cls = getClass();
boolean ok = false;
while (cls != null && cls != Enum.class && cls != ValuedEnum.class) {
if (cls == enumClass) {
ok = true;
break;
}
cls = cls.getSuperclass();
}
if (ok == false) {
throw new IllegalArgumentException("getEnumClass() must return a superclass of this class");
}
Entry entry;
synchronized( Enum.class ) { // LANG-334
// create entry
entry = (Entry) cEnumClasses.get(enumClass);
if (entry == null) {
entry = createEntry(enumClass);
Map myMap = new WeakHashMap( ); // we avoid the (Map) constructor to achieve JDK 1.2 support
myMap.putAll( cEnumClasses );
myMap.put(enumClass, entry);
cEnumClasses = myMap;
}
}
if (entry.map.containsKey(name)) {
throw new IllegalArgumentException("The Enum name must be unique, '" + name + "' has already been added");
}
entry.map.put(name, this);
entry.list.add(this);
}
/**
* Handle the deserialization of the class to ensure that multiple
* copies are not wastefully created, or illegal enum types created.
*
* @return the resolved object
*/
protected Object readResolve() {
Entry entry = (Entry) cEnumClasses.get(getEnumClass());
if (entry == null) {
return null;
}
return entry.map.get(getName());
}
//--------------------------------------------------------------------------------
/**
* Gets an Enum
object by class and name.
*
* @param enumClass the class of the Enum to get, must not
* be null
* @param name the name of the Enum
to get,
* may be null
* @return the enum object, or null
if the enum does not exist
* @throws IllegalArgumentException if the enum class
* is null
*/
protected static Enum getEnum(Class enumClass, String name) {
Entry entry = getEntry(enumClass);
if (entry == null) {
return null;
}
return (Enum) entry.map.get(name);
}
/**
* Gets the Map
of Enum
objects by
* name using the Enum
class.
*
* If the requested class has no enum objects an empty
* Map
is returned.
*
* @param enumClass the class of the Enum
to get,
* must not be null
* @return the enum object Map
* @throws IllegalArgumentException if the enum class is null
* @throws IllegalArgumentException if the enum class is not a subclass of Enum
*/
protected static Map getEnumMap(Class enumClass) {
Entry entry = getEntry(enumClass);
if (entry == null) {
return EMPTY_MAP;
}
return entry.unmodifiableMap;
}
/**
* Gets the List
of Enum
objects using the
* Enum
class.
*
* The list is in the order that the objects were created (source code order).
* If the requested class has no enum objects an empty List
is
* returned.
*
* @param enumClass the class of the Enum
to get,
* must not be null
* @return the enum object Map
* @throws IllegalArgumentException if the enum class is null
* @throws IllegalArgumentException if the enum class is not a subclass of Enum
*/
protected static List getEnumList(Class enumClass) {
Entry entry = getEntry(enumClass);
if (entry == null) {
return Collections.EMPTY_LIST;
}
return entry.unmodifiableList;
}
/**
* Gets an Iterator
over the Enum
objects in
* an Enum
class.
*
* The Iterator
is in the order that the objects were
* created (source code order). If the requested class has no enum
* objects an empty Iterator
is returned.
*
* @param enumClass the class of the Enum
to get,
* must not be null
* @return an iterator of the Enum objects
* @throws IllegalArgumentException if the enum class is null
* @throws IllegalArgumentException if the enum class is not a subclass of Enum
*/
protected static Iterator iterator(Class enumClass) {
return Enum.getEnumList(enumClass).iterator();
}
//-----------------------------------------------------------------------
/**
* Gets an Entry
from the map of Enums.
*
* @param enumClass the class of the Enum
to get
* @return the enum entry
*/
private static Entry getEntry(Class enumClass) {
if (enumClass == null) {
throw new IllegalArgumentException("The Enum Class must not be null");
}
if (Enum.class.isAssignableFrom(enumClass) == false) {
throw new IllegalArgumentException("The Class must be a subclass of Enum");
}
Entry entry = (Entry) cEnumClasses.get(enumClass);
if (entry == null) {
try {
// LANG-76 - try to force class initialization for JDK 1.5+
Class.forName(enumClass.getName(), true, enumClass.getClassLoader());
entry = (Entry) cEnumClasses.get(enumClass);
} catch (Exception e) {
// Ignore
}
}
return entry;
}
/**
* Creates an Entry
for storing the Enums.
*
* This accounts for subclassed Enums.
*
* @param enumClass the class of the Enum
to get
* @return the enum entry
*/
private static Entry createEntry(Class enumClass) {
Entry entry = new Entry();
Class cls = enumClass.getSuperclass();
while (cls != null && cls != Enum.class && cls != ValuedEnum.class) {
Entry loopEntry = (Entry) cEnumClasses.get(cls);
if (loopEntry != null) {
entry.list.addAll(loopEntry.list);
entry.map.putAll(loopEntry.map);
break; // stop here, as this will already have had superclasses added
}
cls = cls.getSuperclass();
}
return entry;
}
//-----------------------------------------------------------------------
/**
* Retrieve the name of this Enum item, set in the constructor.
*
* @return the String
name of this Enum item
*/
public final String getName() {
return iName;
}
/**
* Retrieves the Class of this Enum item, set in the constructor.
*
* This is normally the same as getClass()
, but for
* advanced Enums may be different. If overridden, it must return a
* constant value.
*
* @return the Class
of the enum
* @since 2.0
*/
public Class getEnumClass() {
return getClass();
}
/**
* Tests for equality.
*
* Two Enum objects are considered equal
* if they have the same class names and the same names.
* Identity is tested for first, so this method usually runs fast.
*
* If the parameter is in a different class loader than this instance,
* reflection is used to compare the names.
*
* @param other the other object to compare for equality
* @return true
if the Enums are equal
*/
public final boolean equals(Object other) {
if (other == this) {
return true;
} else if (other == null) {
return false;
} else if (other.getClass() == this.getClass()) {
// Ok to do a class cast to Enum here since the test above
// guarantee both
// classes are in the same class loader.
return iName.equals(((Enum) other).iName);
} else {
// This and other are in different class loaders, we must check indirectly
if (other.getClass().getName().equals(this.getClass().getName()) == false) {
return false;
}
return iName.equals( getNameInOtherClassLoader(other) );
}
}
/**
* Returns a suitable hashCode for the enumeration.
*
* @return a hashcode based on the name
*/
public final int hashCode() {
return iHashCode;
}
/**
* Tests for order.
*
* The default ordering is alphabetic by name, but this
* can be overridden by subclasses.
*
* If the parameter is in a different class loader than this instance,
* reflection is used to compare the names.
*
* @see java.lang.Comparable#compareTo(Object)
* @param other the other object to compare to
* @return -ve if this is less than the other object, +ve if greater
* than, 0
of equal
* @throws ClassCastException if other is not an Enum
* @throws NullPointerException if other is null
*/
public int compareTo(Object other) {
if (other == this) {
return 0;
}
if (other.getClass() != this.getClass()) {
if (other.getClass().getName().equals(this.getClass().getName())) {
return iName.compareTo( getNameInOtherClassLoader(other) );
}
throw new ClassCastException(
"Different enum class '" + ClassUtils.getShortClassName(other.getClass()) + "'");
}
return iName.compareTo(((Enum) other).iName);
}
/**
* Use reflection to return an objects class name.
*
* @param other The object to determine the class name for
* @return The class name
*/
private String getNameInOtherClassLoader(Object other) {
try {
Method mth = other.getClass().getMethod("getName", null);
String name = (String) mth.invoke(other, null);
return name;
} catch (NoSuchMethodException e) {
// ignore - should never happen
} catch (IllegalAccessException e) {
// ignore - should never happen
} catch (InvocationTargetException e) {
// ignore - should never happen
}
throw new IllegalStateException("This should not happen");
}
/**
* Human readable description of this Enum item.
*
* @return String in the form type[name]
, for example:
* Color[Red]
. Note that the package name is stripped from
* the type name.
*/
public String toString() {
if (iToString == null) {
String shortName = ClassUtils.getShortClassName(getEnumClass());
iToString = shortName + "[" + getName() + "]";
}
return iToString;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/enum/EnumUtils.java 100644 0 0 12010 11513702445 24477 0 ustar 0 0 /*
* 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.lang.enum;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Utility class for accessing and manipulating {@link Enum}s.
*
* @deprecated Replaced by {@link org.apache.commons.lang.enums.EnumUtils org.apache.commons.lang.enums.EnumUtils}
* and will be removed in version 3.0. All classes in this package are deprecated and repackaged to
* {@link org.apache.commons.lang.enums} since enum
is a Java 1.5 keyword.
* @see org.apache.commons.lang.enums.EnumUtils
* @see Enum
* @see ValuedEnum
* @author Apache Software Foundation
* @author Gary Gregory
* @since 1.0
* @version $Id: EnumUtils.java 905636 2010-02-02 14:03:32Z niallp $
*/
public class EnumUtils {
/**
* Public constructor. This class should not normally be instantiated.
* @since 2.0
*/
public EnumUtils() {
super();
}
/**
* Gets an Enum
object by class and name.
*
* @param enumClass the class of the Enum
to get
* @param name the name of the Enum to get, may be null
* @return the enum object
* @throws IllegalArgumentException if the enum class is null
*/
public static Enum getEnum(Class enumClass, String name) {
return Enum.getEnum(enumClass, name);
}
/**
* Gets a ValuedEnum
object by class and value.
*
* @param enumClass the class of the Enum
to get
* @param value the value of the Enum
to get
* @return the enum object, or null if the enum does not exist
* @throws IllegalArgumentException if the enum class is null
*/
public static ValuedEnum getEnum(Class enumClass, int value) {
return (ValuedEnum) ValuedEnum.getEnum(enumClass, value);
}
/**
* Gets the Map
of Enum
objects by
* name using the Enum
class.
*
* If the requested class has no enum objects an empty
* Map
is returned. The Map
is unmodifiable.
*
* @param enumClass the class of the Enum
to get
* @return the enum object Map
* @throws IllegalArgumentException if the enum class is null
* @throws IllegalArgumentException if the enum class is not a subclass
* of Enum
*/
public static Map getEnumMap(Class enumClass) {
return Enum.getEnumMap(enumClass);
}
/**
* Gets the List
of Enum
objects using
* the Enum
class.
*
* The list is in the order that the objects were created
* (source code order).
*
* If the requested class has no enum objects an empty
* List
is returned. The List
is unmodifiable.
*
* @param enumClass the class of the Enum to get
* @return the enum object Map
* @throws IllegalArgumentException if the enum class is null
* @throws IllegalArgumentException if the enum class is not a subclass
* of Enum
*/
public static List getEnumList(Class enumClass) {
return Enum.getEnumList(enumClass);
}
/**
* Gets an Iterator
over the Enum
objects
* in an Enum
class.
*
* The iterator is in the order that the objects were created
* (source code order).
*
* If the requested class has no enum objects an empty
* Iterator
is returned. The Iterator
* is unmodifiable.
*
* @param enumClass the class of the Enum
to get
* @return an Iterator
of the Enum
objects
* @throws IllegalArgumentException if the enum class is null
* @throws IllegalArgumentException if the enum class is not a subclass of Enum
*/
public static Iterator iterator(Class enumClass) {
return Enum.getEnumList(enumClass).iterator();
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/enum/package.html 100644 0 0 3713 11513702445 24162 0 ustar 0 0
Deprecated and replaced by {@link org.apache.commons.lang.enums}
and will be removed in version 3.0.
All classes in this package are deprecated and repackaged to {@link org.apache.commons.lang.enums}
since enum
is a Java 1.5 keyword.
Provides an implementation of the C style enum
in the Java world.
The classic example being an RGB color enumeration.
public final class ColorEnum extends Enum {
public static final ColorEnum RED = new ColorEnum("Red");
public static final ColorEnum GREEN = new ColorEnum("Green");
public static final ColorEnum BLUE = new ColorEnum("Blue");
private ColorEnum(String color) {
super(color);
}
public static ColorEnum getEnum(String color) {
return (ColorEnum) getEnum(ColorEnum.class, color);
}
public static Map getEnumMap() {
return getEnumMap(ColorEnum.class);
}
public static List getEnumList() {
return getEnumList(ColorEnum.class);
}
public static Iterator iterator() {
return iterator(ColorEnum.class);
}
}
@since 1.0
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/enum/ValuedEnum.java 100644 0 0 16076 11513702445 24637 0 ustar 0 0 /*
* 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.lang.enum;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.lang.ClassUtils;
/**
* Abstract superclass for type-safe enums with integer values suitable
* for use in switch
statements.
*
* NOTE:Due to the way in which Java ClassLoaders work, comparing
* Enum
objects should always be done using the equals() method,
* not ==
. The equals() method will try ==
first so
* in most cases the effect is the same.
*
* To use this class, it must be subclassed. For example:
*
*
* public final class JavaVersionEnum extends ValuedEnum {
* //standard enums for version of JVM
* public static final int JAVA1_0_VALUE = 100;
* public static final int JAVA1_1_VALUE = 110;
* public static final int JAVA1_2_VALUE = 120;
* public static final int JAVA1_3_VALUE = 130;
* public static final JavaVersionEnum JAVA1_0 = new JavaVersionEnum( "Java 1.0", JAVA1_0_VALUE );
* public static final JavaVersionEnum JAVA1_1 = new JavaVersionEnum( "Java 1.1", JAVA1_1_VALUE );
* public static final JavaVersionEnum JAVA1_2 = new JavaVersionEnum( "Java 1.2", JAVA1_2_VALUE );
* public static final JavaVersionEnum JAVA1_3 = new JavaVersionEnum( "Java 1.3", JAVA1_3_VALUE );
*
* private JavaVersionEnum(String name, int value) {
* super( name, value );
* }
*
* public static JavaVersionEnum getEnum(String javaVersion) {
* return (JavaVersionEnum) getEnum(JavaVersionEnum.class, javaVersion);
* }
*
* public static JavaVersionEnum getEnum(int javaVersion) {
* return (JavaVersionEnum) getEnum(JavaVersionEnum.class, javaVersion);
* }
*
* public static Map getEnumMap() {
* return getEnumMap(JavaVersionEnum.class);
* }
*
* public static List getEnumList() {
* return getEnumList(JavaVersionEnum.class);
* }
*
* public static Iterator iterator() {
* return iterator(JavaVersionEnum.class);
* }
* }
*
*
* The above class could then be used as follows:
*
*
* public void doSomething(JavaVersionEnum ver) {
* switch (ver.getValue()) {
* case JAVA1_0_VALUE:
* // ...
* break;
* case JAVA1_1_VALUE:
* // ...
* break;
* //...
* }
* }
*
*
* As shown, each enum has a name and a value. These can be accessed using
* getName
and getValue
.
*
* The getEnum
and iterator
methods are recommended.
* Unfortunately, Java restrictions require these to be coded as shown in each subclass.
* An alternative choice is to use the {@link EnumUtils} class.
*
* @deprecated Replaced by {@link org.apache.commons.lang.enums.ValuedEnum org.apache.commons.lang.enums.ValuedEnum}
* and will be removed in version 3.0. All classes in this package are deprecated and repackaged to
* {@link org.apache.commons.lang.enums} since enum
is a Java 1.5 keyword.
* @see org.apache.commons.lang.enums.ValuedEnum
* @author Apache Avalon project
* @author Apache Software Foundation
* @since 1.0
* @version $Id: ValuedEnum.java 905636 2010-02-02 14:03:32Z niallp $
*/
public abstract class ValuedEnum extends Enum {
/**
* Required for serialization support. Lang version 1.0.1 serial compatibility.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = -7129650521543789085L;
/**
* The value contained in enum.
*/
private final int iValue;
/**
* Constructor for enum item.
*
* @param name the name of enum item
* @param value the value of enum item
*/
protected ValuedEnum(String name, int value) {
super(name);
iValue = value;
}
/**
* Gets an Enum
object by class and value.
*
* This method loops through the list of Enum
,
* thus if there are many Enum
s this will be
* slow.
*
* @param enumClass the class of the Enum
to get
* @param value the value of the Enum
to get
* @return the enum object, or null if the enum does not exist
* @throws IllegalArgumentException if the enum class is null
*/
protected static Enum getEnum(Class enumClass, int value) {
if (enumClass == null) {
throw new IllegalArgumentException("The Enum Class must not be null");
}
List list = Enum.getEnumList(enumClass);
for (Iterator it = list.iterator(); it.hasNext();) {
ValuedEnum enumeration = (ValuedEnum) it.next();
if (enumeration.getValue() == value) {
return enumeration;
}
}
return null;
}
/**
* Get value of enum item.
*
* @return the enum item's value.
*/
public final int getValue() {
return iValue;
}
/**
* Tests for order.
*
* The default ordering is numeric by value, but this
* can be overridden by subclasses.
*
* @see java.lang.Comparable#compareTo(Object)
* @param other the other object to compare to
* @return -ve if this is less than the other object, +ve if greater than,
* 0
of equal
* @throws ClassCastException if other is not an Enum
* @throws NullPointerException if other is null
*/
public int compareTo(Object other) {
return iValue - ((ValuedEnum) other).iValue;
}
/**
* Human readable description of this Enum
item.
*
* @return String in the form type[name=value]
, for example:
* JavaVersion[Java 1.0=100]
. Note that the package name is
* stripped from the type name.
*/
public String toString() {
if (iToString == null) {
String shortName = ClassUtils.getShortClassName(getEnumClass());
iToString = shortName + "[" + getName() + "=" + getValue() + "]";
}
return iToString;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/enums/Enum.java 100644 0 0 61072 11513702442 23652 0 ustar 0 0 /*
* 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.lang.enums;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import org.apache.commons.lang.ClassUtils;
import org.apache.commons.lang.StringUtils;
/**
* Abstract superclass for type-safe enums.
*
* One feature of the C programming language lacking in Java is enumerations. The
* C implementation based on ints was poor and open to abuse. The original Java
* recommendation and most of the JDK also uses int constants. It has been recognised
* however that a more robust type-safe class-based solution can be designed. This
* class follows the basic Java type-safe enumeration pattern.
*
* NOTE: Due to the way in which Java ClassLoaders work, comparing
* Enum objects should always be done using equals()
, not ==
.
* The equals() method will try == first so in most cases the effect is the same.
*
* Of course, if you actually want (or don't mind) Enums in different class
* loaders being non-equal, then you can use ==
.
*
* Simple Enums
*
* To use this class, it must be subclassed. For example:
*
*
* public final class ColorEnum extends Enum {
* public static final ColorEnum RED = new ColorEnum("Red");
* public static final ColorEnum GREEN = new ColorEnum("Green");
* public static final ColorEnum BLUE = new ColorEnum("Blue");
*
* private ColorEnum(String color) {
* super(color);
* }
*
* public static ColorEnum getEnum(String color) {
* return (ColorEnum) getEnum(ColorEnum.class, color);
* }
*
* public static Map getEnumMap() {
* return getEnumMap(ColorEnum.class);
* }
*
* public static List getEnumList() {
* return getEnumList(ColorEnum.class);
* }
*
* public static Iterator iterator() {
* return iterator(ColorEnum.class);
* }
* }
*
*
* As shown, each enum has a name. This can be accessed using getName
.
*
* The getEnum
and iterator
methods are recommended.
* Unfortunately, Java restrictions require these to be coded as shown in each subclass.
* An alternative choice is to use the {@link EnumUtils} class.
*
* Subclassed Enums
* A hierarchy of Enum classes can be built. In this case, the superclass is
* unaffected by the addition of subclasses (as per normal Java). The subclasses
* may add additional Enum constants of the type of the superclass. The
* query methods on the subclass will return all of the Enum constants from the
* superclass and subclass.
*
*
* public final class ExtraColorEnum extends ColorEnum {
* // NOTE: Color enum declared above is final, change that to get this
* // example to compile.
* public static final ColorEnum YELLOW = new ExtraColorEnum("Yellow");
*
* private ExtraColorEnum(String color) {
* super(color);
* }
*
* public static ColorEnum getEnum(String color) {
* return (ColorEnum) getEnum(ExtraColorEnum.class, color);
* }
*
* public static Map getEnumMap() {
* return getEnumMap(ExtraColorEnum.class);
* }
*
* public static List getEnumList() {
* return getEnumList(ExtraColorEnum.class);
* }
*
* public static Iterator iterator() {
* return iterator(ExtraColorEnum.class);
* }
* }
*
*
* This example will return RED, GREEN, BLUE, YELLOW from the List and iterator
* methods in that order. The RED, GREEN and BLUE instances will be the same (==)
* as those from the superclass ColorEnum. Note that YELLOW is declared as a
* ColorEnum and not an ExtraColorEnum.
*
* Functional Enums
*
* The enums can have functionality by defining subclasses and
* overriding the getEnumClass()
method:
*
*
* public static final OperationEnum PLUS = new PlusOperation();
* private static final class PlusOperation extends OperationEnum {
* private PlusOperation() {
* super("Plus");
* }
* public int eval(int a, int b) {
* return a + b;
* }
* }
* public static final OperationEnum MINUS = new MinusOperation();
* private static final class MinusOperation extends OperationEnum {
* private MinusOperation() {
* super("Minus");
* }
* public int eval(int a, int b) {
* return a - b;
* }
* }
*
* private OperationEnum(String color) {
* super(color);
* }
*
* public final Class getEnumClass() { // NOTE: new method!
* return OperationEnum.class;
* }
*
* public abstract double eval(double a, double b);
*
* public static OperationEnum getEnum(String name) {
* return (OperationEnum) getEnum(OperationEnum.class, name);
* }
*
* public static Map getEnumMap() {
* return getEnumMap(OperationEnum.class);
* }
*
* public static List getEnumList() {
* return getEnumList(OperationEnum.class);
* }
*
* public static Iterator iterator() {
* return iterator(OperationEnum.class);
* }
* }
*
* The code above will work on JDK 1.2. If JDK1.3 and later is used,
* the subclasses may be defined as anonymous.
*
* Nested class Enums
*
* Care must be taken with class loading when defining a static nested class
* for enums. The static nested class can be loaded without the surrounding outer
* class being loaded. This can result in an empty list/map/iterator being returned.
* One solution is to define a static block that references the outer class where
* the constants are defined. For example:
*
*
* public final class Outer {
* public static final BWEnum BLACK = new BWEnum("Black");
* public static final BWEnum WHITE = new BWEnum("White");
*
* // static nested enum class
* public static final class BWEnum extends Enum {
*
* static {
* // explicitly reference BWEnum class to force constants to load
* Object obj = Outer.BLACK;
* }
*
* // ... other methods omitted
* }
* }
*
*
* Although the above solves the problem, it is not recommended. The best solution
* is to define the constants in the enum class, and hold references in the outer class:
*
*
* public final class Outer {
* public static final BWEnum BLACK = BWEnum.BLACK;
* public static final BWEnum WHITE = BWEnum.WHITE;
*
* // static nested enum class
* public static final class BWEnum extends Enum {
* // only define constants in enum classes - private if desired
* private static final BWEnum BLACK = new BWEnum("Black");
* private static final BWEnum WHITE = new BWEnum("White");
*
* // ... other methods omitted
* }
* }
*
*
* For more details, see the 'Nested' test cases.
*
*
Lang Enums and Java 5.0 Enums
*
* Enums were added to Java in Java 5.0. The main differences between Lang's
* implementation and the new official JDK implementation are:
*
* - The standard Enum is a not just a superclass, but is a type baked into the
* language.
* - The standard Enum does not support extension, so the standard methods that
* are provided in the Lang enum are not available.
* - Lang mandates a String name, whereas the standard Enum uses the class
* name as its name. getName() changes to name().
*
*
* Generally people should use the standard Enum. Migrating from the Lang
* enum to the standard Enum is not as easy as it might be due to the lack of
* class inheritence in standard Enums. This means that it's not possible
* to provide a 'super-enum' which could provide the same utility methods
* that the Lang enum does. The following utility class is a Java 5.0
* version of our EnumUtils class and provides those utility methods.
*
*
* import java.util.*;
*
* public class EnumUtils {
*
* public static Enum getEnum(Class enumClass, String token) {
* return Enum.valueOf(enumClass, token);
* }
*
* public static Map getEnumMap(Class enumClass) {
* HashMap map = new HashMap();
* Iterator itr = EnumUtils.iterator(enumClass);
* while(itr.hasNext()) {
* Enum enm = (Enum) itr.next();
* map.put( enm.name(), enm );
* }
* return map;
* }
*
* public static List getEnumList(Class enumClass) {
* return new ArrayList( EnumSet.allOf(enumClass) );
* }
*
* public static Iterator iterator(Class enumClass) {
* return EnumUtils.getEnumList(enumClass).iterator();
* }
* }
*
*
* @author Apache Avalon project
* @author Apache Software Foundation
* @author Chris Webb
* @author Mike Bowler
* @author Matthias Eichel
* @since 2.1 (class existed in enum package from v1.0)
* @version $Id: Enum.java 912394 2010-02-21 20:16:22Z niallp $
*/
public abstract class Enum implements Comparable, Serializable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = -487045951170455942L;
// After discussion, the default size for HashMaps is used, as the
// sizing algorithm changes across the JDK versions
/**
* An empty Map
, as JDK1.2 didn't have an empty map.
*/
private static final Map EMPTY_MAP = Collections.unmodifiableMap(new HashMap(0));
/**
* Map
, key of class name, value of Entry
.
*/
private static Map cEnumClasses
// LANG-334: To avoid exposing a mutating map,
// we copy it each time we add to it. This is cheaper than
// using a synchronized map since we are almost entirely reads
= new WeakHashMap();
/**
* The string representation of the Enum.
*/
private final String iName;
/**
* The hashcode representation of the Enum.
*/
private transient final int iHashCode;
/**
* The toString representation of the Enum.
* @since 2.0
*/
protected transient String iToString = null;
/**
* Enable the iterator to retain the source code order.
*/
private static class Entry {
/**
* Map of Enum name to Enum.
*/
final Map map = new HashMap();
/**
* Map of Enum name to Enum.
*/
final Map unmodifiableMap = Collections.unmodifiableMap(map);
/**
* List of Enums in source code order.
*/
final List list = new ArrayList(25);
/**
* Map of Enum name to Enum.
*/
final List unmodifiableList = Collections.unmodifiableList(list);
/**
* Restrictive constructor.
*/
protected Entry() {
super();
}
}
/**
* Constructor to add a new named item to the enumeration.
*
* @param name the name of the enum object,
* must not be empty or null
* @throws IllegalArgumentException if the name is null
* or an empty string
* @throws IllegalArgumentException if the getEnumClass() method returns
* a null or invalid Class
*/
protected Enum(String name) {
super();
init(name);
iName = name;
iHashCode = 7 + getEnumClass().hashCode() + 3 * name.hashCode();
// cannot create toString here as subclasses may want to include other data
}
/**
* Initializes the enumeration.
*
* @param name the enum name
* @throws IllegalArgumentException if the name is null or empty or duplicate
* @throws IllegalArgumentException if the enumClass is null or invalid
*/
private void init(String name) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("The Enum name must not be empty or null");
}
Class enumClass = getEnumClass();
if (enumClass == null) {
throw new IllegalArgumentException("getEnumClass() must not be null");
}
Class cls = getClass();
boolean ok = false;
while (cls != null && cls != Enum.class && cls != ValuedEnum.class) {
if (cls == enumClass) {
ok = true;
break;
}
cls = cls.getSuperclass();
}
if (ok == false) {
throw new IllegalArgumentException("getEnumClass() must return a superclass of this class");
}
Entry entry;
synchronized( Enum.class ) { // LANG-334
// create entry
entry = (Entry) cEnumClasses.get(enumClass);
if (entry == null) {
entry = createEntry(enumClass);
Map myMap = new WeakHashMap( ); // we avoid the (Map) constructor to achieve JDK 1.2 support
myMap.putAll( cEnumClasses );
myMap.put(enumClass, entry);
cEnumClasses = myMap;
}
}
if (entry.map.containsKey(name)) {
throw new IllegalArgumentException("The Enum name must be unique, '" + name + "' has already been added");
}
entry.map.put(name, this);
entry.list.add(this);
}
/**
* Handle the deserialization of the class to ensure that multiple
* copies are not wastefully created, or illegal enum types created.
*
* @return the resolved object
*/
protected Object readResolve() {
Entry entry = (Entry) cEnumClasses.get(getEnumClass());
if (entry == null) {
return null;
}
return entry.map.get(getName());
}
//--------------------------------------------------------------------------------
/**
* Gets an Enum
object by class and name.
*
* @param enumClass the class of the Enum to get, must not
* be null
* @param name the name of the Enum
to get,
* may be null
* @return the enum object, or null
if the enum does not exist
* @throws IllegalArgumentException if the enum class
* is null
*/
protected static Enum getEnum(Class enumClass, String name) {
Entry entry = getEntry(enumClass);
if (entry == null) {
return null;
}
return (Enum) entry.map.get(name);
}
/**
* Gets the Map
of Enum
objects by
* name using the Enum
class.
*
* If the requested class has no enum objects an empty
* Map
is returned.
*
* @param enumClass the class of the Enum
to get,
* must not be null
* @return the enum object Map
* @throws IllegalArgumentException if the enum class is null
* @throws IllegalArgumentException if the enum class is not a subclass of Enum
*/
protected static Map getEnumMap(Class enumClass) {
Entry entry = getEntry(enumClass);
if (entry == null) {
return EMPTY_MAP;
}
return entry.unmodifiableMap;
}
/**
* Gets the List
of Enum
objects using the
* Enum
class.
*
* The list is in the order that the objects were created (source code order).
* If the requested class has no enum objects an empty List
is
* returned.
*
* @param enumClass the class of the Enum
to get,
* must not be null
* @return the enum object Map
* @throws IllegalArgumentException if the enum class is null
* @throws IllegalArgumentException if the enum class is not a subclass of Enum
*/
protected static List getEnumList(Class enumClass) {
Entry entry = getEntry(enumClass);
if (entry == null) {
return Collections.EMPTY_LIST;
}
return entry.unmodifiableList;
}
/**
* Gets an Iterator
over the Enum
objects in
* an Enum
class.
*
* The Iterator
is in the order that the objects were
* created (source code order). If the requested class has no enum
* objects an empty Iterator
is returned.
*
* @param enumClass the class of the Enum
to get,
* must not be null
* @return an iterator of the Enum objects
* @throws IllegalArgumentException if the enum class is null
* @throws IllegalArgumentException if the enum class is not a subclass of Enum
*/
protected static Iterator iterator(Class enumClass) {
return Enum.getEnumList(enumClass).iterator();
}
//-----------------------------------------------------------------------
/**
* Gets an Entry
from the map of Enums.
*
* @param enumClass the class of the Enum
to get
* @return the enum entry
*/
private static Entry getEntry(Class enumClass) {
if (enumClass == null) {
throw new IllegalArgumentException("The Enum Class must not be null");
}
if (Enum.class.isAssignableFrom(enumClass) == false) {
throw new IllegalArgumentException("The Class must be a subclass of Enum");
}
Entry entry = (Entry) cEnumClasses.get(enumClass);
if (entry == null) {
try {
// LANG-76 - try to force class initialization for JDK 1.5+
Class.forName(enumClass.getName(), true, enumClass.getClassLoader());
entry = (Entry) cEnumClasses.get(enumClass);
} catch (Exception e) {
// Ignore
}
}
return entry;
}
/**
* Creates an Entry
for storing the Enums.
*
* This accounts for subclassed Enums.
*
* @param enumClass the class of the Enum
to get
* @return the enum entry
*/
private static Entry createEntry(Class enumClass) {
Entry entry = new Entry();
Class cls = enumClass.getSuperclass();
while (cls != null && cls != Enum.class && cls != ValuedEnum.class) {
Entry loopEntry = (Entry) cEnumClasses.get(cls);
if (loopEntry != null) {
entry.list.addAll(loopEntry.list);
entry.map.putAll(loopEntry.map);
break; // stop here, as this will already have had superclasses added
}
cls = cls.getSuperclass();
}
return entry;
}
//-----------------------------------------------------------------------
/**
* Retrieve the name of this Enum item, set in the constructor.
*
* @return the String
name of this Enum item
*/
public final String getName() {
return iName;
}
/**
* Retrieves the Class of this Enum item, set in the constructor.
*
* This is normally the same as getClass()
, but for
* advanced Enums may be different. If overridden, it must return a
* constant value.
*
* @return the Class
of the enum
* @since 2.0
*/
public Class getEnumClass() {
return getClass();
}
/**
* Tests for equality.
*
* Two Enum objects are considered equal
* if they have the same class names and the same names.
* Identity is tested for first, so this method usually runs fast.
*
* If the parameter is in a different class loader than this instance,
* reflection is used to compare the names.
*
* @param other the other object to compare for equality
* @return true
if the Enums are equal
*/
public final boolean equals(Object other) {
if (other == this) {
return true;
} else if (other == null) {
return false;
} else if (other.getClass() == this.getClass()) {
// Ok to do a class cast to Enum here since the test above
// guarantee both
// classes are in the same class loader.
return iName.equals(((Enum) other).iName);
} else {
// This and other are in different class loaders, we must check indirectly
if (other.getClass().getName().equals(this.getClass().getName()) == false) {
return false;
}
return iName.equals( getNameInOtherClassLoader(other) );
}
}
/**
* Returns a suitable hashCode for the enumeration.
*
* @return a hashcode based on the name
*/
public final int hashCode() {
return iHashCode;
}
/**
* Tests for order.
*
* The default ordering is alphabetic by name, but this
* can be overridden by subclasses.
*
* If the parameter is in a different class loader than this instance,
* reflection is used to compare the names.
*
* @see java.lang.Comparable#compareTo(Object)
* @param other the other object to compare to
* @return -ve if this is less than the other object, +ve if greater
* than, 0
of equal
* @throws ClassCastException if other is not an Enum
* @throws NullPointerException if other is null
*/
public int compareTo(Object other) {
if (other == this) {
return 0;
}
if (other.getClass() != this.getClass()) {
if (other.getClass().getName().equals(this.getClass().getName())) {
return iName.compareTo( getNameInOtherClassLoader(other) );
}
throw new ClassCastException(
"Different enum class '" + ClassUtils.getShortClassName(other.getClass()) + "'");
}
return iName.compareTo(((Enum) other).iName);
}
/**
* Use reflection to return an objects class name.
*
* @param other The object to determine the class name for
* @return The class name
*/
private String getNameInOtherClassLoader(Object other) {
try {
Method mth = other.getClass().getMethod("getName", null);
String name = (String) mth.invoke(other, null);
return name;
} catch (NoSuchMethodException e) {
// ignore - should never happen
} catch (IllegalAccessException e) {
// ignore - should never happen
} catch (InvocationTargetException e) {
// ignore - should never happen
}
throw new IllegalStateException("This should not happen");
}
/**
* Human readable description of this Enum item.
*
* @return String in the form type[name]
, for example:
* Color[Red]
. Note that the package name is stripped from
* the type name.
*/
public String toString() {
if (iToString == null) {
String shortName = ClassUtils.getShortClassName(getEnumClass());
iToString = shortName + "[" + getName() + "]";
}
return iToString;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/enums/EnumUtils.java 100644 0 0 11271 11513702442 24667 0 ustar 0 0 /*
* 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.lang.enums;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Utility class for accessing and manipulating {@link Enum}s.
*
* @see Enum
* @see ValuedEnum
* @author Apache Software Foundation
* @author Gary Gregory
* @since 2.1 (class existed in enum package from v1.0)
* @version $Id: EnumUtils.java 905636 2010-02-02 14:03:32Z niallp $
*/
public class EnumUtils {
/**
* Public constructor. This class should not normally be instantiated.
* @since 2.0
*/
public EnumUtils() {
super();
}
/**
* Gets an Enum
object by class and name.
*
* @param enumClass the class of the Enum
to get
* @param name the name of the Enum to get, may be null
* @return the enum object
* @throws IllegalArgumentException if the enum class is null
*/
public static Enum getEnum(Class enumClass, String name) {
return Enum.getEnum(enumClass, name);
}
/**
* Gets a ValuedEnum
object by class and value.
*
* @param enumClass the class of the Enum
to get
* @param value the value of the Enum
to get
* @return the enum object, or null if the enum does not exist
* @throws IllegalArgumentException if the enum class is null
*/
public static ValuedEnum getEnum(Class enumClass, int value) {
return (ValuedEnum) ValuedEnum.getEnum(enumClass, value);
}
/**
* Gets the Map
of Enum
objects by
* name using the Enum
class.
*
* If the requested class has no enum objects an empty
* Map
is returned. The Map
is unmodifiable.
*
* @param enumClass the class of the Enum
to get
* @return the enum object Map
* @throws IllegalArgumentException if the enum class is null
* @throws IllegalArgumentException if the enum class is not a subclass
* of Enum
*/
public static Map getEnumMap(Class enumClass) {
return Enum.getEnumMap(enumClass);
}
/**
* Gets the List
of Enum
objects using
* the Enum
class.
*
* The list is in the order that the objects were created
* (source code order).
*
* If the requested class has no enum objects an empty
* List
is returned. The List
is unmodifiable.
*
* @param enumClass the class of the Enum to get
* @return the enum object Map
* @throws IllegalArgumentException if the enum class is null
* @throws IllegalArgumentException if the enum class is not a subclass
* of Enum
*/
public static List getEnumList(Class enumClass) {
return Enum.getEnumList(enumClass);
}
/**
* Gets an Iterator
over the Enum
objects
* in an Enum
class.
*
* The iterator is in the order that the objects were created
* (source code order).
*
* If the requested class has no enum objects an empty
* Iterator
is returned. The Iterator
* is unmodifiable.
*
* @param enumClass the class of the Enum
to get
* @return an Iterator
of the Enum
objects
* @throws IllegalArgumentException if the enum class is null
* @throws IllegalArgumentException if the enum class is not a subclass of Enum
*/
public static Iterator iterator(Class enumClass) {
return Enum.getEnumList(enumClass).iterator();
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/enums/package.html 100644 0 0 3262 11513702442 24341 0 ustar 0 0
Provides an implementation of the C style enum
in the Java world.
The classic example being an RGB color enumeration.
public final class ColorEnum extends Enum {
public static final ColorEnum RED = new ColorEnum("Red");
public static final ColorEnum GREEN = new ColorEnum("Green");
public static final ColorEnum BLUE = new ColorEnum("Blue");
private ColorEnum(String color) {
super(color);
}
public static ColorEnum getEnum(String color) {
return (ColorEnum) getEnum(ColorEnum.class, color);
}
public static Map getEnumMap() {
return getEnumMap(ColorEnum.class);
}
public static List getEnumList() {
return getEnumList(ColorEnum.class);
}
public static Iterator iterator() {
return iterator(ColorEnum.class);
}
}
@since 2.1
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/enums/ValuedEnum.java 100644 0 0 21060 11513702442 25004 0 ustar 0 0 /*
* 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.lang.enums;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.lang.ClassUtils;
/**
* Abstract superclass for type-safe enums with integer values suitable
* for use in switch
statements.
*
* NOTE:Due to the way in which Java ClassLoaders work, comparing
* Enum
objects should always be done using the equals() method,
* not ==
. The equals() method will try ==
first so
* in most cases the effect is the same.
*
* To use this class, it must be subclassed. For example:
*
*
* public final class JavaVersionEnum extends ValuedEnum {
* //standard enums for version of JVM
* public static final int JAVA1_0_VALUE = 100;
* public static final int JAVA1_1_VALUE = 110;
* public static final int JAVA1_2_VALUE = 120;
* public static final int JAVA1_3_VALUE = 130;
* public static final JavaVersionEnum JAVA1_0 = new JavaVersionEnum( "Java 1.0", JAVA1_0_VALUE );
* public static final JavaVersionEnum JAVA1_1 = new JavaVersionEnum( "Java 1.1", JAVA1_1_VALUE );
* public static final JavaVersionEnum JAVA1_2 = new JavaVersionEnum( "Java 1.2", JAVA1_2_VALUE );
* public static final JavaVersionEnum JAVA1_3 = new JavaVersionEnum( "Java 1.3", JAVA1_3_VALUE );
*
* private JavaVersionEnum(String name, int value) {
* super( name, value );
* }
*
* public static JavaVersionEnum getEnum(String javaVersion) {
* return (JavaVersionEnum) getEnum(JavaVersionEnum.class, javaVersion);
* }
*
* public static JavaVersionEnum getEnum(int javaVersion) {
* return (JavaVersionEnum) getEnum(JavaVersionEnum.class, javaVersion);
* }
*
* public static Map getEnumMap() {
* return getEnumMap(JavaVersionEnum.class);
* }
*
* public static List getEnumList() {
* return getEnumList(JavaVersionEnum.class);
* }
*
* public static Iterator iterator() {
* return iterator(JavaVersionEnum.class);
* }
* }
*
*
* NOTE:These are declared final
, so compilers may
* inline the code. Ensure you recompile everything when using final.
*
* The above class could then be used as follows:
*
*
* public void doSomething(JavaVersionEnum ver) {
* switch (ver.getValue()) {
* case JAVA1_0_VALUE:
* // ...
* break;
* case JAVA1_1_VALUE:
* // ...
* break;
* //...
* }
* }
*
*
* As shown, each enum has a name and a value. These can be accessed using
* getName
and getValue
.
*
* NOTE: Because the switch is ultimately sitting on top of an
* int, the example above is not type-safe. That is, there is nothing that
* checks that JAVA1_0_VALUE is a legal constant for JavaVersionEnum.
*
* The getEnum
and iterator
methods are recommended.
* Unfortunately, Java restrictions require these to be coded as shown in each subclass.
* An alternative choice is to use the {@link EnumUtils} class.
*
* @author Apache Avalon project
* @author Apache Software Foundation
* @since 2.1 (class existed in enum package from v1.0)
* @version $Id: ValuedEnum.java 905636 2010-02-02 14:03:32Z niallp $
*/
public abstract class ValuedEnum extends Enum {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = -7129650521543789085L;
/**
* The value contained in enum.
*/
private final int iValue;
/**
* Constructor for enum item.
*
* @param name the name of enum item
* @param value the value of enum item
*/
protected ValuedEnum(String name, int value) {
super(name);
iValue = value;
}
/**
* Gets an Enum
object by class and value.
*
* This method loops through the list of Enum
,
* thus if there are many Enum
s this will be
* slow.
*
* @param enumClass the class of the Enum
to get
* @param value the value of the Enum
to get
* @return the enum object, or null if the enum does not exist
* @throws IllegalArgumentException if the enum class is null
*/
protected static Enum getEnum(Class enumClass, int value) {
if (enumClass == null) {
throw new IllegalArgumentException("The Enum Class must not be null");
}
List list = Enum.getEnumList(enumClass);
for (Iterator it = list.iterator(); it.hasNext();) {
ValuedEnum enumeration = (ValuedEnum) it.next();
if (enumeration.getValue() == value) {
return enumeration;
}
}
return null;
}
/**
* Get value of enum item.
*
* @return the enum item's value.
*/
public final int getValue() {
return iValue;
}
/**
* Tests for order.
*
* The default ordering is numeric by value, but this
* can be overridden by subclasses.
*
* NOTE: From v2.2 the enums must be of the same type.
* If the parameter is in a different class loader than this instance,
* reflection is used to compare the values.
*
* @see java.lang.Comparable#compareTo(Object)
* @param other the other object to compare to
* @return -ve if this is less than the other object, +ve if greater than,
* 0
of equal
* @throws ClassCastException if other is not an Enum
* @throws NullPointerException if other is null
*/
public int compareTo(Object other) {
if (other == this) {
return 0;
}
if (other.getClass() != this.getClass()) {
if (other.getClass().getName().equals(this.getClass().getName())) {
return iValue - getValueInOtherClassLoader(other);
}
throw new ClassCastException(
"Different enum class '" + ClassUtils.getShortClassName(other.getClass()) + "'");
}
return iValue - ((ValuedEnum) other).iValue;
}
/**
* Use reflection to return an objects value.
*
* @param other the object to determine the value for
* @return the value
*/
private int getValueInOtherClassLoader(Object other) {
try {
Method mth = other.getClass().getMethod("getValue", null);
Integer value = (Integer) mth.invoke(other, null);
return value.intValue();
} catch (NoSuchMethodException e) {
// ignore - should never happen
} catch (IllegalAccessException e) {
// ignore - should never happen
} catch (InvocationTargetException e) {
// ignore - should never happen
}
throw new IllegalStateException("This should not happen");
}
/**
* Human readable description of this Enum
item.
*
* @return String in the form type[name=value]
, for example:
* JavaVersion[Java 1.0=100]
. Note that the package name is
* stripped from the type name.
*/
public String toString() {
if (iToString == null) {
String shortName = ClassUtils.getShortClassName(getEnumClass());
iToString = shortName + "[" + getName() + "=" + getValue() + "]";
}
return iToString;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/exception/CloneFailedException.java 100644 0 0 4157 11513702442 27622 0 ustar 0 0 /*
* 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.lang.exception;
/**
* Exception thrown when a clone cannot be created. In contrast to
* {@link CloneNotSupportedException} this is a {@link RuntimeException}.
*
* @author Apache Software Foundation
* @since 2.6
*/
public class CloneFailedException extends NestableRuntimeException {
// ~ Static fields/initializers ---------------------------------------------
private static final long serialVersionUID = 20091223L;
// ~ Constructors -----------------------------------------------------------
/**
* Constructs a CloneFailedException.
*
* @param message description of the exception
* @since upcoming
*/
public CloneFailedException(final String message) {
super(message);
}
/**
* Constructs a CloneFailedException.
*
* @param cause cause of the exception
* @since upcoming
*/
public CloneFailedException(final Throwable cause) {
super(cause);
}
/**
* Constructs a CloneFailedException.
*
* @param message description of the exception
* @param cause cause of the exception
* @since upcoming
*/
public CloneFailedException(final String message, final Throwable cause) {
super(message, cause);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/exception/ExceptionUtils.java 100644 0 0 117131 11513702442 26612 0 ustar 0 0 /*
* 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.lang.exception;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.ClassUtils;
import org.apache.commons.lang.NullArgumentException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.SystemUtils;
/**
* Provides utilities for manipulating and examining
* Throwable
objects.
*
* @author Apache Software Foundation
* @author Daniel L. Rall
* @author Dmitri Plotnikov
* @author Gary Gregory
* @author Pete Gieser
* @since 1.0
* @version $Id: ExceptionUtils.java 905837 2010-02-02 23:32:11Z niallp $
*/
public class ExceptionUtils {
/**
* 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] ";
// Lock object for CAUSE_METHOD_NAMES
private static final Object CAUSE_METHOD_NAMES_LOCK = new Object();
/**
* The names of methods commonly used to access a wrapped exception.
*/
private static String[] CAUSE_METHOD_NAMES = {
"getCause",
"getNextException",
"getTargetException",
"getException",
"getSourceException",
"getRootCause",
"getCausedByException",
"getNested",
"getLinkedException",
"getNestedException",
"getLinkedCause",
"getThrowable",
};
/**
* The Method object for Java 1.4 getCause.
*/
private static final Method THROWABLE_CAUSE_METHOD;
/**
* The Method object for Java 1.4 initCause.
*/
private static final Method THROWABLE_INITCAUSE_METHOD;
static {
Method causeMethod;
try {
causeMethod = Throwable.class.getMethod("getCause", null);
} catch (Exception e) {
causeMethod = null;
}
THROWABLE_CAUSE_METHOD = causeMethod;
try {
causeMethod = Throwable.class.getMethod("initCause", new Class[]{Throwable.class});
} catch (Exception e) {
causeMethod = null;
}
THROWABLE_INITCAUSE_METHOD = causeMethod;
}
/**
*
* Public constructor allows an instance of ExceptionUtils
to be created, although that is not
* normally necessary.
*
*/
public ExceptionUtils() {
super();
}
//-----------------------------------------------------------------------
/**
* Adds to the list of method names used in the search for Throwable
* objects.
*
* @param methodName the methodName to add to the list, null
* and empty strings are ignored
* @since 2.0
*/
public static void addCauseMethodName(String methodName) {
if (StringUtils.isNotEmpty(methodName) && !isCauseMethodName(methodName)) {
List list = getCauseMethodNameList();
if (list.add(methodName)) {
synchronized(CAUSE_METHOD_NAMES_LOCK) {
CAUSE_METHOD_NAMES = toArray(list);
}
}
}
}
/**
* Removes from the list of method names used in the search for Throwable
* objects.
*
* @param methodName the methodName to remove from the list, null
* and empty strings are ignored
* @since 2.1
*/
public static void removeCauseMethodName(String methodName) {
if (StringUtils.isNotEmpty(methodName)) {
List list = getCauseMethodNameList();
if (list.remove(methodName)) {
synchronized(CAUSE_METHOD_NAMES_LOCK) {
CAUSE_METHOD_NAMES = toArray(list);
}
}
}
}
/**
* Sets the cause of a Throwable
using introspection, allowing
* source code compatibility between pre-1.4 and post-1.4 Java releases.
*
* The typical use of this method is inside a constructor as in
* the following example:
*
*
* import org.apache.commons.lang.exception.ExceptionUtils;
*
* public class MyException extends Exception {
*
* public MyException(String msg) {
* super(msg);
* }
*
* public MyException(String msg, Throwable cause) {
* super(msg);
* ExceptionUtils.setCause(this, cause);
* }
* }
*
*
* @param target the target Throwable
* @param cause the Throwable
to set in the target
* @return a true
if the target has been modified
* @since 2.2
*/
public static boolean setCause(Throwable target, Throwable cause) {
if (target == null) {
throw new NullArgumentException("target");
}
Object[] causeArgs = new Object[]{cause};
boolean modifiedTarget = false;
if (THROWABLE_INITCAUSE_METHOD != null) {
try {
THROWABLE_INITCAUSE_METHOD.invoke(target, causeArgs);
modifiedTarget = true;
} catch (IllegalAccessException ignored) {
// Exception ignored.
} catch (InvocationTargetException ignored) {
// Exception ignored.
}
}
try {
Method setCauseMethod = target.getClass().getMethod("setCause", new Class[]{Throwable.class});
setCauseMethod.invoke(target, causeArgs);
modifiedTarget = true;
} catch (NoSuchMethodException ignored) {
// Exception ignored.
} catch (IllegalAccessException ignored) {
// Exception ignored.
} catch (InvocationTargetException ignored) {
// Exception ignored.
}
return modifiedTarget;
}
/**
* Returns the given list as a String[]
.
* @param list a list to transform.
* @return the given list as a String[]
.
*/
private static String[] toArray(List list) {
return (String[]) list.toArray(new String[list.size()]);
}
/**
* Returns {@link #CAUSE_METHOD_NAMES} as a List.
*
* @return {@link #CAUSE_METHOD_NAMES} as a List.
*/
private static ArrayList getCauseMethodNameList() {
synchronized(CAUSE_METHOD_NAMES_LOCK) {
return new ArrayList(Arrays.asList(CAUSE_METHOD_NAMES));
}
}
/**
* Tests if the list of method names used in the search for Throwable
* objects include the given name.
*
* @param methodName the methodName to search in the list.
* @return if the list of method names used in the search for Throwable
* objects include the given name.
* @since 2.1
*/
public static boolean isCauseMethodName(String methodName) {
synchronized(CAUSE_METHOD_NAMES_LOCK) {
return ArrayUtils.indexOf(CAUSE_METHOD_NAMES, methodName) >= 0;
}
}
//-----------------------------------------------------------------------
/**
* 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, and
* {@link org.apache.commons.lang.exception.NestableException NestableException}.
* The method names can be added to using {@link #addCauseMethodName(String)}.
*
* The default list searched for are:
*
* getCause()
* getNextException()
* getTargetException()
* getException()
* getSourceException()
* getRootCause()
* getCausedByException()
* getNested()
*
*
* In the absence of any such method, the object is inspected for a
* detail
field assignable to a Throwable
.
*
* If none of the above is found, returns null
.
*
* @param throwable the throwable to introspect for a cause, may be null
* @return the cause of the Throwable
,
* null
if none found or null throwable input
* @since 1.0
*/
public static Throwable getCause(Throwable throwable) {
synchronized(CAUSE_METHOD_NAMES_LOCK) {
return getCause(throwable, CAUSE_METHOD_NAMES);
}
}
/**
* Introspects the Throwable
to obtain the cause.
*
*
* - Try known exception types.
* - Try the supplied array of method names.
* - Try the field 'detail'.
*
*
* A null
set of method names means use the default set.
* A null
in the set of method names will be ignored.
*
* @param throwable the throwable to introspect for a cause, may be null
* @param methodNames the method names, null treated as default set
* @return the cause of the Throwable
,
* null
if none found or null throwable input
* @since 1.0
*/
public static Throwable getCause(Throwable throwable, String[] methodNames) {
if (throwable == null) {
return null;
}
Throwable cause = getCauseUsingWellKnownTypes(throwable);
if (cause == null) {
if (methodNames == null) {
synchronized(CAUSE_METHOD_NAMES_LOCK) {
methodNames = CAUSE_METHOD_NAMES;
}
}
for (int i = 0; i < methodNames.length; i++) {
String methodName = methodNames[i];
if (methodName != null) {
cause = getCauseUsingMethodName(throwable, methodName);
if (cause != null) {
break;
}
}
}
if (cause == null) {
cause = getCauseUsingFieldName(throwable, "detail");
}
}
return cause;
}
/**
* 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 the Throwable
,
* null
if none found or null throwable input
*/
public static Throwable getRootCause(Throwable throwable) {
List list = getThrowableList(throwable);
return (list.size() < 2 ? null : (Throwable)list.get(list.size() - 1));
}
/**
* Finds a Throwable
for known types.
*
* Uses instanceof
checks to examine the exception,
* looking for well known types which could contain chained or
* wrapped exceptions.
*
* @param throwable the exception to examine
* @return the wrapped exception, or null
if not found
*/
private static Throwable getCauseUsingWellKnownTypes(Throwable throwable) {
if (throwable instanceof Nestable) {
return ((Nestable) throwable).getCause();
} else if (throwable instanceof SQLException) {
return ((SQLException) throwable).getNextException();
} else if (throwable instanceof InvocationTargetException) {
return ((InvocationTargetException) throwable).getTargetException();
} else {
return null;
}
}
/**
* Finds a Throwable
by method name.
*
* @param throwable the exception to examine
* @param methodName the name of the method to find and invoke
* @return the wrapped exception, or null
if not found
*/
private static Throwable getCauseUsingMethodName(Throwable throwable, String methodName) {
Method method = null;
try {
method = throwable.getClass().getMethod(methodName, null);
} catch (NoSuchMethodException ignored) {
// exception ignored
} catch (SecurityException ignored) {
// exception ignored
}
if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) {
try {
return (Throwable) method.invoke(throwable, ArrayUtils.EMPTY_OBJECT_ARRAY);
} catch (IllegalAccessException ignored) {
// exception ignored
} catch (IllegalArgumentException ignored) {
// exception ignored
} catch (InvocationTargetException ignored) {
// exception ignored
}
}
return null;
}
/**
* Finds a Throwable
by field name.
*
* @param throwable the exception to examine
* @param fieldName the name of the attribute to examine
* @return the wrapped exception, or null
if not found
*/
private static Throwable getCauseUsingFieldName(Throwable throwable, String fieldName) {
Field field = null;
try {
field = throwable.getClass().getField(fieldName);
} catch (NoSuchFieldException ignored) {
// exception ignored
} catch (SecurityException ignored) {
// exception ignored
}
if (field != null && Throwable.class.isAssignableFrom(field.getType())) {
try {
return (Throwable) field.get(throwable);
} catch (IllegalAccessException ignored) {
// exception ignored
} catch (IllegalArgumentException ignored) {
// exception ignored
}
}
return null;
}
//-----------------------------------------------------------------------
/**
* Checks if the Throwable class has a getCause
method.
*
* This is true for JDK 1.4 and above.
*
* @return true if Throwable is nestable
* @since 2.0
*/
public static boolean isThrowableNested() {
return THROWABLE_CAUSE_METHOD != null;
}
/**
* Checks whether this Throwable
class can store a cause.
*
* This method does not check whether it actually does store a cause.
*
* @param throwable the Throwable
to examine, may be null
* @return boolean true
if nested otherwise false
* @since 2.0
*/
public static boolean isNestedThrowable(Throwable throwable) {
if (throwable == null) {
return false;
}
if (throwable instanceof Nestable) {
return true;
} else if (throwable instanceof SQLException) {
return true;
} else if (throwable instanceof InvocationTargetException) {
return true;
} else if (isThrowableNested()) {
return true;
}
Class cls = throwable.getClass();
synchronized(CAUSE_METHOD_NAMES_LOCK) {
for (int i = 0, isize = CAUSE_METHOD_NAMES.length; i < isize; i++) {
try {
Method method = cls.getMethod(CAUSE_METHOD_NAMES[i], null);
if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) {
return true;
}
} catch (NoSuchMethodException ignored) {
// exception ignored
} catch (SecurityException ignored) {
// exception ignored
}
}
}
try {
Field field = cls.getField("detail");
if (field != null) {
return true;
}
} catch (NoSuchFieldException ignored) {
// exception ignored
} catch (SecurityException ignored) {
// exception ignored
}
return false;
}
//-----------------------------------------------------------------------
/**
*
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) {
List list = getThrowableList(throwable);
return (Throwable[]) list.toArray(new Throwable[list.size()]);
}
/**
* Returns 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 List getThrowableList(Throwable throwable) {
List list = new ArrayList();
while (throwable != null && list.contains(throwable) == false) {
list.add(throwable);
throwable = ExceptionUtils.getCause(throwable);
}
return list;
}
//-----------------------------------------------------------------------
/**
* Returns 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
.
*
* @param throwable the throwable to inspect, may be null
* @param clazz the class to search for, subclasses do not match, null returns -1
* @return the index into the throwable chain, -1 if no match or null input
*/
public static int indexOfThrowable(Throwable throwable, Class clazz) {
return indexOf(throwable, clazz, 0, false);
}
/**
* 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
.
*
* @param throwable the throwable to inspect, may be null
* @param clazz the class to search for, subclasses do not match, null returns -1
* @param fromIndex the (zero based) index of the starting position,
* negative treated as zero, larger than chain size returns -1
* @return the index into the throwable chain, -1 if no match or null input
*/
public static int indexOfThrowable(Throwable throwable, Class clazz, int fromIndex) {
return indexOf(throwable, clazz, fromIndex, false);
}
//-----------------------------------------------------------------------
/**
* 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
.
*
* @param throwable the throwable to inspect, may be null
* @param type the type to search for, subclasses match, null returns -1
* @return the index into the throwable chain, -1 if no match or null input
* @since 2.1
*/
public static int indexOfType(Throwable throwable, Class type) {
return indexOf(throwable, type, 0, true);
}
/**
* 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
.
*
* @param throwable the throwable to inspect, may be null
* @param type the type to search for, subclasses match, null returns -1
* @param fromIndex the (zero based) index of the starting position,
* negative treated as zero, larger than chain size returns -1
* @return the index into the throwable chain, -1 if no match or null input
* @since 2.1
*/
public static int indexOfType(Throwable throwable, Class type, int fromIndex) {
return indexOf(throwable, type, fromIndex, true);
}
/**
* Worker method for the indexOfType
methods.
*
* @param throwable the throwable to inspect, may be null
* @param type the type to search for, subclasses match, null returns -1
* @param fromIndex the (zero based) index of the starting position,
* negative treated as zero, larger than chain size returns -1
* @param subclass if 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.
*
* @param throwable the throwable to output
* @since 2.0
*/
public static void printRootCauseStackTrace(Throwable throwable) {
printRootCauseStackTrace(throwable, System.err);
}
/**
* 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.
*
* @param throwable the throwable to output, may be null
* @param stream the stream to output to, may not be null
* @throws IllegalArgumentException if the stream is 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 (int i = 0; i < trace.length; i++) {
stream.println(trace[i]);
}
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.
*
* @param throwable the throwable to output, may be null
* @param writer the writer to output to, may not be null
* @throws IllegalArgumentException if the writer is 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 (int i = 0; i < trace.length; i++) {
writer.println(trace[i]);
}
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;
ArrayList frames = new ArrayList();
List nextTrace = getStackFrameList(throwables[count - 1]);
for (int i = count; --i >= 0;) {
List trace = nextTrace;
if (i != 0) {
nextTrace = getStackFrameList(throwables[i - 1]);
removeCommonFrames(trace, nextTrace);
}
if (i == count - 1) {
frames.add(throwables[i].toString());
} else {
frames.add(WRAPPED_MARKER + throwables[i].toString());
}
for (int j = 0; j < trace.size(); j++) {
frames.add(trace.get(j));
}
}
return (String[]) frames.toArray(new String[0]);
}
/**
* Removes 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(List causeFrames, List wrapperFrames) {
if (causeFrames == null || wrapperFrames == null) {
throw new IllegalArgumentException("The List must not be null");
}
int causeFrameIndex = causeFrames.size() - 1;
int wrapperFrameIndex = wrapperFrames.size() - 1;
while (causeFrameIndex >= 0 && wrapperFrameIndex >= 0) {
// Remove the frame from the cause trace if it is the same
// as in the wrapper trace
String causeFrame = (String) causeFrames.get(causeFrameIndex);
String wrapperFrame = (String) wrapperFrames.get(wrapperFrameIndex);
if (causeFrame.equals(wrapperFrame)) {
causeFrames.remove(causeFrameIndex);
}
causeFrameIndex--;
wrapperFrameIndex--;
}
}
//-----------------------------------------------------------------------
/**
* A way to get the entire nested stack-trace of an throwable.
*
* The result of this method is highly dependent on the JDK version
* and whether the exceptions override printStackTrace or not.
*
* @param throwable the Throwable
to be examined
* @return the nested stack trace, with the root cause first
* @since 2.0
*/
public static String getFullStackTrace(Throwable throwable) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
Throwable[] ts = getThrowables(throwable);
for (int i = 0; i < ts.length; i++) {
ts[i].printStackTrace(pw);
if (isNestedThrowable(ts[i])) {
break;
}
}
return sw.getBuffer().toString();
}
//-----------------------------------------------------------------------
/**
* Gets 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 the Throwable
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 the Throwable
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}.
*
* Functionality shared between the
* getStackFrames(Throwable)
methods of this and the
* {@link org.apache.commons.lang.exception.NestableDelegate} classes.
*
* @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);
List list = new ArrayList();
while (frames.hasMoreTokens()) {
list.add(frames.nextToken());
}
return toArray(list);
}
/**
* Produces 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".
*
* @param t is any throwable
* @return List of stack frames
*/
static List getStackFrameList(Throwable t) {
String stackTrace = getStackTrace(t);
String linebreak = SystemUtils.LINE_SEPARATOR;
StringTokenizer frames = new StringTokenizer(stackTrace, linebreak);
List list = new ArrayList();
boolean traceStarted = false;
while (frames.hasMoreTokens()) {
String token = frames.nextToken();
// Determine if the line starts with at
int at = token.indexOf("at");
if (at != -1 && token.substring(0, at).trim().length() == 0) {
traceStarted = true;
list.add(token);
} else if (traceStarted) {
break;
}
}
return list;
}
//-----------------------------------------------------------------------
/**
* Gets a short message summarising the 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 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);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/exception/Nestable.java 100644 0 0 16107 11513702442 25351 0 ustar 0 0 /*
* 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.lang.exception;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* An interface to be implemented by {@link java.lang.Throwable}
* extensions which would like to be able to nest root exceptions
* inside themselves.
*
* @author Daniel L. Rall
* @author Kasper Nielsen
* @author Steven Caswell
* @author Pete Gieser
* @since 1.0
* @version $Id: Nestable.java 512889 2007-02-28 18:18:20Z dlr $
*/
public interface Nestable {
/**
* Returns the reference to the exception or error that caused the
* exception implementing the Nestable
to be thrown.
*
* @return throwable that caused the original exception
*/
public Throwable getCause();
/**
* Returns the error message of this and any nested
* Throwable
.
*
* @return the error message
*/
public String getMessage();
/**
* Returns the error message of the Throwable
in the chain
* of Throwable
s at the specified index, numbered from 0.
*
* @param index the index of the Throwable
in the chain of
* Throwable
s
* @return the error message, or null if the Throwable
at the
* specified index in the chain does not contain a message
* @throws IndexOutOfBoundsException if the index
argument is
* negative or not less than the count of Throwable
s in the
* chain
*/
public String getMessage(int index);
/**
* Returns the error message of this and any nested Throwable
s
* in an array of Strings, one element for each message. Any
* Throwable
not containing a message is represented in the
* array by a null. This has the effect of cause the length of the returned
* array to be equal to the result of the {@link #getThrowableCount()}
* operation.
*
* @return the error messages
*/
public String[] getMessages();
/**
* Returns the Throwable
in the chain of
* Throwable
s at the specified index, numbered from 0.
*
* @param index the index, numbered from 0, of the Throwable
in
* the chain of Throwable
s
* @return the Throwable
* @throws IndexOutOfBoundsException if the index
argument is
* negative or not less than the count of Throwable
s in the
* chain
*/
public Throwable getThrowable(int index);
/**
* Returns the number of nested Throwable
s represented by
* this Nestable
, including this Nestable
.
*
* @return the throwable count
*/
public int getThrowableCount();
/**
* Returns this Nestable
and any nested Throwable
s
* in an array of Throwable
s, one element for each
* Throwable
.
*
* @return the Throwable
s
*/
public Throwable[] getThrowables();
/**
* Returns the index, numbered from 0, of the first occurrence of the
* specified type, or a subclass, in the chain of Throwable
s.
* The method returns -1 if the specified type is not found in the chain.
*
* NOTE: From v2.1, we have clarified the Nestable
interface
* such that this method matches subclasses.
* If you want to NOT match subclasses, please use
* {@link ExceptionUtils#indexOfThrowable(Throwable, Class)}
* (which is avaiable in all versions of lang).
*
* @param type the type to find, subclasses match, null returns -1
* @return index of the first occurrence of the type in the chain, or -1 if
* the type is not found
*/
public int indexOfThrowable(Class type);
/**
* Returns the index, numbered from 0, of the first Throwable
* that matches the specified type, or a subclass, in the chain of Throwable
s
* with an index greater than or equal to the specified index.
* The method returns -1 if the specified type is not found in the chain.
*
* NOTE: From v2.1, we have clarified the Nestable
interface
* such that this method matches subclasses.
* If you want to NOT match subclasses, please use
* {@link ExceptionUtils#indexOfThrowable(Throwable, Class, int)}
* (which is avaiable in all versions of lang).
*
* @param type the type to find, subclasses match, null returns -1
* @param fromIndex the index, numbered from 0, of the starting position in
* the chain to be searched
* @return index of the first occurrence of the type in the chain, or -1 if
* the type is not found
* @throws IndexOutOfBoundsException if the fromIndex
argument
* is negative or not less than the count of Throwable
s in the
* chain
*/
public int indexOfThrowable(Class type, int fromIndex);
/**
* Prints the stack trace of this exception to the specified print
* writer. Includes information from the exception, if any,
* which caused this exception.
*
* @param out PrintWriter
to use for output.
*/
public void printStackTrace(PrintWriter out);
/**
* Prints the stack trace of this exception to the specified print
* stream. Includes information from the exception, if any,
* which caused this exception.
*
* @param out PrintStream
to use for output.
*/
public void printStackTrace(PrintStream out);
/**
* Prints the stack trace for this exception only--root cause not
* included--using the provided writer. Used by
* {@link org.apache.commons.lang.exception.NestableDelegate} to write
* individual stack traces to a buffer. The implementation of
* this method should call
* super.printStackTrace(out);
in most cases.
*
* @param out The writer to use.
*/
public void printPartialStackTrace(PrintWriter out);
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/exception/NestableDelegate.java 100644 0 0 36442 11513702442 27010 0 ustar 0 0 /*
* 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.lang.exception;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
*
A shared implementation of the nestable exception functionality.
*
* The code is shared between
* {@link org.apache.commons.lang.exception.NestableError NestableError},
* {@link org.apache.commons.lang.exception.NestableException NestableException} and
* {@link org.apache.commons.lang.exception.NestableRuntimeException NestableRuntimeException}.
*
*
* @author Apache Software Foundation
* @author Rafal Krzewski
* @author Daniel L. Rall
* @author Kasper Nielsen
* @author Steven Caswell
* @author Sean C. Sullivan
* @since 1.0
* @version $Id: NestableDelegate.java 905636 2010-02-02 14:03:32Z niallp $
*/
public class NestableDelegate implements Serializable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 1L;
/**
* Constructor error message.
*/
private transient static final String MUST_BE_THROWABLE =
"The Nestable implementation passed to the NestableDelegate(Nestable) "
+ "constructor must extend java.lang.Throwable";
/**
* Holds the reference to the exception or error that we're
* wrapping (which must be a {@link
* org.apache.commons.lang.exception.Nestable} implementation).
*/
private Throwable nestable = null;
/**
* Whether to print the stack trace top-down.
* This public flag may be set by calling code, typically in initialisation.
* This exists for backwards compatability, setting it to false will return
* the library to v1.0 behaviour (but will affect all users of the library
* in the classloader).
* @since 2.0
*/
public static boolean topDown = true;
/**
* Whether to trim the repeated stack trace.
* This public flag may be set by calling code, typically in initialisation.
* This exists for backwards compatability, setting it to false will return
* the library to v1.0 behaviour (but will affect all users of the library
* in the classloader).
* @since 2.0
*/
public static boolean trimStackFrames = true;
/**
* Whether to match subclasses via indexOf.
* This public flag may be set by calling code, typically in initialisation.
* This exists for backwards compatability, setting it to false will return
* the library to v2.0 behaviour (but will affect all users of the library
* in the classloader).
* @since 2.1
*/
public static boolean matchSubclasses = true;
/**
* Constructs a new NestableDelegate
instance to manage the
* specified Nestable
.
*
* @param nestable the Nestable implementation (must extend
* {@link java.lang.Throwable})
* @since 2.0
*/
public NestableDelegate(Nestable nestable) {
if (nestable instanceof Throwable) {
this.nestable = (Throwable) nestable;
} else {
throw new IllegalArgumentException(MUST_BE_THROWABLE);
}
}
/**
* Returns the error message of the Throwable
in the chain of Throwable
s at the
* specified index, numbered from 0.
*
* @param index
* the index of the Throwable
in the chain of Throwable
s
* @return the error message, or null if the Throwable
at the specified index in the chain does not
* contain a message
* @throws IndexOutOfBoundsException
* if the index
argument is negative or not less than the count of Throwable
s
* in the chain
* @since 2.0
*/
public String getMessage(int index) {
Throwable t = this.getThrowable(index);
if (Nestable.class.isInstance(t)) {
return ((Nestable) t).getMessage(0);
}
return t.getMessage();
}
/**
* Returns the full message contained by the Nestable
and any nested Throwable
s.
*
* @param baseMsg
* the base message to use when creating the full message. Should be generally be called via
* nestableHelper.getMessage(super.getMessage())
, where super
is an
* instance of {@link java.lang.Throwable}.
* @return The concatenated message for this and all nested Throwable
s
* @since 2.0
*/
public String getMessage(String baseMsg) {
Throwable nestedCause = ExceptionUtils.getCause(this.nestable);
String causeMsg = nestedCause == null ? null : nestedCause.getMessage();
if (nestedCause == null || causeMsg == null) {
return baseMsg; // may be null, which is a valid result
}
if (baseMsg == null) {
return causeMsg;
}
return baseMsg + ": " + causeMsg;
}
/**
* Returns the error message of this and any nested Throwable
s in an array of Strings, one element
* for each message. Any Throwable
not containing a message is represented in the array by a null.
* This has the effect of cause the length of the returned array to be equal to the result of the
* {@link #getThrowableCount()} operation.
*
* @return the error messages
* @since 2.0
*/
public String[] getMessages() {
Throwable[] throwables = this.getThrowables();
String[] msgs = new String[throwables.length];
for (int i = 0; i < throwables.length; i++) {
msgs[i] =
(Nestable.class.isInstance(throwables[i])
? ((Nestable) throwables[i]).getMessage(0)
: throwables[i].getMessage());
}
return msgs;
}
/**
* Returns the Throwable
in the chain of
* Throwable
s at the specified index, numbered from 0.
*
* @param index the index, numbered from 0, of the Throwable
in
* the chain of Throwable
s
* @return the Throwable
* @throws IndexOutOfBoundsException if the index
argument is
* negative or not less than the count of Throwable
s in the
* chain
* @since 2.0
*/
public Throwable getThrowable(int index) {
if (index == 0) {
return this.nestable;
}
Throwable[] throwables = this.getThrowables();
return throwables[index];
}
/**
* Returns the number of Throwable
s contained in the
* Nestable
contained by this delegate.
*
* @return the throwable count
* @since 2.0
*/
public int getThrowableCount() {
return ExceptionUtils.getThrowableCount(this.nestable);
}
/**
* Returns this delegate's Nestable
and any nested
* Throwable
s in an array of Throwable
s, one
* element for each Throwable
.
*
* @return the Throwable
s
* @since 2.0
*/
public Throwable[] getThrowables() {
return ExceptionUtils.getThrowables(this.nestable);
}
/**
* Returns the index, numbered from 0, of the first Throwable
* that matches the specified type, or a subclass, in the chain of Throwable
s
* with an index greater than or equal to the specified index.
* The method returns -1 if the specified type is not found in the chain.
*
* NOTE: From v2.1, we have clarified the Nestable
interface
* such that this method matches subclasses.
* If you want to NOT match subclasses, please use
* {@link ExceptionUtils#indexOfThrowable(Throwable, Class, int)}
* (which is avaiable in all versions of lang).
* An alternative is to use the public static flag {@link #matchSubclasses}
* on NestableDelegate
, however this is not recommended.
*
* @param type the type to find, subclasses match, null returns -1
* @param fromIndex the index, numbered from 0, of the starting position in
* the chain to be searched
* @return index of the first occurrence of the type in the chain, or -1 if
* the type is not found
* @throws IndexOutOfBoundsException if the fromIndex
argument
* is negative or not less than the count of Throwable
s in the
* chain
* @since 2.0
*/
public int indexOfThrowable(Class type, int fromIndex) {
if (type == null) {
return -1;
}
if (fromIndex < 0) {
throw new IndexOutOfBoundsException("The start index was out of bounds: " + fromIndex);
}
Throwable[] throwables = ExceptionUtils.getThrowables(this.nestable);
if (fromIndex >= throwables.length) {
throw new IndexOutOfBoundsException("The start index was out of bounds: "
+ fromIndex + " >= " + throwables.length);
}
if (matchSubclasses) {
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 the stack trace of this exception the the standar error
* stream.
*/
public void printStackTrace() {
printStackTrace(System.err);
}
/**
* Prints the stack trace of this exception to the specified
* stream.
*
* @param out PrintStream
to use for output.
* @see #printStackTrace(PrintWriter)
*/
public void printStackTrace(PrintStream out) {
synchronized (out) {
PrintWriter pw = new PrintWriter(out, false);
printStackTrace(pw);
// Flush the PrintWriter before it's GC'ed.
pw.flush();
}
}
/**
* Prints the stack trace of this exception to the specified
* writer. If the Throwable class has a getCause
* method (i.e. running on jre1.4 or higher), this method just
* uses Throwable's printStackTrace() method. Otherwise, generates
* the stack-trace, by taking into account the 'topDown' and
* 'trimStackFrames' parameters. The topDown and trimStackFrames
* are set to 'true' by default (produces jre1.4-like stack trace).
*
* @param out PrintWriter
to use for output.
*/
public void printStackTrace(PrintWriter out) {
Throwable throwable = this.nestable;
// if running on jre1.4 or higher, use default printStackTrace
if (ExceptionUtils.isThrowableNested()) {
if (throwable instanceof Nestable) {
((Nestable)throwable).printPartialStackTrace(out);
} else {
throwable.printStackTrace(out);
}
return;
}
// generating the nested stack trace
List stacks = new ArrayList();
while (throwable != null) {
String[] st = getStackFrames(throwable);
stacks.add(st);
throwable = ExceptionUtils.getCause(throwable);
}
// If NOT topDown, reverse the stack
String separatorLine = "Caused by: ";
if (!topDown) {
separatorLine = "Rethrown as: ";
Collections.reverse(stacks);
}
// Remove the repeated lines in the stack
if (trimStackFrames) {
trimStackFrames(stacks);
}
synchronized (out) {
for (Iterator iter=stacks.iterator(); iter.hasNext();) {
String[] st = (String[]) iter.next();
for (int i=0, len=st.length; i < len; i++) {
out.println(st[i]);
}
if (iter.hasNext()) {
out.print(separatorLine);
}
}
}
}
/**
* Captures the stack trace associated with the specified
* Throwable
object, decomposing it into a list of
* stack frames.
*
* @param t The Throwable
.
* @return An array of strings describing each stack frame.
* @since 2.0
*/
protected String[] getStackFrames(Throwable t) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
// Avoid infinite loop between decompose() and printStackTrace().
if (t instanceof Nestable) {
((Nestable) t).printPartialStackTrace(pw);
} else {
t.printStackTrace(pw);
}
return ExceptionUtils.getStackFrames(sw.getBuffer().toString());
}
/**
* Trims the stack frames. The first set is left untouched. The rest
* of the frames are truncated from the bottom by comparing with
* one just on top.
*
* @param stacks The list containing String[] elements
* @since 2.0
*/
protected void trimStackFrames(List stacks) {
for (int size=stacks.size(), i=size-1; i > 0; i--) {
String[] curr = (String[]) stacks.get(i);
String[] next = (String[]) stacks.get(i-1);
List currList = new ArrayList(Arrays.asList(curr));
List nextList = new ArrayList(Arrays.asList(next));
ExceptionUtils.removeCommonFrames(currList, nextList);
int trimmed = curr.length - currList.size();
if (trimmed > 0) {
currList.add("\t... "+trimmed+" more");
stacks.set(
i,
currList.toArray(new String[currList.size()])
);
}
}
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/exception/NestableError.java 100644 0 0 12000 11513702442 26347 0 ustar 0 0 /*
* 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.lang.exception;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* The base class of all errors which can contain other exceptions.
*
* @author Daniel L. Rall
* @see org.apache.commons.lang.exception.NestableException
* @since 1.0
* @version $Id: NestableError.java 512889 2007-02-28 18:18:20Z dlr $
*/
public class NestableError extends Error implements Nestable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 1L;
/**
* The helper instance which contains much of the code which we
* delegate to.
*/
protected NestableDelegate delegate = new NestableDelegate(this);
/**
* Holds the reference to the exception or error that caused
* this exception to be thrown.
*/
private Throwable cause = null;
/**
* Constructs a new NestableError
without specified
* detail message.
*/
public NestableError() {
super();
}
/**
* Constructs a new NestableError
with specified
* detail message.
*
* @param msg The error message.
*/
public NestableError(String msg) {
super(msg);
}
/**
* Constructs a new NestableError
with specified
* nested Throwable
.
*
* @param cause the exception or error that caused this exception to be
* thrown
*/
public NestableError(Throwable cause) {
super();
this.cause = cause;
}
/**
* Constructs a new NestableError
with specified
* detail message and nested Throwable
.
*
* @param msg the error message
* @param cause the exception or error that caused this exception to be
* thrown
*/
public NestableError(String msg, Throwable cause) {
super(msg);
this.cause = cause;
}
/**
* {@inheritDoc}
*/
public Throwable getCause() {
return cause;
}
/**
* Returns the detail message string of this throwable. If it was
* created with a null message, returns the following:
* (cause==null ? null : cause.toString()).
*
* @return String message string of the throwable
*/
public String getMessage() {
if (super.getMessage() != null) {
return super.getMessage();
} else if (cause != null) {
return cause.toString();
} else {
return null;
}
}
/**
* {@inheritDoc}
*/
public String getMessage(int index) {
if (index == 0) {
return super.getMessage();
}
return delegate.getMessage(index);
}
/**
* {@inheritDoc}
*/
public String[] getMessages() {
return delegate.getMessages();
}
/**
* {@inheritDoc}
*/
public Throwable getThrowable(int index) {
return delegate.getThrowable(index);
}
/**
* {@inheritDoc}
*/
public int getThrowableCount() {
return delegate.getThrowableCount();
}
/**
* {@inheritDoc}
*/
public Throwable[] getThrowables() {
return delegate.getThrowables();
}
/**
* {@inheritDoc}
*/
public int indexOfThrowable(Class type) {
return delegate.indexOfThrowable(type, 0);
}
/**
* {@inheritDoc}
*/
public int indexOfThrowable(Class type, int fromIndex) {
return delegate.indexOfThrowable(type, fromIndex);
}
/**
* {@inheritDoc}
*/
public void printStackTrace() {
delegate.printStackTrace();
}
/**
* {@inheritDoc}
*/
public void printStackTrace(PrintStream out) {
delegate.printStackTrace(out);
}
/**
* {@inheritDoc}
*/
public void printStackTrace(PrintWriter out) {
delegate.printStackTrace(out);
}
/**
* {@inheritDoc}
*/
public final void printPartialStackTrace(PrintWriter out) {
super.printStackTrace(out);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/exception/NestableException.java 100644 0 0 16341 11513702442 27230 0 ustar 0 0 /*
* 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.lang.exception;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* The base class of all exceptions which can contain other exceptions.
*
* It is intended to ease the debugging by carrying on the information
* about the exception which was caught and provoked throwing the
* current exception. Catching and rethrowing may occur multiple
* times, and provided that all exceptions except the first one
* are descendants of NestedException
, when the
* exception is finally printed out using any of the
* printStackTrace()
methods, the stack trace will contain
* the information about all exceptions thrown and caught on
* the way.
*
Running the following program
*
* 1 import org.apache.commons.lang.exception.NestableException;
* 2
* 3 public class Test {
* 4 public static void main( String[] args ) {
* 5 try {
* 6 a();
* 7 } catch(Exception e) {
* 8 e.printStackTrace();
* 9 }
* 10 }
* 11
* 12 public static void a() throws Exception {
* 13 try {
* 14 b();
* 15 } catch(Exception e) {
* 16 throw new NestableException("foo", e);
* 17 }
* 18 }
* 19
* 20 public static void b() throws Exception {
* 21 try {
* 22 c();
* 23 } catch(Exception e) {
* 24 throw new NestableException("bar", e);
* 25 }
* 26 }
* 27
* 28 public static void c() throws Exception {
* 29 throw new Exception("baz");
* 30 }
* 31 }
*
* Yields the following stack trace:
*
* org.apache.commons.lang.exception.NestableException: foo
* at Test.a(Test.java:16)
* at Test.main(Test.java:6)
* Caused by: org.apache.commons.lang.exception.NestableException: bar
* at Test.b(Test.java:24)
* at Test.a(Test.java:14)
* ... 1 more
* Caused by: java.lang.Exception: baz
* at Test.c(Test.java:29)
* at Test.b(Test.java:22)
* ... 2 more
*
*
* @author Rafal Krzewski
* @author Daniel L. Rall
* @author Kasper Nielsen
* @author Steven Caswell
* @since 1.0
* @version $Id: NestableException.java 512889 2007-02-28 18:18:20Z dlr $
*/
public class NestableException extends Exception implements Nestable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 1L;
/**
* The helper instance which contains much of the code which we
* delegate to.
*/
protected NestableDelegate delegate = new NestableDelegate(this);
/**
* Holds the reference to the exception or error that caused
* this exception to be thrown.
*/
private Throwable cause = null;
/**
* Constructs a new NestableException
without specified
* detail message.
*/
public NestableException() {
super();
}
/**
* Constructs a new NestableException
with specified
* detail message.
*
* @param msg The error message.
*/
public NestableException(String msg) {
super(msg);
}
/**
* Constructs a new NestableException
with specified
* nested Throwable
.
*
* @param cause the exception or error that caused this exception to be
* thrown
*/
public NestableException(Throwable cause) {
super();
this.cause = cause;
}
/**
* Constructs a new NestableException
with specified
* detail message and nested Throwable
.
*
* @param msg the error message
* @param cause the exception or error that caused this exception to be
* thrown
*/
public NestableException(String msg, Throwable cause) {
super(msg);
this.cause = cause;
}
/**
* {@inheritDoc}
*/
public Throwable getCause() {
return cause;
}
/**
* Returns the detail message string of this throwable. If it was
* created with a null message, returns the following:
* (cause==null ? null : cause.toString()).
*
* @return String message string of the throwable
*/
public String getMessage() {
if (super.getMessage() != null) {
return super.getMessage();
} else if (cause != null) {
return cause.toString();
} else {
return null;
}
}
/**
* {@inheritDoc}
*/
public String getMessage(int index) {
if (index == 0) {
return super.getMessage();
}
return delegate.getMessage(index);
}
/**
* {@inheritDoc}
*/
public String[] getMessages() {
return delegate.getMessages();
}
/**
* {@inheritDoc}
*/
public Throwable getThrowable(int index) {
return delegate.getThrowable(index);
}
/**
* {@inheritDoc}
*/
public int getThrowableCount() {
return delegate.getThrowableCount();
}
/**
* {@inheritDoc}
*/
public Throwable[] getThrowables() {
return delegate.getThrowables();
}
/**
* {@inheritDoc}
*/
public int indexOfThrowable(Class type) {
return delegate.indexOfThrowable(type, 0);
}
/**
* {@inheritDoc}
*/
public int indexOfThrowable(Class type, int fromIndex) {
return delegate.indexOfThrowable(type, fromIndex);
}
/**
* {@inheritDoc}
*/
public void printStackTrace() {
delegate.printStackTrace();
}
/**
* {@inheritDoc}
*/
public void printStackTrace(PrintStream out) {
delegate.printStackTrace(out);
}
/**
* {@inheritDoc}
*/
public void printStackTrace(PrintWriter out) {
delegate.printStackTrace(out);
}
/**
* {@inheritDoc}
*/
public final void printPartialStackTrace(PrintWriter out) {
super.printStackTrace(out);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/exception/NestableRuntimeException.java 100644 0 0 12540 11513702442 30571 0 ustar 0 0 /*
* 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.lang.exception;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* The base class of all runtime exceptions which can contain other
* exceptions.
*
* @see org.apache.commons.lang.exception.NestableException
* @author Rafal Krzewski
* @author Daniel L. Rall
* @author Kasper Nielsen
* @author Steven Caswell
* @since 1.0
* @version $Id: NestableRuntimeException.java 512889 2007-02-28 18:18:20Z dlr $
*/
public class NestableRuntimeException extends RuntimeException implements Nestable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 1L;
/**
* The helper instance which contains much of the code which we
* delegate to.
*/
protected NestableDelegate delegate = new NestableDelegate(this);
/**
* Holds the reference to the exception or error that caused
* this exception to be thrown.
*/
private Throwable cause = null;
/**
* Constructs a new NestableRuntimeException
without specified
* detail message.
*/
public NestableRuntimeException() {
super();
}
/**
* Constructs a new NestableRuntimeException
with specified
* detail message.
*
* @param msg the error message
*/
public NestableRuntimeException(String msg) {
super(msg);
}
/**
* Constructs a new NestableRuntimeException
with specified
* nested Throwable
.
*
* @param cause the exception or error that caused this exception to be
* thrown
*/
public NestableRuntimeException(Throwable cause) {
super();
this.cause = cause;
}
/**
* Constructs a new NestableRuntimeException
with specified
* detail message and nested Throwable
.
*
* @param msg the error message
* @param cause the exception or error that caused this exception to be
* thrown
*/
public NestableRuntimeException(String msg, Throwable cause) {
super(msg);
this.cause = cause;
}
/**
* {@inheritDoc}
*/
public Throwable getCause() {
return cause;
}
/**
* Returns the detail message string of this throwable. If it was
* created with a null message, returns the following:
* (cause==null ? null : cause.toString()).
*
* @return String message string of the throwable
*/
public String getMessage() {
if (super.getMessage() != null) {
return super.getMessage();
} else if (cause != null) {
return cause.toString();
} else {
return null;
}
}
/**
* {@inheritDoc}
*/
public String getMessage(int index) {
if (index == 0) {
return super.getMessage();
}
return delegate.getMessage(index);
}
/**
* {@inheritDoc}
*/
public String[] getMessages() {
return delegate.getMessages();
}
/**
* {@inheritDoc}
*/
public Throwable getThrowable(int index) {
return delegate.getThrowable(index);
}
/**
* {@inheritDoc}
*/
public int getThrowableCount() {
return delegate.getThrowableCount();
}
/**
* {@inheritDoc}
*/
public Throwable[] getThrowables() {
return delegate.getThrowables();
}
/**
* {@inheritDoc}
*/
public int indexOfThrowable(Class type) {
return delegate.indexOfThrowable(type, 0);
}
/**
* {@inheritDoc}
*/
public int indexOfThrowable(Class type, int fromIndex) {
return delegate.indexOfThrowable(type, fromIndex);
}
/**
* {@inheritDoc}
*/
public void printStackTrace() {
delegate.printStackTrace();
}
/**
* {@inheritDoc}
*/
public void printStackTrace(PrintStream out) {
delegate.printStackTrace(out);
}
/**
* {@inheritDoc}
*/
public void printStackTrace(PrintWriter out) {
delegate.printStackTrace(out);
}
/**
* {@inheritDoc}
*/
public final void printPartialStackTrace(PrintWriter out) {
super.printStackTrace(out);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/exception/package.html 100644 0 0 2270 11513702442 25206 0 ustar 0 0
Provides JDK 1.4 style Nested Exception functionality for those on prior Java
versions.
Includes a static utility to create version independent Nested
Exception which can handle JDK 1.4 Exceptions as well as others.
Lastly, {@link org.apache.commons.lang.exception.ExceptionUtils}
also contains Throwable
manipulation and examination routines.
@since 1.0
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/IllegalClassException.java 100644 0 0 7165 11513702446 26024 0 ustar 0 0 /*
* 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.lang;
/**
* Thrown when an object is an instance of an unexpected type (a class or interface).
* This exception supplements the standard IllegalArgumentException
* by providing a more semantically rich description of the problem.
*
* IllegalClassException
represents the case where a method takes
* in a genericly typed parameter like Object (typically because it has to due to some
* other interface it implements), but this implementation only actually accepts a specific
* type, for example String. This exception would be used in place of
* IllegalArgumentException
, yet it still extends it.
*
*
* public void foo(Object obj) {
* if (obj instanceof String == false) {
* throw new IllegalClassException(String.class, obj);
* }
* // do something with the string
* }
*
*
* @author Apache Software Foundation
* @author Matthew Hawthorne
* @author Gary Gregory
* @since 2.0
* @version $Id: IllegalClassException.java 905636 2010-02-02 14:03:32Z niallp $
*/
public class IllegalClassException extends IllegalArgumentException {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 8063272569377254819L;
/**
* Instantiates with the expected type, and actual object.
*
* @param expected the expected type
* @param actual the actual object
* @since 2.1
*/
public IllegalClassException(Class expected, Object actual) {
super(
"Expected: "
+ safeGetClassName(expected)
+ ", actual: "
+ (actual == null ? "null" : actual.getClass().getName()));
}
/**
* Instantiates with the expected and actual types.
*
* @param expected the expected type
* @param actual the actual type
*/
public IllegalClassException(Class expected, Class actual) {
super(
"Expected: "
+ safeGetClassName(expected)
+ ", actual: "
+ safeGetClassName(actual));
}
/**
* Instantiates with the specified message.
*
* @param message the exception message
*/
public IllegalClassException(String message) {
super(message);
}
/**
* Returns the class name or null
if the class is
* null
.
*
* @param cls a Class
* @return the name of cls
, or null
if if cls
is null
.
*/
private static final String safeGetClassName(Class cls) {
return cls == null ? null : cls.getName();
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/IncompleteArgumentException.java 100644 0 0 6322 11513702446 27261 0 ustar 0 0 /*
* 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.lang;
import java.util.Arrays;
/**
* Thrown to indicate an incomplete argument to a method.
* This exception supplements the standard IllegalArgumentException
* by providing a more semantically rich description of the problem.
*
* IncompleteArgumentException
represents the case where a method takes
* in a parameter that has a number of properties, some of which have not been set.
* A case might be a search requirements bean that must have three properties set
* in order for the method to run, but only one is actually set.
* This exception would be used in place of
* IllegalArgumentException
, yet it still extends it.
*
*
* public void foo(PersonSearcher search) {
* if (search.getSurname() == null ||
* search.getForename() == null ||
* search.getSex() == null) {
* throw new IncompleteArgumentException("search");
* }
* // do something with the searcher
* }
*
*
* @author Matthew Hawthorne
* @since 2.0
* @version $Id: IncompleteArgumentException.java 437554 2006-08-28 06:21:41Z bayard $
*/
public class IncompleteArgumentException extends IllegalArgumentException {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 4954193403612068178L;
/**
* Instantiates with the specified description.
*
* @param argName a description of the incomplete argument
*/
public IncompleteArgumentException(String argName) {
super(argName + " is incomplete.");
}
/**
* Instantiates with the specified description.
*
* @param argName a description of the incomplete argument
* @param items an array describing the arguments missing
*/
public IncompleteArgumentException(String argName, String[] items) {
super(
argName
+ " is missing the following items: "
+ safeArrayToString(items));
}
/**
* Converts an array to a string without throwing an exception.
*
* @param array an array
* @return the array as a string
*/
private static final String safeArrayToString(Object[] array) {
return array == null ? null : Arrays.asList(array).toString();
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/IntHashMap.java 100644 0 0 27513 11513702446 23621 0 ustar 0 0 /*
* 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.
*/
/*
* Note: originally released under the GNU LGPL v2.1,
* but rereleased by the original author under the ASF license (above).
*/
package org.apache.commons.lang;
/**
* A hash map that uses primitive ints for the key rather than objects.
*
* Note that this class is for internal optimization purposes only, and may
* not be supported in future releases of Apache Commons Lang. Utilities of
* this sort may be included in future releases of Apache Commons Collections.
*
* @author Apache Software Foundation
* @author Justin Couch
* @author Alex Chaffee (alex@apache.org)
* @since 2.0
* @version $Revision: 905857 $
* @see java.util.HashMap
*/
class IntHashMap {
/**
* The hash table data.
*/
private transient Entry table[];
/**
* The total number of entries in the hash table.
*/
private transient int count;
/**
* The table is rehashed when its size exceeds this threshold. (The
* value of this field is (int)(capacity * loadFactor).)
*
* @serial
*/
private int threshold;
/**
* The load factor for the hashtable.
*
* @serial
*/
private final float loadFactor;
/**
* Innerclass that acts as a datastructure to create a new entry in the
* table.
*/
private static class Entry {
final int hash;
final int key; // TODO not read; seems to be always same as hash
Object value;
Entry next;
/**
* Create a new entry with the given values.
*
* @param hash The code used to hash the object with
* @param key The key used to enter this in the table
* @param value The value for this key
* @param next A reference to the next entry in the table
*/
protected Entry(int hash, int key, Object value, Entry next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
}
/**
* Constructs a new, empty hashtable with a default capacity and load
* factor, which is 20
and 0.75
respectively.
*/
public IntHashMap() {
this(20, 0.75f);
}
/**
* Constructs a new, empty hashtable with the specified initial capacity
* and default load factor, which is 0.75
.
*
* @param initialCapacity the initial capacity of the hashtable.
* @throws IllegalArgumentException if the initial capacity is less
* than zero.
*/
public IntHashMap(int initialCapacity) {
this(initialCapacity, 0.75f);
}
/**
* Constructs a new, empty hashtable with the specified initial
* capacity and the specified load factor.
*
* @param initialCapacity the initial capacity of the hashtable.
* @param loadFactor the load factor of the hashtable.
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive.
*/
public IntHashMap(int initialCapacity, float loadFactor) {
super();
if (initialCapacity < 0) {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
if (loadFactor <= 0) {
throw new IllegalArgumentException("Illegal Load: " + loadFactor);
}
if (initialCapacity == 0) {
initialCapacity = 1;
}
this.loadFactor = loadFactor;
table = new Entry[initialCapacity];
threshold = (int) (initialCapacity * loadFactor);
}
/**
* Returns the number of keys in this hashtable.
*
* @return the number of keys in this hashtable.
*/
public int size() {
return count;
}
/**
* Tests if this hashtable maps no keys to values.
*
* @return true
if this hashtable maps no keys to values;
* false
otherwise.
*/
public boolean isEmpty() {
return count == 0;
}
/**
* Tests if some key maps into the specified value in this hashtable.
* This operation is more expensive than the containsKey
* method.
*
* Note that this method is identical in functionality to containsValue,
* (which is part of the Map interface in the collections framework).
*
* @param value a value to search for.
* @return true
if and only if some key maps to the
* value
argument in this hashtable as
* determined by the equals method;
* false
otherwise.
* @throws NullPointerException if the value is null
.
* @see #containsKey(int)
* @see #containsValue(Object)
* @see java.util.Map
*/
public boolean contains(Object value) {
if (value == null) {
throw new NullPointerException();
}
Entry tab[] = table;
for (int i = tab.length; i-- > 0;) {
for (Entry e = tab[i]; e != null; e = e.next) {
if (e.value.equals(value)) {
return true;
}
}
}
return false;
}
/**
* Returns true
if this HashMap maps one or more keys
* to this value.
*
* Note that this method is identical in functionality to contains
* (which predates the Map interface).
*
* @param value value whose presence in this HashMap is to be tested.
* @return boolean true
if the value is contained
* @see java.util.Map
* @since JDK1.2
*/
public boolean containsValue(Object value) {
return contains(value);
}
/**
* Tests if the specified object is a key in this hashtable.
*
* @param key possible key.
* @return true
if and only if the specified object is a
* key in this hashtable, as determined by the equals
* method; false
otherwise.
* @see #contains(Object)
*/
public boolean containsKey(int key) {
Entry tab[] = table;
int hash = key;
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index]; e != null; e = e.next) {
if (e.hash == hash) {
return true;
}
}
return false;
}
/**
* Returns the value to which the specified key is mapped in this map.
*
* @param key a key in the hashtable.
* @return the value to which the key is mapped in this hashtable;
* null
if the key is not mapped to any value in
* this hashtable.
* @see #put(int, Object)
*/
public Object get(int key) {
Entry tab[] = table;
int hash = key;
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index]; e != null; e = e.next) {
if (e.hash == hash) {
return e.value;
}
}
return null;
}
/**
* Increases the capacity of and internally reorganizes this
* hashtable, in order to accommodate and access its entries more
* efficiently.
*
* This method is called automatically when the number of keys
* in the hashtable exceeds this hashtable's capacity and load
* factor.
*/
protected void rehash() {
int oldCapacity = table.length;
Entry oldMap[] = table;
int newCapacity = oldCapacity * 2 + 1;
Entry newMap[] = new Entry[newCapacity];
threshold = (int) (newCapacity * loadFactor);
table = newMap;
for (int i = oldCapacity; i-- > 0;) {
for (Entry old = oldMap[i]; old != null;) {
Entry e = old;
old = old.next;
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = newMap[index];
newMap[index] = e;
}
}
}
/**
* Maps the specified key
to the specified
* value
in this hashtable. The key cannot be
* null
.
*
* The value can be retrieved by calling the get
method
* with a key that is equal to the original key.
*
* @param key the hashtable key.
* @param value the value.
* @return the previous value of the specified key in this hashtable,
* or null
if it did not have one.
* @throws NullPointerException if the key is null
.
* @see #get(int)
*/
public Object put(int key, Object value) {
// Makes sure the key is not already in the hashtable.
Entry tab[] = table;
int hash = key;
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index]; e != null; e = e.next) {
if (e.hash == hash) {
Object old = e.value;
e.value = value;
return old;
}
}
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
index = (hash & 0x7FFFFFFF) % tab.length;
}
// Creates the new entry.
Entry e = new Entry(hash, key, value, tab[index]);
tab[index] = e;
count++;
return null;
}
/**
* Removes the key (and its corresponding value) from this
* hashtable.
*
* This method does nothing if the key is not present in the
* hashtable.
*
* @param key the key that needs to be removed.
* @return the value to which the key had been mapped in this hashtable,
* or null
if the key did not have a mapping.
*/
public Object remove(int key) {
Entry tab[] = table;
int hash = key;
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index], prev = null; e != null; prev = e, e = e.next) {
if (e.hash == hash) {
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
count--;
Object oldValue = e.value;
e.value = null;
return oldValue;
}
}
return null;
}
/**
* Clears this hashtable so that it contains no keys.
*/
public synchronized void clear() {
Entry tab[] = table;
for (int index = tab.length; --index >= 0;) {
tab[index] = null;
}
count = 0;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/LocaleUtils.java 100644 0 0 31303 11513702446 24035 0 ustar 0 0 /*
* 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.lang;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
/**
* Operations to assist when working with a {@link Locale}.
*
* This class tries to handle null
input gracefully.
* An exception will not be thrown for a null
input.
* Each method documents its behaviour in more detail.
*
* @author Apache Software Foundation
* @since 2.2
* @version $Id: LocaleUtils.java 911968 2010-02-19 20:26:21Z niallp $
*/
public class LocaleUtils {
/** Unmodifiable list of available locales. */
private static List cAvailableLocaleList; // lazily created by availableLocaleList()
/** Unmodifiable set of available locales. */
private static Set cAvailableLocaleSet; // lazily created by availableLocaleSet()
/** Unmodifiable map of language locales by country. */
private static final Map cLanguagesByCountry = Collections.synchronizedMap(new HashMap());
/** Unmodifiable map of country locales by language. */
private static final Map cCountriesByLanguage = Collections.synchronizedMap(new HashMap());
/**
* LocaleUtils
instances should NOT be constructed in standard programming.
* Instead, the class should be used as LocaleUtils.toLocale("en_GB");
.
*
* This constructor is public to permit tools that require a JavaBean instance
* to operate.
*/
public LocaleUtils() {
super();
}
//-----------------------------------------------------------------------
/**
* Converts a String to a Locale.
*
* This method takes the string format of a locale and creates the
* locale object from it.
*
*
* LocaleUtils.toLocale("en") = new Locale("en", "")
* LocaleUtils.toLocale("en_GB") = new Locale("en", "GB")
* LocaleUtils.toLocale("en_GB_xxx") = new Locale("en", "GB", "xxx") (#)
*
*
* (#) The behaviour of the JDK variant constructor changed between JDK1.3 and JDK1.4.
* In JDK1.3, the constructor upper cases the variant, in JDK1.4, it doesn't.
* Thus, the result from getVariant() may vary depending on your JDK.
*
* This method validates the input strictly.
* The language code must be lowercase.
* The country code must be uppercase.
* The separator must be an underscore.
* The length must be correct.
*
*
* @param str the locale String to convert, null returns null
* @return a Locale, null if null input
* @throws IllegalArgumentException if the string is an invalid format
*/
public static Locale toLocale(String str) {
if (str == null) {
return null;
}
int len = str.length();
if (len != 2 && len != 5 && len < 7) {
throw new IllegalArgumentException("Invalid locale format: " + str);
}
char ch0 = str.charAt(0);
char ch1 = str.charAt(1);
if (ch0 < 'a' || ch0 > 'z' || ch1 < 'a' || ch1 > 'z') {
throw new IllegalArgumentException("Invalid locale format: " + str);
}
if (len == 2) {
return new Locale(str, "");
} else {
if (str.charAt(2) != '_') {
throw new IllegalArgumentException("Invalid locale format: " + str);
}
char ch3 = str.charAt(3);
if (ch3 == '_') {
return new Locale(str.substring(0, 2), "", str.substring(4));
}
char ch4 = str.charAt(4);
if (ch3 < 'A' || ch3 > 'Z' || ch4 < 'A' || ch4 > 'Z') {
throw new IllegalArgumentException("Invalid locale format: " + str);
}
if (len == 5) {
return new Locale(str.substring(0, 2), str.substring(3, 5));
} else {
if (str.charAt(5) != '_') {
throw new IllegalArgumentException("Invalid locale format: " + str);
}
return new Locale(str.substring(0, 2), str.substring(3, 5), str.substring(6));
}
}
}
//-----------------------------------------------------------------------
/**
* Obtains the list of locales to search through when performing
* a locale search.
*
*
* localeLookupList(Locale("fr","CA","xxx"))
* = [Locale("fr","CA","xxx"), Locale("fr","CA"), Locale("fr")]
*
*
* @param locale the locale to start from
* @return the unmodifiable list of Locale objects, 0 being locale, never null
*/
public static List localeLookupList(Locale locale) {
return localeLookupList(locale, locale);
}
//-----------------------------------------------------------------------
/**
* Obtains the list of locales to search through when performing
* a locale search.
*
*
* localeLookupList(Locale("fr", "CA", "xxx"), Locale("en"))
* = [Locale("fr","CA","xxx"), Locale("fr","CA"), Locale("fr"), Locale("en"]
*
*
* The result list begins with the most specific locale, then the
* next more general and so on, finishing with the default locale.
* The list will never contain the same locale twice.
*
* @param locale the locale to start from, null returns empty list
* @param defaultLocale the default locale to use if no other is found
* @return the unmodifiable list of Locale objects, 0 being locale, never null
*/
public static List localeLookupList(Locale locale, Locale defaultLocale) {
List list = new ArrayList(4);
if (locale != null) {
list.add(locale);
if (locale.getVariant().length() > 0) {
list.add(new Locale(locale.getLanguage(), locale.getCountry()));
}
if (locale.getCountry().length() > 0) {
list.add(new Locale(locale.getLanguage(), ""));
}
if (list.contains(defaultLocale) == false) {
list.add(defaultLocale);
}
}
return Collections.unmodifiableList(list);
}
//-----------------------------------------------------------------------
/**
* Obtains an unmodifiable list of installed locales.
*
* This method is a wrapper around {@link Locale#getAvailableLocales()}.
* It is more efficient, as the JDK method must create a new array each
* time it is called.
*
* @return the unmodifiable list of available locales
*/
public static List availableLocaleList() {
if(cAvailableLocaleList == null) {
initAvailableLocaleList();
}
return cAvailableLocaleList;
}
/**
* Initializes the availableLocaleList. It is separate from availableLocaleList()
* to avoid the synchronized block affecting normal use, yet synchronized and
* lazy loading to avoid a static block affecting other methods in this class.
*/
private static synchronized void initAvailableLocaleList() {
if(cAvailableLocaleList == null) {
List list = Arrays.asList(Locale.getAvailableLocales());
cAvailableLocaleList = Collections.unmodifiableList(list);
}
}
//-----------------------------------------------------------------------
/**
* Obtains an unmodifiable set of installed locales.
*
* This method is a wrapper around {@link Locale#getAvailableLocales()}.
* It is more efficient, as the JDK method must create a new array each
* time it is called.
*
* @return the unmodifiable set of available locales
*/
public static Set availableLocaleSet() {
if(cAvailableLocaleSet == null) {
initAvailableLocaleSet();
}
return cAvailableLocaleSet;
}
/**
* Initializes the availableLocaleSet. It is separate from availableLocaleSet()
* to avoid the synchronized block affecting normal use, yet synchronized and
* lazy loading to avoid a static block affecting other methods in this class.
*/
private static synchronized void initAvailableLocaleSet() {
if(cAvailableLocaleSet == null) {
cAvailableLocaleSet = Collections.unmodifiableSet( new HashSet(availableLocaleList()) );
}
}
//-----------------------------------------------------------------------
/**
* Checks if the locale specified is in the list of available locales.
*
* @param locale the Locale object to check if it is available
* @return true if the locale is a known locale
*/
public static boolean isAvailableLocale(Locale locale) {
return availableLocaleList().contains(locale);
}
//-----------------------------------------------------------------------
/**
* Obtains the list of languages supported for a given country.
*
* This method takes a country code and searches to find the
* languages available for that country. Variant locales are removed.
*
* @param countryCode the 2 letter country code, null returns empty
* @return an unmodifiable List of Locale objects, never null
*/
public static List languagesByCountry(String countryCode) {
List langs = (List) cLanguagesByCountry.get(countryCode); //syncd
if (langs == null) {
if (countryCode != null) {
langs = new ArrayList();
List locales = availableLocaleList();
for (int i = 0; i < locales.size(); i++) {
Locale locale = (Locale) locales.get(i);
if (countryCode.equals(locale.getCountry()) &&
locale.getVariant().length() == 0) {
langs.add(locale);
}
}
langs = Collections.unmodifiableList(langs);
} else {
langs = Collections.EMPTY_LIST;
}
cLanguagesByCountry.put(countryCode, langs); //syncd
}
return langs;
}
//-----------------------------------------------------------------------
/**
* Obtains the list of countries supported for a given language.
*
* This method takes a language code and searches to find the
* countries available for that language. Variant locales are removed.
*
* @param languageCode the 2 letter language code, null returns empty
* @return an unmodifiable List of Locale objects, never null
*/
public static List countriesByLanguage(String languageCode) {
List countries = (List) cCountriesByLanguage.get(languageCode); //syncd
if (countries == null) {
if (languageCode != null) {
countries = new ArrayList();
List locales = availableLocaleList();
for (int i = 0; i < locales.size(); i++) {
Locale locale = (Locale) locales.get(i);
if (languageCode.equals(locale.getLanguage()) &&
locale.getCountry().length() != 0 &&
locale.getVariant().length() == 0) {
countries.add(locale);
}
}
countries = Collections.unmodifiableList(countries);
} else {
countries = Collections.EMPTY_LIST;
}
cCountriesByLanguage.put(languageCode, countries); //syncd
}
return countries;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/math/DoubleRange.java 100644 0 0 33516 11513702442 24741 0 ustar 0 0 /*
* 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.lang.math;
import java.io.Serializable;
import org.apache.commons.lang.text.StrBuilder;
/**
* DoubleRange
represents an inclusive range of double
s.
*
* @author Apache Software Foundation
* @since 2.0
* @version $Id: DoubleRange.java 1057072 2011-01-10 01:55:57Z niallp $
*/
public final class DoubleRange extends Range implements Serializable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 71849363892740L;
/**
* The minimum number in this range (inclusive).
*/
private final double min;
/**
* The maximum number in this range (inclusive).
*/
private final double max;
/**
* Cached output minObject (class is immutable).
*/
private transient Double minObject = null;
/**
* Cached output maxObject (class is immutable).
*/
private transient Double maxObject = null;
/**
* Cached output hashCode (class is immutable).
*/
private transient int hashCode = 0;
/**
* Cached output toString (class is immutable).
*/
private transient String toString = null;
/**
* Constructs a new DoubleRange
using the specified
* number as both the minimum and maximum in this range.
*
* @param number the number to use for this range
* @throws IllegalArgumentException if the number is NaN
*/
public DoubleRange(double number) {
super();
if (Double.isNaN(number)) {
throw new IllegalArgumentException("The number must not be NaN");
}
this.min = number;
this.max = number;
}
/**
* Constructs a new DoubleRange
using the specified
* number as both the minimum and maximum in this range.
*
* @param number the number to use for this range, must not
* be null
* @throws IllegalArgumentException if the number is null
* @throws IllegalArgumentException if the number is NaN
*/
public DoubleRange(Number number) {
super();
if (number == null) {
throw new IllegalArgumentException("The number must not be null");
}
this.min = number.doubleValue();
this.max = number.doubleValue();
if (Double.isNaN(min) || Double.isNaN(max)) {
throw new IllegalArgumentException("The number must not be NaN");
}
if (number instanceof Double) {
this.minObject = (Double) number;
this.maxObject = (Double) number;
}
}
/**
* Constructs a new DoubleRange
with the specified
* minimum and maximum numbers (both inclusive).
*
* The arguments may be passed in the order (min,max) or (max,min). The
* getMinimum and getMaximum methods will return the correct values.
*
* @param number1 first number that defines the edge of the range, inclusive
* @param number2 second number that defines the edge of the range, inclusive
* @throws IllegalArgumentException if either number is NaN
*/
public DoubleRange(double number1, double number2) {
super();
if (Double.isNaN(number1) || Double.isNaN(number2)) {
throw new IllegalArgumentException("The numbers must not be NaN");
}
if (number2 < number1) {
this.min = number2;
this.max = number1;
} else {
this.min = number1;
this.max = number2;
}
}
/**
* Constructs a new DoubleRange
with the specified
* minimum and maximum numbers (both inclusive).
*
* The arguments may be passed in the order (min,max) or (max,min). The
* getMinimum and getMaximum methods will return the correct values.
*
* @param number1 first number that defines the edge of the range, inclusive
* @param number2 second number that defines the edge of the range, inclusive
* @throws IllegalArgumentException if either number is null
* @throws IllegalArgumentException if either number is NaN
*/
public DoubleRange(Number number1, Number number2) {
super();
if (number1 == null || number2 == null) {
throw new IllegalArgumentException("The numbers must not be null");
}
double number1val = number1.doubleValue();
double number2val = number2.doubleValue();
if (Double.isNaN(number1val) || Double.isNaN(number2val)) {
throw new IllegalArgumentException("The numbers must not be NaN");
}
if (number2val < number1val) {
this.min = number2val;
this.max = number1val;
if (number2 instanceof Double) {
this.minObject = (Double) number2;
}
if (number1 instanceof Double) {
this.maxObject = (Double) number1;
}
} else {
this.min = number1val;
this.max = number2val;
if (number1 instanceof Double) {
this.minObject = (Double) number1;
}
if (number2 instanceof Double) {
this.maxObject = (Double) number2;
}
}
}
// Accessors
//--------------------------------------------------------------------
/**
* Returns the minimum number in this range.
*
* @return the minimum number in this range
*/
public Number getMinimumNumber() {
if (minObject == null) {
minObject = new Double(min);
}
return minObject;
}
/**
* Gets the minimum number in this range as a long
.
*
* This conversion can lose information for large values or decimals.
*
* @return the minimum number in this range
*/
public long getMinimumLong() {
return (long) min;
}
/**
* Gets the minimum number in this range as a int
.
*
* This conversion can lose information for large values or decimals.
*
* @return the minimum number in this range
*/
public int getMinimumInteger() {
return (int) min;
}
/**
* Gets the minimum number in this range as a double
.
*
* @return the minimum number in this range
*/
public double getMinimumDouble() {
return min;
}
/**
* Gets the minimum number in this range as a float
.
*
* This conversion can lose information for large values.
*
* @return the minimum number in this range
*/
public float getMinimumFloat() {
return (float) min;
}
/**
* Returns the maximum number in this range.
*
* @return the maximum number in this range
*/
public Number getMaximumNumber() {
if (maxObject == null) {
maxObject = new Double(max);
}
return maxObject;
}
/**
* Gets the maximum number in this range as a long
.
*
* This conversion can lose information for large values or decimals.
*
* @return the maximum number in this range
*/
public long getMaximumLong() {
return (long) max;
}
/**
* Gets the maximum number in this range as a int
.
*
* This conversion can lose information for large values or decimals.
*
* @return the maximum number in this range
*/
public int getMaximumInteger() {
return (int) max;
}
/**
* Gets the maximum number in this range as a double
.
*
* @return the maximum number in this range
*/
public double getMaximumDouble() {
return max;
}
/**
* Gets the maximum number in this range as a float
.
*
* This conversion can lose information for large values.
*
* @return the maximum number in this range
*/
public float getMaximumFloat() {
return (float) max;
}
// Tests
//--------------------------------------------------------------------
/**
* Tests whether the specified number
occurs within
* this range using double
comparison.
*
* null
is handled and returns false
.
*
* @param number the number to test, may be null
* @return true
if the specified number occurs within this range
*/
public boolean containsNumber(Number number) {
if (number == null) {
return false;
}
return containsDouble(number.doubleValue());
}
/**
* Tests whether the specified double
occurs within
* this range using double
comparison.
*
* This implementation overrides the superclass for performance as it is
* the most common case.
*
* @param value the double to test
* @return true
if the specified number occurs within this
* range by double
comparison
*/
public boolean containsDouble(double value) {
return value >= min && value <= max;
}
// Range tests
//--------------------------------------------------------------------
/**
* Tests whether the specified range occurs entirely within this range
* using double
comparison.
*
* null
is handled and returns false
.
*
* @param range the range to test, may be null
* @return true
if the specified range occurs entirely within this range
* @throws IllegalArgumentException if the range is not of this type
*/
public boolean containsRange(Range range) {
if (range == null) {
return false;
}
return containsDouble(range.getMinimumDouble())
&& containsDouble(range.getMaximumDouble());
}
/**
* Tests whether the specified range overlaps with this range
* using double
comparison.
*
* null
is handled and returns false
.
*
* @param range the range to test, may be null
* @return true
if the specified range overlaps with this range
*/
public boolean overlapsRange(Range range) {
if (range == null) {
return false;
}
return range.containsDouble(min)
|| range.containsDouble(max)
|| containsDouble(range.getMinimumDouble());
}
// Basics
//--------------------------------------------------------------------
/**
* Compares this range to another object to test if they are equal.
.
*
* To be equal, the class, minimum and maximum must be equal.
*
* @param obj the reference object with which to compare
* @return true
if this object is equal
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof DoubleRange == false) {
return false;
}
DoubleRange range = (DoubleRange) obj;
return (Double.doubleToLongBits(min) == Double.doubleToLongBits(range.min) &&
Double.doubleToLongBits(max) == Double.doubleToLongBits(range.max));
}
/**
* Gets a hashCode for the range.
*
* @return a hash code value for this object
*/
public int hashCode() {
if (hashCode == 0) {
hashCode = 17;
hashCode = 37 * hashCode + getClass().hashCode();
long lng = Double.doubleToLongBits(min);
hashCode = 37 * hashCode + ((int) (lng ^ (lng >> 32)));
lng = Double.doubleToLongBits(max);
hashCode = 37 * hashCode + ((int) (lng ^ (lng >> 32)));
}
return hashCode;
}
/**
* Gets the range as a String
.
*
* The format of the String is 'Range[min,max]'.
*
* @return the String
representation of this range
*/
public String toString() {
if (toString == null) {
StrBuilder buf = new StrBuilder(32);
buf.append("Range[");
buf.append(min);
buf.append(',');
buf.append(max);
buf.append(']');
toString = buf.toString();
}
return toString;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/math/FloatRange.java 100644 0 0 32700 11513702442 24566 0 ustar 0 0 /*
* 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.lang.math;
import java.io.Serializable;
/**
* FloatRange
represents an inclusive range of float
s.
*
* @author Apache Software Foundation
* @since 2.0
* @version $Id: FloatRange.java 905636 2010-02-02 14:03:32Z niallp $
*/
public final class FloatRange extends Range implements Serializable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 71849363892750L;
/**
* The minimum number in this range (inclusive).
*/
private final float min;
/**
* The maximum number in this range (inclusive).
*/
private final float max;
/**
* Cached output minObject (class is immutable).
*/
private transient Float minObject = null;
/**
* Cached output maxObject (class is immutable).
*/
private transient Float maxObject = null;
/**
* Cached output hashCode (class is immutable).
*/
private transient int hashCode = 0;
/**
* Cached output toString (class is immutable).
*/
private transient String toString = null;
/**
* Constructs a new FloatRange
using the specified
* number as both the minimum and maximum in this range.
*
* @param number the number to use for this range
* @throws IllegalArgumentException if the number is NaN
*/
public FloatRange(float number) {
super();
if (Float.isNaN(number)) {
throw new IllegalArgumentException("The number must not be NaN");
}
this.min = number;
this.max = number;
}
/**
* Constructs a new FloatRange
using the specified
* number as both the minimum and maximum in this range.
*
* @param number the number to use for this range, must not
* be null
* @throws IllegalArgumentException if the number is null
* @throws IllegalArgumentException if the number is NaN
*/
public FloatRange(Number number) {
super();
if (number == null) {
throw new IllegalArgumentException("The number must not be null");
}
this.min = number.floatValue();
this.max = number.floatValue();
if (Float.isNaN(min) || Float.isNaN(max)) {
throw new IllegalArgumentException("The number must not be NaN");
}
if (number instanceof Float) {
this.minObject = (Float) number;
this.maxObject = (Float) number;
}
}
/**
* Constructs a new FloatRange
with the specified
* minimum and maximum numbers (both inclusive).
*
* The arguments may be passed in the order (min,max) or (max,min). The
* getMinimum and getMaximum methods will return the correct values.
*
* @param number1 first number that defines the edge of the range, inclusive
* @param number2 second number that defines the edge of the range, inclusive
* @throws IllegalArgumentException if either number is NaN
*/
public FloatRange(float number1, float number2) {
super();
if (Float.isNaN(number1) || Float.isNaN(number2)) {
throw new IllegalArgumentException("The numbers must not be NaN");
}
if (number2 < number1) {
this.min = number2;
this.max = number1;
} else {
this.min = number1;
this.max = number2;
}
}
/**
* Constructs a new FloatRange
with the specified
* minimum and maximum numbers (both inclusive).
*
* The arguments may be passed in the order (min,max) or (max,min). The
* getMinimum and getMaximum methods will return the correct values.
*
* @param number1 first number that defines the edge of the range, inclusive
* @param number2 second number that defines the edge of the range, inclusive
* @throws IllegalArgumentException if either number is null
* @throws IllegalArgumentException if either number is NaN
*/
public FloatRange(Number number1, Number number2) {
super();
if (number1 == null || number2 == null) {
throw new IllegalArgumentException("The numbers must not be null");
}
float number1val = number1.floatValue();
float number2val = number2.floatValue();
if (Float.isNaN(number1val) || Float.isNaN(number2val)) {
throw new IllegalArgumentException("The numbers must not be NaN");
}
if (number2val < number1val) {
this.min = number2val;
this.max = number1val;
if (number2 instanceof Float) {
this.minObject = (Float) number2;
}
if (number1 instanceof Float) {
this.maxObject = (Float) number1;
}
} else {
this.min = number1val;
this.max = number2val;
if (number1 instanceof Float) {
this.minObject = (Float) number1;
}
if (number2 instanceof Float) {
this.maxObject = (Float) number2;
}
}
}
// Accessors
//--------------------------------------------------------------------
/**
* Returns the minimum number in this range.
*
* @return the minimum number in this range
*/
public Number getMinimumNumber() {
if (minObject == null) {
minObject = new Float(min);
}
return minObject;
}
/**
* Gets the minimum number in this range as a long
.
*
* This conversion can lose information for large values or decimals.
*
* @return the minimum number in this range
*/
public long getMinimumLong() {
return (long) min;
}
/**
* Gets the minimum number in this range as a int
.
*
* This conversion can lose information for large values or decimals.
*
* @return the minimum number in this range
*/
public int getMinimumInteger() {
return (int) min;
}
/**
* Gets the minimum number in this range as a double
.
*
* @return the minimum number in this range
*/
public double getMinimumDouble() {
return min;
}
/**
* Gets the minimum number in this range as a float
.
*
* @return the minimum number in this range
*/
public float getMinimumFloat() {
return min;
}
/**
* Returns the maximum number in this range.
*
* @return the maximum number in this range
*/
public Number getMaximumNumber() {
if (maxObject == null) {
maxObject = new Float(max);
}
return maxObject;
}
/**
* Gets the maximum number in this range as a long
.
*
* This conversion can lose information for large values or decimals.
*
* @return the maximum number in this range
*/
public long getMaximumLong() {
return (long) max;
}
/**
* Gets the maximum number in this range as a int
.
*
* This conversion can lose information for large values or decimals.
*
* @return the maximum number in this range
*/
public int getMaximumInteger() {
return (int) max;
}
/**
* Gets the maximum number in this range as a double
.
*
* @return the maximum number in this range
*/
public double getMaximumDouble() {
return max;
}
/**
* Gets the maximum number in this range as a float
.
*
* @return the maximum number in this range
*/
public float getMaximumFloat() {
return max;
}
// Tests
//--------------------------------------------------------------------
/**
* Tests whether the specified number
occurs within
* this range using float
comparison.
*
* null
is handled and returns false
.
*
* @param number the number to test, may be null
* @return true
if the specified number occurs within this range
*/
public boolean containsNumber(Number number) {
if (number == null) {
return false;
}
return containsFloat(number.floatValue());
}
/**
* Tests whether the specified float
occurs within
* this range using float
comparison.
*
* This implementation overrides the superclass for performance as it is
* the most common case.
*
* @param value the float to test
* @return true
if the specified number occurs within this
* range by float
comparison
*/
public boolean containsFloat(float value) {
return value >= min && value <= max;
}
// Range tests
//--------------------------------------------------------------------
/**
* Tests whether the specified range occurs entirely within this range
* using float
comparison.
*
* null
is handled and returns false
.
*
* @param range the range to test, may be null
* @return true
if the specified range occurs entirely within this range
* @throws IllegalArgumentException if the range is not of this type
*/
public boolean containsRange(Range range) {
if (range == null) {
return false;
}
return containsFloat(range.getMinimumFloat()) &&
containsFloat(range.getMaximumFloat());
}
/**
* Tests whether the specified range overlaps with this range
* using float
comparison.
*
* null
is handled and returns false
.
*
* @param range the range to test, may be null
* @return true
if the specified range overlaps with this range
*/
public boolean overlapsRange(Range range) {
if (range == null) {
return false;
}
return range.containsFloat(min) ||
range.containsFloat(max) ||
containsFloat(range.getMinimumFloat());
}
// Basics
//--------------------------------------------------------------------
/**
* Compares this range to another object to test if they are equal.
.
*
* To be equal, the class, minimum and maximum must be equal.
*
* @param obj the reference object with which to compare
* @return true
if this object is equal
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof FloatRange == false) {
return false;
}
FloatRange range = (FloatRange) obj;
return (Float.floatToIntBits(min) == Float.floatToIntBits(range.min) &&
Float.floatToIntBits(max) == Float.floatToIntBits(range.max));
}
/**
* Gets a hashCode for the range.
*
* @return a hash code value for this object
*/
public int hashCode() {
if (hashCode == 0) {
hashCode = 17;
hashCode = 37 * hashCode + getClass().hashCode();
hashCode = 37 * hashCode + Float.floatToIntBits(min);
hashCode = 37 * hashCode + Float.floatToIntBits(max);
}
return hashCode;
}
/**
* Gets the range as a String
.
*
* The format of the String is 'Range[min,max]'.
*
* @return the String
representation of this range
*/
public String toString() {
if (toString == null) {
StringBuffer buf = new StringBuffer(32);
buf.append("Range[");
buf.append(min);
buf.append(',');
buf.append(max);
buf.append(']');
toString = buf.toString();
}
return toString;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/math/Fraction.java 100644 0 0 105707 11513702442 24341 0 ustar 0 0 /*
* 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.lang.math;
import java.math.BigInteger;
import org.apache.commons.lang.text.StrBuilder;
/**
* Fraction
is a Number
implementation that
* stores fractions accurately.
*
* This class is immutable, and interoperable with most methods that accept
* a Number
.
*
* @author Apache Software Foundation
* @author Travis Reeder
* @author Tim O'Brien
* @author Pete Gieser
* @author C. Scott Ananian
* @since 2.0
* @version $Id: Fraction.java 1057072 2011-01-10 01:55:57Z niallp $
*/
public final class Fraction extends Number implements Comparable {
/**
* Required for serialization support. Lang version 2.0.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 65382027393090L;
/**
* Fraction
representation of 0.
*/
public static final Fraction ZERO = new Fraction(0, 1);
/**
* Fraction
representation of 1.
*/
public static final Fraction ONE = new Fraction(1, 1);
/**
* Fraction
representation of 1/2.
*/
public static final Fraction ONE_HALF = new Fraction(1, 2);
/**
* Fraction
representation of 1/3.
*/
public static final Fraction ONE_THIRD = new Fraction(1, 3);
/**
* Fraction
representation of 2/3.
*/
public static final Fraction TWO_THIRDS = new Fraction(2, 3);
/**
* Fraction
representation of 1/4.
*/
public static final Fraction ONE_QUARTER = new Fraction(1, 4);
/**
* Fraction
representation of 2/4.
*/
public static final Fraction TWO_QUARTERS = new Fraction(2, 4);
/**
* Fraction
representation of 3/4.
*/
public static final Fraction THREE_QUARTERS = new Fraction(3, 4);
/**
* Fraction
representation of 1/5.
*/
public static final Fraction ONE_FIFTH = new Fraction(1, 5);
/**
* Fraction
representation of 2/5.
*/
public static final Fraction TWO_FIFTHS = new Fraction(2, 5);
/**
* Fraction
representation of 3/5.
*/
public static final Fraction THREE_FIFTHS = new Fraction(3, 5);
/**
* Fraction
representation of 4/5.
*/
public static final Fraction FOUR_FIFTHS = new Fraction(4, 5);
/**
* The numerator number part of the fraction (the three in three sevenths).
*/
private final int numerator;
/**
* The denominator number part of the fraction (the seven in three sevenths).
*/
private final int denominator;
/**
* Cached output hashCode (class is immutable).
*/
private transient int hashCode = 0;
/**
* Cached output toString (class is immutable).
*/
private transient String toString = null;
/**
* Cached output toProperString (class is immutable).
*/
private transient String toProperString = null;
/**
* Constructs a Fraction
instance with the 2 parts
* of a fraction Y/Z.
*
* @param numerator the numerator, for example the three in 'three sevenths'
* @param denominator the denominator, for example the seven in 'three sevenths'
*/
private Fraction(int numerator, int denominator) {
super();
this.numerator = numerator;
this.denominator = denominator;
}
/**
* Creates a Fraction
instance with the 2 parts
* of a fraction Y/Z.
*
* Any negative signs are resolved to be on the numerator.
*
* @param numerator the numerator, for example the three in 'three sevenths'
* @param denominator the denominator, for example the seven in 'three sevenths'
* @return a new fraction instance
* @throws ArithmeticException if the denomiator is zero
*/
public static Fraction getFraction(int numerator, int denominator) {
if (denominator == 0) {
throw new ArithmeticException("The denominator must not be zero");
}
if (denominator < 0) {
if (numerator==Integer.MIN_VALUE ||
denominator==Integer.MIN_VALUE) {
throw new ArithmeticException("overflow: can't negate");
}
numerator = -numerator;
denominator = -denominator;
}
return new Fraction(numerator, denominator);
}
/**
* Creates a Fraction
instance with the 3 parts
* of a fraction X Y/Z.
*
* The negative sign must be passed in on the whole number part.
*
* @param whole the whole number, for example the one in 'one and three sevenths'
* @param numerator the numerator, for example the three in 'one and three sevenths'
* @param denominator the denominator, for example the seven in 'one and three sevenths'
* @return a new fraction instance
* @throws ArithmeticException if the denomiator is zero
* @throws ArithmeticException if the denominator is negative
* @throws ArithmeticException if the numerator is negative
* @throws ArithmeticException if the resulting numerator exceeds
* Integer.MAX_VALUE
*/
public static Fraction getFraction(int whole, int numerator, int denominator) {
if (denominator == 0) {
throw new ArithmeticException("The denominator must not be zero");
}
if (denominator < 0) {
throw new ArithmeticException("The denominator must not be negative");
}
if (numerator < 0) {
throw new ArithmeticException("The numerator must not be negative");
}
long numeratorValue;
if (whole < 0) {
numeratorValue = whole * (long)denominator - numerator;
} else {
numeratorValue = whole * (long)denominator + numerator;
}
if (numeratorValue < Integer.MIN_VALUE ||
numeratorValue > Integer.MAX_VALUE) {
throw new ArithmeticException("Numerator too large to represent as an Integer.");
}
return new Fraction((int) numeratorValue, denominator);
}
/**
* Creates a reduced Fraction
instance with the 2 parts
* of a fraction Y/Z.
*
* For example, if the input parameters represent 2/4, then the created
* fraction will be 1/2.
*
* Any negative signs are resolved to be on the numerator.
*
* @param numerator the numerator, for example the three in 'three sevenths'
* @param denominator the denominator, for example the seven in 'three sevenths'
* @return a new fraction instance, with the numerator and denominator reduced
* @throws ArithmeticException if the denominator is zero
*/
public static Fraction getReducedFraction(int numerator, int denominator) {
if (denominator == 0) {
throw new ArithmeticException("The denominator must not be zero");
}
if (numerator==0) {
return ZERO; // normalize zero.
}
// allow 2^k/-2^31 as a valid fraction (where k>0)
if (denominator==Integer.MIN_VALUE && (numerator&1)==0) {
numerator/=2; denominator/=2;
}
if (denominator < 0) {
if (numerator==Integer.MIN_VALUE ||
denominator==Integer.MIN_VALUE) {
throw new ArithmeticException("overflow: can't negate");
}
numerator = -numerator;
denominator = -denominator;
}
// simplify fraction.
int gcd = greatestCommonDivisor(numerator, denominator);
numerator /= gcd;
denominator /= gcd;
return new Fraction(numerator, denominator);
}
/**
* Creates a Fraction
instance from a double
value.
*
* This method uses the
* continued fraction algorithm, computing a maximum of
* 25 convergents and bounding the denominator by 10,000.
*
* @param value the double value to convert
* @return a new fraction instance that is close to the value
* @throws ArithmeticException if |value| > Integer.MAX_VALUE
* or value = NaN
* @throws ArithmeticException if the calculated denominator is zero
* @throws ArithmeticException if the the algorithm does not converge
*/
public static Fraction getFraction(double value) {
int sign = (value < 0 ? -1 : 1);
value = Math.abs(value);
if (value > Integer.MAX_VALUE || Double.isNaN(value)) {
throw new ArithmeticException
("The value must not be greater than Integer.MAX_VALUE or NaN");
}
int wholeNumber = (int) value;
value -= wholeNumber;
int numer0 = 0; // the pre-previous
int denom0 = 1; // the pre-previous
int numer1 = 1; // the previous
int denom1 = 0; // the previous
int numer2 = 0; // the current, setup in calculation
int denom2 = 0; // the current, setup in calculation
int a1 = (int) value;
int a2 = 0;
double x1 = 1;
double x2 = 0;
double y1 = value - a1;
double y2 = 0;
double delta1, delta2 = Double.MAX_VALUE;
double fraction;
int i = 1;
// System.out.println("---");
do {
delta1 = delta2;
a2 = (int) (x1 / y1);
x2 = y1;
y2 = x1 - a2 * y1;
numer2 = a1 * numer1 + numer0;
denom2 = a1 * denom1 + denom0;
fraction = (double) numer2 / (double) denom2;
delta2 = Math.abs(value - fraction);
// System.out.println(numer2 + " " + denom2 + " " + fraction + " " + delta2 + " " + y1);
a1 = a2;
x1 = x2;
y1 = y2;
numer0 = numer1;
denom0 = denom1;
numer1 = numer2;
denom1 = denom2;
i++;
// System.out.println(">>" + delta1 +" "+ delta2+" "+(delta1 > delta2)+" "+i+" "+denom2);
} while ((delta1 > delta2) && (denom2 <= 10000) && (denom2 > 0) && (i < 25));
if (i == 25) {
throw new ArithmeticException("Unable to convert double to fraction");
}
return getReducedFraction((numer0 + wholeNumber * denom0) * sign, denom0);
}
/**
* Creates a Fraction from a String
.
*
* The formats accepted are:
*
*
* double
String containing a dot
* - 'X Y/Z'
* - 'Y/Z'
* - 'X' (a simple whole number)
*
* and a .
*
* @param str the string to parse, must not be null
* @return the new Fraction
instance
* @throws IllegalArgumentException if the string is null
* @throws NumberFormatException if the number format is invalid
*/
public static Fraction getFraction(String str) {
if (str == null) {
throw new IllegalArgumentException("The string must not be null");
}
// parse double format
int pos = str.indexOf('.');
if (pos >= 0) {
return getFraction(Double.parseDouble(str));
}
// parse X Y/Z format
pos = str.indexOf(' ');
if (pos > 0) {
int whole = Integer.parseInt(str.substring(0, pos));
str = str.substring(pos + 1);
pos = str.indexOf('/');
if (pos < 0) {
throw new NumberFormatException("The fraction could not be parsed as the format X Y/Z");
} else {
int numer = Integer.parseInt(str.substring(0, pos));
int denom = Integer.parseInt(str.substring(pos + 1));
return getFraction(whole, numer, denom);
}
}
// parse Y/Z format
pos = str.indexOf('/');
if (pos < 0) {
// simple whole number
return getFraction(Integer.parseInt(str), 1);
} else {
int numer = Integer.parseInt(str.substring(0, pos));
int denom = Integer.parseInt(str.substring(pos + 1));
return getFraction(numer, denom);
}
}
// Accessors
//-------------------------------------------------------------------
/**
* Gets the numerator part of the fraction.
*
* This method may return a value greater than the denominator, an
* improper fraction, such as the seven in 7/4.
*
* @return the numerator fraction part
*/
public int getNumerator() {
return numerator;
}
/**
* Gets the denominator part of the fraction.
*
* @return the denominator fraction part
*/
public int getDenominator() {
return denominator;
}
/**
* Gets the proper numerator, always positive.
*
* An improper fraction 7/4 can be resolved into a proper one, 1 3/4.
* This method returns the 3 from the proper fraction.
*
* If the fraction is negative such as -7/4, it can be resolved into
* -1 3/4, so this method returns the positive proper numerator, 3.
*
* @return the numerator fraction part of a proper fraction, always positive
*/
public int getProperNumerator() {
return Math.abs(numerator % denominator);
}
/**
* Gets the proper whole part of the fraction.
*
* An improper fraction 7/4 can be resolved into a proper one, 1 3/4.
* This method returns the 1 from the proper fraction.
*
* If the fraction is negative such as -7/4, it can be resolved into
* -1 3/4, so this method returns the positive whole part -1.
*
* @return the whole fraction part of a proper fraction, that includes the sign
*/
public int getProperWhole() {
return numerator / denominator;
}
// Number methods
//-------------------------------------------------------------------
/**
* Gets the fraction as an int
. This returns the whole number
* part of the fraction.
*
* @return the whole number fraction part
*/
public int intValue() {
return numerator / denominator;
}
/**
* Gets the fraction as a long
. This returns the whole number
* part of the fraction.
*
* @return the whole number fraction part
*/
public long longValue() {
return (long) numerator / denominator;
}
/**
* Gets the fraction as a float
. This calculates the fraction
* as the numerator divided by denominator.
*
* @return the fraction as a float
*/
public float floatValue() {
return ((float) numerator) / ((float) denominator);
}
/**
* Gets the fraction as a double
. This calculates the fraction
* as the numerator divided by denominator.
*
* @return the fraction as a double
*/
public double doubleValue() {
return ((double) numerator) / ((double) denominator);
}
// Calculations
//-------------------------------------------------------------------
/**
* Reduce the fraction to the smallest values for the numerator and
* denominator, returning the result.
*
* For example, if this fraction represents 2/4, then the result
* will be 1/2.
*
* @return a new reduced fraction instance, or this if no simplification possible
*/
public Fraction reduce() {
if (numerator == 0) {
return equals(ZERO) ? this : ZERO;
}
int gcd = greatestCommonDivisor(Math.abs(numerator), denominator);
if (gcd == 1) {
return this;
}
return Fraction.getFraction(numerator / gcd, denominator / gcd);
}
/**
* Gets a fraction that is the inverse (1/fraction) of this one.
*
* The returned fraction is not reduced.
*
* @return a new fraction instance with the numerator and denominator
* inverted.
* @throws ArithmeticException if the fraction represents zero.
*/
public Fraction invert() {
if (numerator == 0) {
throw new ArithmeticException("Unable to invert zero.");
}
if (numerator==Integer.MIN_VALUE) {
throw new ArithmeticException("overflow: can't negate numerator");
}
if (numerator<0) {
return new Fraction(-denominator, -numerator);
} else {
return new Fraction(denominator, numerator);
}
}
/**
* Gets a fraction that is the negative (-fraction) of this one.
*
* The returned fraction is not reduced.
*
* @return a new fraction instance with the opposite signed numerator
*/
public Fraction negate() {
// the positive range is one smaller than the negative range of an int.
if (numerator==Integer.MIN_VALUE) {
throw new ArithmeticException("overflow: too large to negate");
}
return new Fraction(-numerator, denominator);
}
/**
* Gets a fraction that is the positive equivalent of this one.
* More precisely: (fraction >= 0 ? this : -fraction)
*
* The returned fraction is not reduced.
*
* @return this
if it is positive, or a new positive fraction
* instance with the opposite signed numerator
*/
public Fraction abs() {
if (numerator >= 0) {
return this;
}
return negate();
}
/**
* Gets a fraction that is raised to the passed in power.
*
* The returned fraction is in reduced form.
*
* @param power the power to raise the fraction to
* @return this
if the power is one, ONE
if the power
* is zero (even if the fraction equals ZERO) or a new fraction instance
* raised to the appropriate power
* @throws ArithmeticException if the resulting numerator or denominator exceeds
* Integer.MAX_VALUE
*/
public Fraction pow(int power) {
if (power == 1) {
return this;
} else if (power == 0) {
return ONE;
} else if (power < 0) {
if (power==Integer.MIN_VALUE) { // MIN_VALUE can't be negated.
return this.invert().pow(2).pow(-(power/2));
}
return this.invert().pow(-power);
} else {
Fraction f = this.multiplyBy(this);
if ((power % 2) == 0) { // if even...
return f.pow(power/2);
} else { // if odd...
return f.pow(power/2).multiplyBy(this);
}
}
}
/**
* Gets the greatest common divisor of the absolute value of
* two numbers, using the "binary gcd" method which avoids
* division and modulo operations. See Knuth 4.5.2 algorithm B.
* This algorithm is due to Josef Stein (1961).
*
* @param u a non-zero number
* @param v a non-zero number
* @return the greatest common divisor, never zero
*/
private static int greatestCommonDivisor(int u, int v) {
//if either op. is abs 0 or 1, return 1:
if (Math.abs(u) <= 1 || Math.abs(v) <= 1) {
return 1;
}
// keep u and v negative, as negative integers range down to
// -2^31, while positive numbers can only be as large as 2^31-1
// (i.e. we can't necessarily negate a negative number without
// overflow)
if (u>0) { u=-u; } // make u negative
if (v>0) { v=-v; } // make v negative
// B1. [Find power of 2]
int k=0;
while ((u&1)==0 && (v&1)==0 && k<31) { // while u and v are both even...
u/=2; v/=2; k++; // cast out twos.
}
if (k==31) {
throw new ArithmeticException("overflow: gcd is 2^31");
}
// B2. Initialize: u and v have been divided by 2^k and at least
// one is odd.
int t = ((u&1)==1) ? v : -(u/2)/*B3*/;
// t negative: u was odd, v may be even (t replaces v)
// t positive: u was even, v is odd (t replaces u)
do {
/* assert u<0 && v<0; */
// B4/B3: cast out twos from t.
while ((t&1)==0) { // while t is even..
t/=2; // cast out twos
}
// B5 [reset max(u,v)]
if (t>0) {
u = -t;
} else {
v = t;
}
// B6/B3. at this point both u and v should be odd.
t = (v - u)/2;
// |u| larger: t positive (replace u)
// |v| larger: t negative (replace v)
} while (t!=0);
return -u*(1<x*y
* @throws ArithmeticException if the result can not be represented as
* an int
*/
private static int mulAndCheck(int x, int y) {
long m = ((long)x)*((long)y);
if (m < Integer.MIN_VALUE ||
m > Integer.MAX_VALUE) {
throw new ArithmeticException("overflow: mul");
}
return (int)m;
}
/**
* Multiply two non-negative integers, checking for overflow.
*
* @param x a non-negative factor
* @param y a non-negative factor
* @return the product x*y
* @throws ArithmeticException if the result can not be represented as
* an int
*/
private static int mulPosAndCheck(int x, int y) {
/* assert x>=0 && y>=0; */
long m = ((long)x)*((long)y);
if (m > Integer.MAX_VALUE) {
throw new ArithmeticException("overflow: mulPos");
}
return (int)m;
}
/**
* Add two integers, checking for overflow.
*
* @param x an addend
* @param y an addend
* @return the sum x+y
* @throws ArithmeticException if the result can not be represented as
* an int
*/
private static int addAndCheck(int x, int y) {
long s = (long)x+(long)y;
if (s < Integer.MIN_VALUE ||
s > Integer.MAX_VALUE) {
throw new ArithmeticException("overflow: add");
}
return (int)s;
}
/**
* Subtract two integers, checking for overflow.
*
* @param x the minuend
* @param y the subtrahend
* @return the difference x-y
* @throws ArithmeticException if the result can not be represented as
* an int
*/
private static int subAndCheck(int x, int y) {
long s = (long)x-(long)y;
if (s < Integer.MIN_VALUE ||
s > Integer.MAX_VALUE) {
throw new ArithmeticException("overflow: add");
}
return (int)s;
}
/**
* Adds the value of this fraction to another, returning the result in reduced form.
* The algorithm follows Knuth, 4.5.1.
*
* @param fraction the fraction to add, must not be null
* @return a Fraction
instance with the resulting values
* @throws IllegalArgumentException if the fraction is null
* @throws ArithmeticException if the resulting numerator or denominator exceeds
* Integer.MAX_VALUE
*/
public Fraction add(Fraction fraction) {
return addSub(fraction, true /* add */);
}
/**
* Subtracts the value of another fraction from the value of this one,
* returning the result in reduced form.
*
* @param fraction the fraction to subtract, must not be null
* @return a Fraction
instance with the resulting values
* @throws IllegalArgumentException if the fraction is null
* @throws ArithmeticException if the resulting numerator or denominator
* cannot be represented in an int
.
*/
public Fraction subtract(Fraction fraction) {
return addSub(fraction, false /* subtract */);
}
/**
* Implement add and subtract using algorithm described in Knuth 4.5.1.
*
* @param fraction the fraction to subtract, must not be null
* @param isAdd true to add, false to subtract
* @return a Fraction
instance with the resulting values
* @throws IllegalArgumentException if the fraction is null
* @throws ArithmeticException if the resulting numerator or denominator
* cannot be represented in an int
.
*/
private Fraction addSub(Fraction fraction, boolean isAdd) {
if (fraction == null) {
throw new IllegalArgumentException("The fraction must not be null");
}
// zero is identity for addition.
if (numerator == 0) {
return isAdd ? fraction : fraction.negate();
}
if (fraction.numerator == 0) {
return this;
}
// if denominators are randomly distributed, d1 will be 1 about 61%
// of the time.
int d1 = greatestCommonDivisor(denominator, fraction.denominator);
if (d1==1) {
// result is ( (u*v' +/- u'v) / u'v')
int uvp = mulAndCheck(numerator, fraction.denominator);
int upv = mulAndCheck(fraction.numerator, denominator);
return new Fraction
(isAdd ? addAndCheck(uvp, upv) : subAndCheck(uvp, upv),
mulPosAndCheck(denominator, fraction.denominator));
}
// the quantity 't' requires 65 bits of precision; see knuth 4.5.1
// exercise 7. we're going to use a BigInteger.
// t = u(v'/d1) +/- v(u'/d1)
BigInteger uvp = BigInteger.valueOf(numerator)
.multiply(BigInteger.valueOf(fraction.denominator/d1));
BigInteger upv = BigInteger.valueOf(fraction.numerator)
.multiply(BigInteger.valueOf(denominator/d1));
BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv);
// but d2 doesn't need extra precision because
// d2 = gcd(t,d1) = gcd(t mod d1, d1)
int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue();
int d2 = (tmodd1==0)?d1:greatestCommonDivisor(tmodd1, d1);
// result is (t/d2) / (u'/d1)(v'/d2)
BigInteger w = t.divide(BigInteger.valueOf(d2));
if (w.bitLength() > 31) {
throw new ArithmeticException
("overflow: numerator too large after multiply");
}
return new Fraction
(w.intValue(),
mulPosAndCheck(denominator/d1, fraction.denominator/d2));
}
/**
* Multiplies the value of this fraction by another, returning the
* result in reduced form.
*
* @param fraction the fraction to multiply by, must not be null
* @return a Fraction
instance with the resulting values
* @throws IllegalArgumentException if the fraction is null
* @throws ArithmeticException if the resulting numerator or denominator exceeds
* Integer.MAX_VALUE
*/
public Fraction multiplyBy(Fraction fraction) {
if (fraction == null) {
throw new IllegalArgumentException("The fraction must not be null");
}
if (numerator == 0 || fraction.numerator == 0) {
return ZERO;
}
// knuth 4.5.1
// make sure we don't overflow unless the result *must* overflow.
int d1 = greatestCommonDivisor(numerator, fraction.denominator);
int d2 = greatestCommonDivisor(fraction.numerator, denominator);
return getReducedFraction
(mulAndCheck(numerator/d1, fraction.numerator/d2),
mulPosAndCheck(denominator/d2, fraction.denominator/d1));
}
/**
* Divide the value of this fraction by another.
*
* @param fraction the fraction to divide by, must not be null
* @return a Fraction
instance with the resulting values
* @throws IllegalArgumentException if the fraction is null
* @throws ArithmeticException if the fraction to divide by is zero
* @throws ArithmeticException if the resulting numerator or denominator exceeds
* Integer.MAX_VALUE
*/
public Fraction divideBy(Fraction fraction) {
if (fraction == null) {
throw new IllegalArgumentException("The fraction must not be null");
}
if (fraction.numerator == 0) {
throw new ArithmeticException("The fraction to divide by must not be zero");
}
return multiplyBy(fraction.invert());
}
// Basics
//-------------------------------------------------------------------
/**
* Compares this fraction to another object to test if they are equal.
.
*
* To be equal, both values must be equal. Thus 2/4 is not equal to 1/2.
*
* @param obj the reference object with which to compare
* @return true
if this object is equal
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof Fraction == false) {
return false;
}
Fraction other = (Fraction) obj;
return (getNumerator() == other.getNumerator() &&
getDenominator() == other.getDenominator());
}
/**
* Gets a hashCode for the fraction.
*
* @return a hash code value for this object
*/
public int hashCode() {
if (hashCode == 0) {
// hashcode update should be atomic.
hashCode = 37 * (37 * 17 + getNumerator()) + getDenominator();
}
return hashCode;
}
/**
* Compares this object to another based on size.
*
* Note: this class has a natural ordering that is inconsistent
* with equals, because, for example, equals treats 1/2 and 2/4 as
* different, whereas compareTo treats them as equal.
*
* @param object the object to compare to
* @return -1 if this is less, 0 if equal, +1 if greater
* @throws ClassCastException if the object is not a Fraction
* @throws NullPointerException if the object is null
*/
public int compareTo(Object object) {
Fraction other = (Fraction) object;
if (this==other) {
return 0;
}
if (numerator == other.numerator && denominator == other.denominator) {
return 0;
}
// otherwise see which is less
long first = (long) numerator * (long) other.denominator;
long second = (long) other.numerator * (long) denominator;
if (first == second) {
return 0;
} else if (first < second) {
return -1;
} else {
return 1;
}
}
/**
*
Gets the fraction as a String
.
*
* The format used is 'numerator/denominator' always.
*
* @return a String
form of the fraction
*/
public String toString() {
if (toString == null) {
toString = new StrBuilder(32)
.append(getNumerator())
.append('/')
.append(getDenominator()).toString();
}
return toString;
}
/**
*
Gets the fraction as a proper String
in the format X Y/Z.
*
* The format used in 'wholeNumber numerator/denominator'.
* If the whole number is zero it will be ommitted. If the numerator is zero,
* only the whole number is returned.
*
* @return a String
form of the fraction
*/
public String toProperString() {
if (toProperString == null) {
if (numerator == 0) {
toProperString = "0";
} else if (numerator == denominator) {
toProperString = "1";
} else if (numerator == -1 * denominator) {
toProperString = "-1";
} else if ((numerator>0?-numerator:numerator) < -denominator) {
// note that we do the magnitude comparison test above with
// NEGATIVE (not positive) numbers, since negative numbers
// have a larger range. otherwise numerator==Integer.MIN_VALUE
// is handled incorrectly.
int properNumerator = getProperNumerator();
if (properNumerator == 0) {
toProperString = Integer.toString(getProperWhole());
} else {
toProperString = new StrBuilder(32)
.append(getProperWhole()).append(' ')
.append(properNumerator).append('/')
.append(getDenominator()).toString();
}
} else {
toProperString = new StrBuilder(32)
.append(getNumerator()).append('/')
.append(getDenominator()).toString();
}
}
return toProperString;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/math/IEEE754rUtils.java 100644 0 0 20272 11513702442 24717 0 ustar 0 0 /*
* 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.lang.math;
/**
* Provides IEEE-754r variants of NumberUtils methods.
*
* See: http://en.wikipedia.org/wiki/IEEE_754r
*
* @since 2.4
* @author Apache Software Foundation
* @version $Id: IEEE754rUtils.java 905636 2010-02-02 14:03:32Z niallp $
*/
public class IEEE754rUtils {
/**
* Returns the minimum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
*/
public static double min(double[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns min
double min = array[0];
for (int i = 1; i < array.length; i++) {
min = min(array[i], min);
}
return min;
}
/**
* Returns the minimum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
*/
public static float min(float[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns min
float min = array[0];
for (int i = 1; i < array.length; i++) {
min = min(array[i], min);
}
return min;
}
/**
* Gets the minimum of three double
values.
*
* NaN is only returned if all numbers are NaN as per IEEE-754r.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
*/
public static double min(double a, double b, double c) {
return min(min(a, b), c);
}
/**
* Gets the minimum of two double
values.
*
* NaN is only returned if all numbers are NaN as per IEEE-754r.
*
* @param a value 1
* @param b value 2
* @return the smallest of the values
*/
public static double min(double a, double b) {
if(Double.isNaN(a)) {
return b;
} else
if(Double.isNaN(b)) {
return a;
} else {
return Math.min(a, b);
}
}
/**
* Gets the minimum of three float
values.
*
* NaN is only returned if all numbers are NaN as per IEEE-754r.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
*/
public static float min(float a, float b, float c) {
return min(min(a, b), c);
}
/**
* Gets the minimum of two float
values.
*
* NaN is only returned if all numbers are NaN as per IEEE-754r.
*
* @param a value 1
* @param b value 2
* @return the smallest of the values
*/
public static float min(float a, float b) {
if(Float.isNaN(a)) {
return b;
} else
if(Float.isNaN(b)) {
return a;
} else {
return Math.min(a, b);
}
}
/**
* Returns the maximum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
*/
public static double max(double[] array) {
// Validates input
if (array== null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns max
double max = array[0];
for (int j = 1; j < array.length; j++) {
max = max(array[j], max);
}
return max;
}
/**
* Returns the maximum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
*/
public static float max(float[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns max
float max = array[0];
for (int j = 1; j < array.length; j++) {
max = max(array[j], max);
}
return max;
}
/**
* Gets the maximum of three double
values.
*
* NaN is only returned if all numbers are NaN as per IEEE-754r.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
*/
public static double max(double a, double b, double c) {
return max(max(a, b), c);
}
/**
* Gets the maximum of two double
values.
*
* NaN is only returned if all numbers are NaN as per IEEE-754r.
*
* @param a value 1
* @param b value 2
* @return the largest of the values
*/
public static double max(double a, double b) {
if(Double.isNaN(a)) {
return b;
} else
if(Double.isNaN(b)) {
return a;
} else {
return Math.max(a, b);
}
}
/**
* Gets the maximum of three float
values.
*
* NaN is only returned if all numbers are NaN as per IEEE-754r.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
*/
public static float max(float a, float b, float c) {
return max(max(a, b), c);
}
/**
* Gets the maximum of two float
values.
*
* NaN is only returned if all numbers are NaN as per IEEE-754r.
*
* @param a value 1
* @param b value 2
* @return the largest of the values
*/
public static float max(float a, float b) {
if(Float.isNaN(a)) {
return b;
} else
if(Float.isNaN(b)) {
return a;
} else {
return Math.max(a, b);
}
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/math/IntRange.java 100644 0 0 30715 11513702442 24257 0 ustar 0 0 /*
* 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.lang.math;
import java.io.Serializable;
import org.apache.commons.lang.text.StrBuilder;
/**
* IntRange
represents an inclusive range of int
s.
*
* @author Apache Software Foundation
* @since 2.0
* @version $Id: IntRange.java 1057072 2011-01-10 01:55:57Z niallp $
*/
public final class IntRange extends Range implements Serializable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 71849363892730L;
/**
* The minimum number in this range (inclusive).
*/
private final int min;
/**
* The maximum number in this range (inclusive).
*/
private final int max;
/**
* Cached output minObject (class is immutable).
*/
private transient Integer minObject = null;
/**
* Cached output maxObject (class is immutable).
*/
private transient Integer maxObject = null;
/**
* Cached output hashCode (class is immutable).
*/
private transient int hashCode = 0;
/**
* Cached output toString (class is immutable).
*/
private transient String toString = null;
/**
* Constructs a new IntRange
using the specified
* number as both the minimum and maximum in this range.
*
* @param number the number to use for this range
*/
public IntRange(int number) {
super();
this.min = number;
this.max = number;
}
/**
* Constructs a new IntRange
using the specified
* number as both the minimum and maximum in this range.
*
* @param number the number to use for this range, must not be null
* @throws IllegalArgumentException if the number is null
*/
public IntRange(Number number) {
super();
if (number == null) {
throw new IllegalArgumentException("The number must not be null");
}
this.min = number.intValue();
this.max = number.intValue();
if (number instanceof Integer) {
this.minObject = (Integer) number;
this.maxObject = (Integer) number;
}
}
/**
* Constructs a new IntRange
with the specified
* minimum and maximum numbers (both inclusive).
*
* The arguments may be passed in the order (min,max) or (max,min). The
* getMinimum and getMaximum methods will return the correct values.
*
* @param number1 first number that defines the edge of the range, inclusive
* @param number2 second number that defines the edge of the range, inclusive
*/
public IntRange(int number1, int number2) {
super();
if (number2 < number1) {
this.min = number2;
this.max = number1;
} else {
this.min = number1;
this.max = number2;
}
}
/**
* Constructs a new IntRange
with the specified
* minimum and maximum numbers (both inclusive).
*
* The arguments may be passed in the order (min,max) or (max,min). The
* getMinimum and getMaximum methods will return the correct values.
*
* @param number1 first number that defines the edge of the range, inclusive
* @param number2 second number that defines the edge of the range, inclusive
* @throws IllegalArgumentException if either number is null
*/
public IntRange(Number number1, Number number2) {
super();
if (number1 == null || number2 == null) {
throw new IllegalArgumentException("The numbers must not be null");
}
int number1val = number1.intValue();
int number2val = number2.intValue();
if (number2val < number1val) {
this.min = number2val;
this.max = number1val;
if (number2 instanceof Integer) {
this.minObject = (Integer) number2;
}
if (number1 instanceof Integer) {
this.maxObject = (Integer) number1;
}
} else {
this.min = number1val;
this.max = number2val;
if (number1 instanceof Integer) {
this.minObject = (Integer) number1;
}
if (number2 instanceof Integer) {
this.maxObject = (Integer) number2;
}
}
}
// Accessors
//--------------------------------------------------------------------
/**
* Returns the minimum number in this range.
*
* @return the minimum number in this range
*/
public Number getMinimumNumber() {
if (minObject == null) {
minObject = new Integer(min);
}
return minObject;
}
/**
* Gets the minimum number in this range as a long
.
*
* @return the minimum number in this range
*/
public long getMinimumLong() {
return min;
}
/**
* Gets the minimum number in this range as a int
.
*
* @return the minimum number in this range
*/
public int getMinimumInteger() {
return min;
}
/**
* Gets the minimum number in this range as a double
.
*
* @return the minimum number in this range
*/
public double getMinimumDouble() {
return min;
}
/**
* Gets the minimum number in this range as a float
.
*
* @return the minimum number in this range
*/
public float getMinimumFloat() {
return min;
}
/**
* Returns the maximum number in this range.
*
* @return the maximum number in this range
*/
public Number getMaximumNumber() {
if (maxObject == null) {
maxObject = new Integer(max);
}
return maxObject;
}
/**
* Gets the maximum number in this range as a long
.
*
* @return the maximum number in this range
*/
public long getMaximumLong() {
return max;
}
/**
* Gets the maximum number in this range as a int
.
*
* @return the maximum number in this range
*/
public int getMaximumInteger() {
return max;
}
/**
* Gets the maximum number in this range as a double
.
*
* @return the maximum number in this range
*/
public double getMaximumDouble() {
return max;
}
/**
* Gets the maximum number in this range as a float
.
*
* @return the maximum number in this range
*/
public float getMaximumFloat() {
return max;
}
// Tests
//--------------------------------------------------------------------
/**
* Tests whether the specified number
occurs within
* this range using int
comparison.
*
* null
is handled and returns false
.
*
* @param number the number to test, may be null
* @return true
if the specified number occurs within this range
*/
public boolean containsNumber(Number number) {
if (number == null) {
return false;
}
return containsInteger(number.intValue());
}
/**
* Tests whether the specified int
occurs within
* this range using int
comparison.
*
* This implementation overrides the superclass for performance as it is
* the most common case.
*
* @param value the int to test
* @return true
if the specified number occurs within this
* range by int
comparison
*/
public boolean containsInteger(int value) {
return value >= min && value <= max;
}
// Range tests
//--------------------------------------------------------------------
/**
* Tests whether the specified range occurs entirely within this range
* using int
comparison.
*
* null
is handled and returns false
.
*
* @param range the range to test, may be null
* @return true
if the specified range occurs entirely within this range
* @throws IllegalArgumentException if the range is not of this type
*/
public boolean containsRange(Range range) {
if (range == null) {
return false;
}
return containsInteger(range.getMinimumInteger()) &&
containsInteger(range.getMaximumInteger());
}
/**
* Tests whether the specified range overlaps with this range
* using int
comparison.
*
* null
is handled and returns false
.
*
* @param range the range to test, may be null
* @return true
if the specified range overlaps with this range
*/
public boolean overlapsRange(Range range) {
if (range == null) {
return false;
}
return range.containsInteger(min) ||
range.containsInteger(max) ||
containsInteger(range.getMinimumInteger());
}
// Basics
//--------------------------------------------------------------------
/**
* Compares this range to another object to test if they are equal.
.
*
* To be equal, the class, minimum and maximum must be equal.
*
* @param obj the reference object with which to compare
* @return true
if this object is equal
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof IntRange == false) {
return false;
}
IntRange range = (IntRange) obj;
return min == range.min && max == range.max;
}
/**
* Gets a hashCode for the range.
*
* @return a hash code value for this object
*/
public int hashCode() {
if (hashCode == 0) {
hashCode = 17;
hashCode = 37 * hashCode + getClass().hashCode();
hashCode = 37 * hashCode + min;
hashCode = 37 * hashCode + max;
}
return hashCode;
}
/**
* Gets the range as a String
.
*
* The format of the String is 'Range[min,max]'.
*
* @return the String
representation of this range
*/
public String toString() {
if (toString == null) {
StrBuilder buf = new StrBuilder(32);
buf.append("Range[");
buf.append(min);
buf.append(',');
buf.append(max);
buf.append(']');
toString = buf.toString();
}
return toString;
}
/**
* Returns an array containing all the integer values in the range.
*
* @return the int[]
representation of this range
* @since 2.4
*/
public int[] toArray() {
int[] array = new int[max - min + 1];
for (int i = 0; i < array.length; i++) {
array[i] = min + i;
}
return array;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/math/JVMRandom.java 100644 0 0 15733 11513702442 24350 0 ustar 0 0 /*
* 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.lang.math;
import java.util.Random;
/**
* JVMRandom
is a wrapper that supports all possible
* Random methods via the {@link java.lang.Math#random()} method
* and its system-wide {@link Random} object.
*
* It does this to allow for a Random class in which the seed is
* shared between all members of the class - a better name would
* have been SharedSeedRandom.
*
* N.B. the current implementation overrides the methods
* {@link Random#nextInt(int)} and {@link Random#nextLong()}
* to produce positive numbers ranging from 0 (inclusive)
* to MAX_VALUE (exclusive).
*
* @since 2.0
* @version $Id: JVMRandom.java 911986 2010-02-19 21:19:05Z niallp $
*/
public final class JVMRandom extends Random {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 1L;
private static final Random SHARED_RANDOM = new Random();
/**
* Ensures that only the parent constructor can call reseed.
*/
private boolean constructed = false;
/**
* Constructs a new instance.
*/
public JVMRandom() {
this.constructed = true;
}
/**
* Unsupported in 2.0.
*
* @param seed ignored
* @throws UnsupportedOperationException
*/
public synchronized void setSeed(long seed) {
if (this.constructed) {
throw new UnsupportedOperationException();
}
}
/**
* Unsupported in 2.0.
*
* @return Nothing, this method always throws an UnsupportedOperationException.
* @throws UnsupportedOperationException
*/
public synchronized double nextGaussian() {
throw new UnsupportedOperationException();
}
/**
* Unsupported in 2.0.
*
* @param byteArray ignored
* @throws UnsupportedOperationException
*/
public void nextBytes(byte[] byteArray) {
throw new UnsupportedOperationException();
}
/**
*
Returns the next pseudorandom, uniformly distributed int value
* from the Math.random() sequence.
* Identical to nextInt(Integer.MAX_VALUE)
*
* N.B. All values are >= 0.
*
* @return the random int
*/
public int nextInt() {
return nextInt(Integer.MAX_VALUE);
}
/**
* Returns a pseudorandom, uniformly distributed int value between
* 0
(inclusive) and the specified value (exclusive), from
* the Math.random() sequence.
*
* @param n the specified exclusive max-value
* @return the random int
* @throws IllegalArgumentException when n <= 0
*/
public int nextInt(int n) {
return SHARED_RANDOM.nextInt(n);
}
/**
* Returns the next pseudorandom, uniformly distributed long value
* from the Math.random() sequence.
* Identical to nextLong(Long.MAX_VALUE)
*
* N.B. All values are >= 0.
*
* @return the random long
*/
public long nextLong() {
return nextLong(Long.MAX_VALUE);
}
/**
* Returns a pseudorandom, uniformly distributed long value between
* 0
(inclusive) and the specified value (exclusive), from
* the Math.random() sequence.
*
* @param n the specified exclusive max-value
* @return the random long
* @throws IllegalArgumentException when n <= 0
*/
public static long nextLong(long n) {
if (n <= 0) {
throw new IllegalArgumentException(
"Upper bound for nextInt must be positive"
);
}
// Code adapted from Harmony Random#nextInt(int)
if ((n & -n) == n) { // n is power of 2
// dropping lower order bits improves behaviour for low values of n
return next63bits() >> 63 // drop all the bits
- bitsRequired(n-1); // except the ones we need
}
// Not a power of two
long val;
long bits;
do { // reject some values to improve distribution
bits = next63bits();
val = bits % n;
} while (bits - val + (n - 1) < 0);
return val;
}
/**
* Returns the next pseudorandom, uniformly distributed boolean value
* from the Math.random() sequence.
*
* @return the random boolean
*/
public boolean nextBoolean() {
return SHARED_RANDOM.nextBoolean();
}
/**
* Returns the next pseudorandom, uniformly distributed float value
* between 0.0
and 1.0
from the Math.random()
* sequence.
*
* @return the random float
*/
public float nextFloat() {
return SHARED_RANDOM.nextFloat();
}
/**
* Synonymous to the Math.random() call.
*
* @return the random double
*/
public double nextDouble() {
return SHARED_RANDOM.nextDouble();
}
/**
* Get the next unsigned random long
* @return unsigned random long
*/
private static long next63bits(){
// drop the sign bit to leave 63 random bits
return SHARED_RANDOM.nextLong() & 0x7fffffffffffffffL;
}
/**
* Count the number of bits required to represent a long number.
*
* @param num long number
* @return number of bits required
*/
private static int bitsRequired(long num){
// Derived from Hacker's Delight, Figure 5-9
long y=num; // for checking right bits
int n=0; // number of leading zeros found
while(true){
// 64 = number of bits in a long
if (num < 0) {
return 64-n; // no leading zeroes left
}
if (y == 0) {
return n; // no bits left to check
}
n++;
num=num << 1; // check leading bits
y=y >> 1; // check trailing bits
}
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/math/LongRange.java 100644 0 0 32045 11513702442 24422 0 ustar 0 0 /*
* 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.lang.math;
import java.io.Serializable;
import org.apache.commons.lang.text.StrBuilder;
/**
* LongRange
represents an inclusive range of long
s.
*
* @author Apache Software Foundation
* @since 2.0
* @version $Id: LongRange.java 1057072 2011-01-10 01:55:57Z niallp $
*/
public final class LongRange extends Range implements Serializable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 71849363892720L;
/**
* The minimum number in this range (inclusive).
*/
private final long min;
/**
* The maximum number in this range (inclusive).
*/
private final long max;
/**
* Cached output minObject (class is immutable).
*/
private transient Long minObject = null;
/**
* Cached output maxObject (class is immutable).
*/
private transient Long maxObject = null;
/**
* Cached output hashCode (class is immutable).
*/
private transient int hashCode = 0;
/**
* Cached output toString (class is immutable).
*/
private transient String toString = null;
/**
* Constructs a new LongRange
using the specified
* number as both the minimum and maximum in this range.
*
* @param number the number to use for this range
*/
public LongRange(long number) {
super();
this.min = number;
this.max = number;
}
/**
* Constructs a new LongRange
using the specified
* number as both the minimum and maximum in this range.
*
* @param number the number to use for this range, must not
* be null
* @throws IllegalArgumentException if the number is null
*/
public LongRange(Number number) {
super();
if (number == null) {
throw new IllegalArgumentException("The number must not be null");
}
this.min = number.longValue();
this.max = number.longValue();
if (number instanceof Long) {
this.minObject = (Long) number;
this.maxObject = (Long) number;
}
}
/**
* Constructs a new LongRange
with the specified
* minimum and maximum numbers (both inclusive).
*
* The arguments may be passed in the order (min,max) or (max,min). The
* getMinimum and getMaximum methods will return the correct values.
*
* @param number1 first number that defines the edge of the range, inclusive
* @param number2 second number that defines the edge of the range, inclusive
*/
public LongRange(long number1, long number2) {
super();
if (number2 < number1) {
this.min = number2;
this.max = number1;
} else {
this.min = number1;
this.max = number2;
}
}
/**
* Constructs a new LongRange
with the specified
* minimum and maximum numbers (both inclusive).
*
* The arguments may be passed in the order (min,max) or (max,min). The
* getMinimum and getMaximum methods will return the correct values.
*
* @param number1 first number that defines the edge of the range, inclusive
* @param number2 second number that defines the edge of the range, inclusive
* @throws IllegalArgumentException if either number is null
*/
public LongRange(Number number1, Number number2) {
super();
if (number1 == null || number2 == null) {
throw new IllegalArgumentException("The numbers must not be null");
}
long number1val = number1.longValue();
long number2val = number2.longValue();
if (number2val < number1val) {
this.min = number2val;
this.max = number1val;
if (number2 instanceof Long) {
this.minObject = (Long) number2;
}
if (number1 instanceof Long) {
this.maxObject = (Long) number1;
}
} else {
this.min = number1val;
this.max = number2val;
if (number1 instanceof Long) {
this.minObject = (Long) number1;
}
if (number2 instanceof Long) {
this.maxObject = (Long) number2;
}
}
}
// Accessors
//--------------------------------------------------------------------
/**
* Returns the minimum number in this range.
*
* @return the minimum number in this range
*/
public Number getMinimumNumber() {
if (minObject == null) {
minObject = new Long(min);
}
return minObject;
}
/**
* Gets the minimum number in this range as a long
.
*
* @return the minimum number in this range
*/
public long getMinimumLong() {
return min;
}
/**
* Gets the minimum number in this range as a int
.
*
* This conversion can lose information for large values.
*
* @return the minimum number in this range
*/
public int getMinimumInteger() {
return (int) min;
}
/**
* Gets the minimum number in this range as a double
.
*
* This conversion can lose information for large values.
*
* @return the minimum number in this range
*/
public double getMinimumDouble() {
return min;
}
/**
* Gets the minimum number in this range as a float
.
*
* This conversion can lose information for large values.
*
* @return the minimum number in this range
*/
public float getMinimumFloat() {
return min;
}
/**
* Returns the maximum number in this range.
*
* @return the maximum number in this range
*/
public Number getMaximumNumber() {
if (maxObject == null) {
maxObject = new Long(max);
}
return maxObject;
}
/**
* Gets the maximum number in this range as a long
.
*
* @return the maximum number in this range
*/
public long getMaximumLong() {
return max;
}
/**
* Gets the maximum number in this range cast to an int
.
*
* This conversion can lose information for large values.
*
* @return the maximum number in this range cast to an int
.
*/
public int getMaximumInteger() {
return (int) max;
}
/**
* Gets the maximum number in this range as a double
.
*
* This conversion can lose information for large values.
*
* @return The maximum number in this range as a double
.
*/
public double getMaximumDouble() {
return max;
}
/**
* Gets the maximum number in this range as a float
.
*
* This conversion can lose information for large values.
*
* @return The maximum number in this range as a float
.
*/
public float getMaximumFloat() {
return max;
}
// Tests
//--------------------------------------------------------------------
/**
* Tests whether the specified number
occurs within
* this range using long
comparison.
*
* null
is handled and returns false
.
*
* @param number the number to test, may be null
* @return true
if the specified number occurs within this range
*/
public boolean containsNumber(Number number) {
if (number == null) {
return false;
}
return containsLong(number.longValue());
}
/**
* Tests whether the specified long
occurs within
* this range using long
comparison.
*
* This implementation overrides the superclass for performance as it is
* the most common case.
*
* @param value the long to test
* @return true
if the specified number occurs within this
* range by long
comparison
*/
public boolean containsLong(long value) {
return value >= min && value <= max;
}
// Range tests
//--------------------------------------------------------------------
/**
* Tests whether the specified range occurs entirely within this range
* using long
comparison.
*
* null
is handled and returns false
.
*
* @param range the range to test, may be null
* @return true
if the specified range occurs entirely within this range
* @throws IllegalArgumentException if the range is not of this type
*/
public boolean containsRange(Range range) {
if (range == null) {
return false;
}
return containsLong(range.getMinimumLong()) &&
containsLong(range.getMaximumLong());
}
/**
* Tests whether the specified range overlaps with this range
* using long
comparison.
*
* null
is handled and returns false
.
*
* @param range the range to test, may be null
* @return true
if the specified range overlaps with this range
*/
public boolean overlapsRange(Range range) {
if (range == null) {
return false;
}
return range.containsLong(min) ||
range.containsLong(max) ||
containsLong(range.getMinimumLong());
}
// Basics
//--------------------------------------------------------------------
/**
* Compares this range to another object to test if they are equal.
.
*
* To be equal, the class, minimum and maximum must be equal.
*
* @param obj the reference object with which to compare
* @return true
if this object is equal
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof LongRange == false) {
return false;
}
LongRange range = (LongRange) obj;
return min == range.min && max == range.max;
}
/**
* Gets a hashCode for the range.
*
* @return a hash code value for this object
*/
public int hashCode() {
if (hashCode == 0) {
hashCode = 17;
hashCode = 37 * hashCode + getClass().hashCode();
hashCode = 37 * hashCode + ((int) (min ^ (min >> 32)));
hashCode = 37 * hashCode + ((int) (max ^ (max >> 32)));
}
return hashCode;
}
/**
* Gets the range as a String
.
*
* The format of the String is 'Range[min,max]'.
*
* @return the String
representation of this range
*/
public String toString() {
if (toString == null) {
StrBuilder buf = new StrBuilder(32);
buf.append("Range[");
buf.append(min);
buf.append(',');
buf.append(max);
buf.append(']');
toString = buf.toString();
}
return toString;
}
/**
* Returns an array containing all the long values in the range.
*
* @return the long[]
representation of this range
* @since 2.4
*/
public long[] toArray() {
long[] array = new long[(int)(max - min + 1L)];
for(int i = 0; i < array.length; i++) {
array[i] = min + i;
}
return array;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/math/NumberRange.java 100644 0 0 21202 11513702442 24744 0 ustar 0 0 /*
* 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.lang.math;
import java.io.Serializable;
import org.apache.commons.lang.text.StrBuilder;
/**
* NumberRange
represents an inclusive range of
* {@link java.lang.Number} objects of the same type.
*
* @author Apache Software Foundation
* @author Christopher Elkins
* @since 2.0 (previously in org.apache.commons.lang)
* @version $Id: NumberRange.java 1057072 2011-01-10 01:55:57Z niallp $
*/
public final class NumberRange extends Range implements Serializable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 71849363892710L;
/**
* The minimum number in this range.
*/
private final Number min;
/**
* The maximum number in this range.
*/
private final Number max;
/**
* Cached output hashCode (class is immutable).
*/
private transient int hashCode = 0;
/**
* Cached output toString (class is immutable).
*/
private transient String toString = null;
/**
* Constructs a new NumberRange
using the specified
* number as both the minimum and maximum in this range.
*
* @param num the number to use for this range
* @throws IllegalArgumentException if the number is null
* @throws IllegalArgumentException if the number doesn't implement Comparable
* @throws IllegalArgumentException if the number is Double.NaN
or Float.NaN
*/
public NumberRange(Number num) {
if (num == null) {
throw new IllegalArgumentException("The number must not be null");
}
if (num instanceof Comparable == false) {
throw new IllegalArgumentException("The number must implement Comparable");
}
if (num instanceof Double && ((Double) num).isNaN()) {
throw new IllegalArgumentException("The number must not be NaN");
}
if (num instanceof Float && ((Float) num).isNaN()) {
throw new IllegalArgumentException("The number must not be NaN");
}
this.min = num;
this.max = num;
}
/**
* Constructs a new NumberRange
with the specified
* minimum and maximum numbers (both inclusive).
*
* The arguments may be passed in the order (min,max) or (max,min). The
* {@link #getMinimumNumber()} and {@link #getMaximumNumber()} methods will return the
* correct value.
*
* This constructor is designed to be used with two Number
* objects of the same type. If two objects of different types are passed in,
* an exception is thrown.
*
* @param num1 first number that defines the edge of the range, inclusive
* @param num2 second number that defines the edge of the range, inclusive
* @throws IllegalArgumentException if either number is null
* @throws IllegalArgumentException if the numbers are of different types
* @throws IllegalArgumentException if the numbers don't implement Comparable
*/
public NumberRange(Number num1, Number num2) {
if (num1 == null || num2 == null) {
throw new IllegalArgumentException("The numbers must not be null");
}
if (num1.getClass() != num2.getClass()) {
throw new IllegalArgumentException("The numbers must be of the same type");
}
if (num1 instanceof Comparable == false) {
throw new IllegalArgumentException("The numbers must implement Comparable");
}
if (num1 instanceof Double) {
if (((Double) num1).isNaN() || ((Double) num2).isNaN()) {
throw new IllegalArgumentException("The number must not be NaN");
}
} else if (num1 instanceof Float) {
if (((Float) num1).isNaN() || ((Float) num2).isNaN()) {
throw new IllegalArgumentException("The number must not be NaN");
}
}
int compare = ((Comparable) num1).compareTo(num2);
if (compare == 0) {
this.min = num1;
this.max = num1;
} else if (compare > 0) {
this.min = num2;
this.max = num1;
} else {
this.min = num1;
this.max = num2;
}
}
// Accessors
//--------------------------------------------------------------------
/**
* Returns the minimum number in this range.
*
* @return the minimum number in this range
*/
public Number getMinimumNumber() {
return min;
}
/**
* Returns the maximum number in this range.
*
* @return the maximum number in this range
*/
public Number getMaximumNumber() {
return max;
}
// Tests
//--------------------------------------------------------------------
/**
* Tests whether the specified number
occurs within
* this range.
*
* null
is handled and returns false
.
*
* @param number the number to test, may be null
* @return true
if the specified number occurs within this range
* @throws IllegalArgumentException if the number is of a different type to the range
*/
public boolean containsNumber(Number number) {
if (number == null) {
return false;
}
if (number.getClass() != min.getClass()) {
throw new IllegalArgumentException("The number must be of the same type as the range numbers");
}
int compareMin = ((Comparable) min).compareTo(number);
int compareMax = ((Comparable) max).compareTo(number);
return compareMin <= 0 && compareMax >= 0;
}
// Range tests
//--------------------------------------------------------------------
// use Range implementations
// Basics
//--------------------------------------------------------------------
/**
* Compares this range to another object to test if they are equal.
.
*
* To be equal, the class, minimum and maximum must be equal.
*
* @param obj the reference object with which to compare
* @return true
if this object is equal
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof NumberRange == false) {
return false;
}
NumberRange range = (NumberRange) obj;
return min.equals(range.min) && max.equals(range.max);
}
/**
* Gets a hashCode for the range.
*
* @return a hash code value for this object
*/
public int hashCode() {
if (hashCode == 0) {
hashCode = 17;
hashCode = 37 * hashCode + getClass().hashCode();
hashCode = 37 * hashCode + min.hashCode();
hashCode = 37 * hashCode + max.hashCode();
}
return hashCode;
}
/**
* Gets the range as a String
.
*
* The format of the String is 'Range[min,max]'.
*
* @return the String
representation of this range
*/
public String toString() {
if (toString == null) {
StrBuilder buf = new StrBuilder(32);
buf.append("Range[");
buf.append(min);
buf.append(',');
buf.append(max);
buf.append(']');
toString = buf.toString();
}
return toString;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/math/NumberUtils.java 100644 0 0 154046 11513702442 25045 0 ustar 0 0 /*
* 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.lang.math;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.apache.commons.lang.StringUtils;
/**
* Provides extra functionality for Java Number classes.
*
* @author Apache Software Foundation
* @author Rand McNeely
* @author Steve Downey
* @author Eric Pugh
* @author Phil Steitz
* @author Matthew Hawthorne
* @author Gary Gregory
* @author Fredrik Westermarck
* @since 2.0
* @version $Id: NumberUtils.java 1056853 2011-01-09 01:07:04Z niallp $
*/
public class NumberUtils {
/** Reusable Long constant for zero. */
public static final Long LONG_ZERO = new Long(0L);
/** Reusable Long constant for one. */
public static final Long LONG_ONE = new Long(1L);
/** Reusable Long constant for minus one. */
public static final Long LONG_MINUS_ONE = new Long(-1L);
/** Reusable Integer constant for zero. */
public static final Integer INTEGER_ZERO = new Integer(0);
/** Reusable Integer constant for one. */
public static final Integer INTEGER_ONE = new Integer(1);
/** Reusable Integer constant for minus one. */
public static final Integer INTEGER_MINUS_ONE = new Integer(-1);
/** Reusable Short constant for zero. */
public static final Short SHORT_ZERO = new Short((short) 0);
/** Reusable Short constant for one. */
public static final Short SHORT_ONE = new Short((short) 1);
/** Reusable Short constant for minus one. */
public static final Short SHORT_MINUS_ONE = new Short((short) -1);
/** Reusable Byte constant for zero. */
public static final Byte BYTE_ZERO = new Byte((byte) 0);
/** Reusable Byte constant for one. */
public static final Byte BYTE_ONE = new Byte((byte) 1);
/** Reusable Byte constant for minus one. */
public static final Byte BYTE_MINUS_ONE = new Byte((byte) -1);
/** Reusable Double constant for zero. */
public static final Double DOUBLE_ZERO = new Double(0.0d);
/** Reusable Double constant for one. */
public static final Double DOUBLE_ONE = new Double(1.0d);
/** Reusable Double constant for minus one. */
public static final Double DOUBLE_MINUS_ONE = new Double(-1.0d);
/** Reusable Float constant for zero. */
public static final Float FLOAT_ZERO = new Float(0.0f);
/** Reusable Float constant for one. */
public static final Float FLOAT_ONE = new Float(1.0f);
/** Reusable Float constant for minus one. */
public static final Float FLOAT_MINUS_ONE = new Float(-1.0f);
/**
* NumberUtils
instances should NOT be constructed in standard programming.
* Instead, the class should be used as NumberUtils.toInt("6");
.
*
* This constructor is public to permit tools that require a JavaBean instance
* to operate.
*/
public NumberUtils() {
super();
}
//-----------------------------------------------------------------------
/**
* Convert a String
to an int
, returning
* zero
if the conversion fails.
*
* If the string is null
, zero
is returned.
*
*
* NumberUtils.stringToInt(null) = 0
* NumberUtils.stringToInt("") = 0
* NumberUtils.stringToInt("1") = 1
*
*
* @param str the string to convert, may be null
* @return the int represented by the string, or zero
if
* conversion fails
* @deprecated Use {@link #toInt(String)}
* This method will be removed in Commons Lang 3.0
*/
public static int stringToInt(String str) {
return toInt(str);
}
/**
* Convert a String
to an int
, returning
* zero
if the conversion fails.
*
* If the string is null
, zero
is returned.
*
*
* NumberUtils.toInt(null) = 0
* NumberUtils.toInt("") = 0
* NumberUtils.toInt("1") = 1
*
*
* @param str the string to convert, may be null
* @return the int represented by the string, or zero
if
* conversion fails
* @since 2.1
*/
public static int toInt(String str) {
return toInt(str, 0);
}
/**
* Convert a String
to an int
, returning a
* default value if the conversion fails.
*
* If the string is null
, the default value is returned.
*
*
* NumberUtils.stringToInt(null, 1) = 1
* NumberUtils.stringToInt("", 1) = 1
* NumberUtils.stringToInt("1", 0) = 1
*
*
* @param str the string to convert, may be null
* @param defaultValue the default value
* @return the int represented by the string, or the default if conversion fails
* @deprecated Use {@link #toInt(String, int)}
* This method will be removed in Commons Lang 3.0
*/
public static int stringToInt(String str, int defaultValue) {
return toInt(str, defaultValue);
}
/**
* Convert a String
to an int
, returning a
* default value if the conversion fails.
*
* If the string is null
, the default value is returned.
*
*
* NumberUtils.toInt(null, 1) = 1
* NumberUtils.toInt("", 1) = 1
* NumberUtils.toInt("1", 0) = 1
*
*
* @param str the string to convert, may be null
* @param defaultValue the default value
* @return the int represented by the string, or the default if conversion fails
* @since 2.1
*/
public static int toInt(String str, int defaultValue) {
if(str == null) {
return defaultValue;
}
try {
return Integer.parseInt(str);
} catch (NumberFormatException nfe) {
return defaultValue;
}
}
/**
* Convert a String
to a long
, returning
* zero
if the conversion fails.
*
* If the string is null
, zero
is returned.
*
*
* NumberUtils.toLong(null) = 0L
* NumberUtils.toLong("") = 0L
* NumberUtils.toLong("1") = 1L
*
*
* @param str the string to convert, may be null
* @return the long represented by the string, or 0
if
* conversion fails
* @since 2.1
*/
public static long toLong(String str) {
return toLong(str, 0L);
}
/**
* Convert a String
to a long
, returning a
* default value if the conversion fails.
*
* If the string is null
, the default value is returned.
*
*
* NumberUtils.toLong(null, 1L) = 1L
* NumberUtils.toLong("", 1L) = 1L
* NumberUtils.toLong("1", 0L) = 1L
*
*
* @param str the string to convert, may be null
* @param defaultValue the default value
* @return the long represented by the string, or the default if conversion fails
* @since 2.1
*/
public static long toLong(String str, long defaultValue) {
if (str == null) {
return defaultValue;
}
try {
return Long.parseLong(str);
} catch (NumberFormatException nfe) {
return defaultValue;
}
}
/**
* Convert a String
to a float
, returning
* 0.0f
if the conversion fails.
*
* If the string str
is null
,
* 0.0f
is returned.
*
*
* NumberUtils.toFloat(null) = 0.0f
* NumberUtils.toFloat("") = 0.0f
* NumberUtils.toFloat("1.5") = 1.5f
*
*
* @param str the string to convert, may be null
* @return the float represented by the string, or 0.0f
* if conversion fails
* @since 2.1
*/
public static float toFloat(String str) {
return toFloat(str, 0.0f);
}
/**
* Convert a String
to a float
, returning a
* default value if the conversion fails.
*
* If the string str
is null
, the default
* value is returned.
*
*
* NumberUtils.toFloat(null, 1.1f) = 1.0f
* NumberUtils.toFloat("", 1.1f) = 1.1f
* NumberUtils.toFloat("1.5", 0.0f) = 1.5f
*
*
* @param str the string to convert, may be null
* @param defaultValue the default value
* @return the float represented by the string, or defaultValue
* if conversion fails
* @since 2.1
*/
public static float toFloat(String str, float defaultValue) {
if (str == null) {
return defaultValue;
}
try {
return Float.parseFloat(str);
} catch (NumberFormatException nfe) {
return defaultValue;
}
}
/**
* Convert a String
to a double
, returning
* 0.0d
if the conversion fails.
*
* If the string str
is null
,
* 0.0d
is returned.
*
*
* NumberUtils.toDouble(null) = 0.0d
* NumberUtils.toDouble("") = 0.0d
* NumberUtils.toDouble("1.5") = 1.5d
*
*
* @param str the string to convert, may be null
* @return the double represented by the string, or 0.0d
* if conversion fails
* @since 2.1
*/
public static double toDouble(String str) {
return toDouble(str, 0.0d);
}
/**
* Convert a String
to a double
, returning a
* default value if the conversion fails.
*
* If the string str
is null
, the default
* value is returned.
*
*
* NumberUtils.toDouble(null, 1.1d) = 1.1d
* NumberUtils.toDouble("", 1.1d) = 1.1d
* NumberUtils.toDouble("1.5", 0.0d) = 1.5d
*
*
* @param str the string to convert, may be null
* @param defaultValue the default value
* @return the double represented by the string, or defaultValue
* if conversion fails
* @since 2.1
*/
public static double toDouble(String str, double defaultValue) {
if (str == null) {
return defaultValue;
}
try {
return Double.parseDouble(str);
} catch (NumberFormatException nfe) {
return defaultValue;
}
}
//-----------------------------------------------------------------------
/**
* Convert a String
to a byte
, returning
* zero
if the conversion fails.
*
* If the string is null
, zero
is returned.
*
*
* NumberUtils.toByte(null) = 0
* NumberUtils.toByte("") = 0
* NumberUtils.toByte("1") = 1
*
*
* @param str the string to convert, may be null
* @return the byte represented by the string, or zero
if
* conversion fails
* @since 2.5
*/
public static byte toByte(String str) {
return toByte(str, (byte) 0);
}
/**
* Convert a String
to a byte
, returning a
* default value if the conversion fails.
*
* If the string is null
, the default value is returned.
*
*
* NumberUtils.toByte(null, 1) = 1
* NumberUtils.toByte("", 1) = 1
* NumberUtils.toByte("1", 0) = 1
*
*
* @param str the string to convert, may be null
* @param defaultValue the default value
* @return the byte represented by the string, or the default if conversion fails
* @since 2.5
*/
public static byte toByte(String str, byte defaultValue) {
if(str == null) {
return defaultValue;
}
try {
return Byte.parseByte(str);
} catch (NumberFormatException nfe) {
return defaultValue;
}
}
/**
* Convert a String
to a short
, returning
* zero
if the conversion fails.
*
* If the string is null
, zero
is returned.
*
*
* NumberUtils.toShort(null) = 0
* NumberUtils.toShort("") = 0
* NumberUtils.toShort("1") = 1
*
*
* @param str the string to convert, may be null
* @return the short represented by the string, or zero
if
* conversion fails
* @since 2.5
*/
public static short toShort(String str) {
return toShort(str, (short) 0);
}
/**
* Convert a String
to an short
, returning a
* default value if the conversion fails.
*
* If the string is null
, the default value is returned.
*
*
* NumberUtils.toShort(null, 1) = 1
* NumberUtils.toShort("", 1) = 1
* NumberUtils.toShort("1", 0) = 1
*
*
* @param str the string to convert, may be null
* @param defaultValue the default value
* @return the short represented by the string, or the default if conversion fails
* @since 2.5
*/
public static short toShort(String str, short defaultValue) {
if(str == null) {
return defaultValue;
}
try {
return Short.parseShort(str);
} catch (NumberFormatException nfe) {
return defaultValue;
}
}
//-----------------------------------------------------------------------
// must handle Long, Float, Integer, Float, Short,
// BigDecimal, BigInteger and Byte
// useful methods:
// Byte.decode(String)
// Byte.valueOf(String,int radix)
// Byte.valueOf(String)
// Double.valueOf(String)
// Float.valueOf(String)
// new Float(String)
// Integer.valueOf(String,int radix)
// Integer.valueOf(String)
// Integer.decode(String)
// Integer.getInteger(String)
// Integer.getInteger(String,int val)
// Integer.getInteger(String,Integer val)
// new Integer(String)
// new Double(String)
// new Byte(String)
// new Long(String)
// Long.getLong(String)
// Long.getLong(String,int)
// Long.getLong(String,Integer)
// Long.valueOf(String,int)
// Long.valueOf(String)
// new Short(String)
// Short.decode(String)
// Short.valueOf(String,int)
// Short.valueOf(String)
// new BigDecimal(String)
// new BigInteger(String)
// new BigInteger(String,int radix)
// Possible inputs:
// 45 45.5 45E7 4.5E7 Hex Oct Binary xxxF xxxD xxxf xxxd
// plus minus everything. Prolly more. A lot are not separable.
/**
* Turns a string value into a java.lang.Number.
*
* First, the value is examined for a type qualifier on the end
* ('f','F','d','D','l','L'
). If it is found, it starts
* trying to create successively larger types from the type specified
* until one is found that can represent the value.
*
* If a type specifier is not found, it will check for a decimal point
* and then try successively larger types from Integer
to
* BigInteger
and from Float
to
* BigDecimal
.
*
* If the string starts with 0x
or -0x
, it
* will be interpreted as a hexadecimal integer. Values with leading
* 0
's will not be interpreted as octal.
*
* Returns null
if the string is null
.
*
* This method does not trim the input string, i.e., strings with leading
* or trailing spaces will generate NumberFormatExceptions.
*
* @param str String containing a number, may be null
* @return Number created from the string
* @throws NumberFormatException if the value cannot be converted
*/
public static Number createNumber(String str) throws NumberFormatException {
if (str == null) {
return null;
}
if (StringUtils.isBlank(str)) {
throw new NumberFormatException("A blank string is not a valid number");
}
if (str.startsWith("--")) {
// this is protection for poorness in java.lang.BigDecimal.
// it accepts this as a legal value, but it does not appear
// to be in specification of class. OS X Java parses it to
// a wrong value.
return null;
}
if (str.startsWith("0x") || str.startsWith("-0x")) {
return createInteger(str);
}
char lastChar = str.charAt(str.length() - 1);
String mant;
String dec;
String exp;
int decPos = str.indexOf('.');
int expPos = str.indexOf('e') + str.indexOf('E') + 1;
if (decPos > -1) {
if (expPos > -1) {
if (expPos < decPos || expPos > str.length()) {
throw new NumberFormatException(str + " is not a valid number.");
}
dec = str.substring(decPos + 1, expPos);
} else {
dec = str.substring(decPos + 1);
}
mant = str.substring(0, decPos);
} else {
if (expPos > -1) {
if (expPos > str.length()) {
throw new NumberFormatException(str + " is not a valid number.");
}
mant = str.substring(0, expPos);
} else {
mant = str;
}
dec = null;
}
if (!Character.isDigit(lastChar) && lastChar != '.') {
if (expPos > -1 && expPos < str.length() - 1) {
exp = str.substring(expPos + 1, str.length() - 1);
} else {
exp = null;
}
//Requesting a specific type..
String numeric = str.substring(0, str.length() - 1);
boolean allZeros = isAllZeros(mant) && isAllZeros(exp);
switch (lastChar) {
case 'l' :
case 'L' :
if (dec == null
&& exp == null
&& (numeric.charAt(0) == '-' && isDigits(numeric.substring(1)) || isDigits(numeric))) {
try {
return createLong(numeric);
} catch (NumberFormatException nfe) {
//Too big for a long
}
return createBigInteger(numeric);
}
throw new NumberFormatException(str + " is not a valid number.");
case 'f' :
case 'F' :
try {
Float f = NumberUtils.createFloat(numeric);
if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) {
//If it's too big for a float or the float value = 0 and the string
//has non-zeros in it, then float does not have the precision we want
return f;
}
} catch (NumberFormatException nfe) {
// ignore the bad number
}
//$FALL-THROUGH$
case 'd' :
case 'D' :
try {
Double d = NumberUtils.createDouble(numeric);
if (!(d.isInfinite() || (d.floatValue() == 0.0D && !allZeros))) {
return d;
}
} catch (NumberFormatException nfe) {
// ignore the bad number
}
try {
return createBigDecimal(numeric);
} catch (NumberFormatException e) {
// ignore the bad number
}
//$FALL-THROUGH$
default :
throw new NumberFormatException(str + " is not a valid number.");
}
} else {
//User doesn't have a preference on the return type, so let's start
//small and go from there...
if (expPos > -1 && expPos < str.length() - 1) {
exp = str.substring(expPos + 1, str.length());
} else {
exp = null;
}
if (dec == null && exp == null) {
//Must be an int,long,bigint
try {
return createInteger(str);
} catch (NumberFormatException nfe) {
// ignore the bad number
}
try {
return createLong(str);
} catch (NumberFormatException nfe) {
// ignore the bad number
}
return createBigInteger(str);
} else {
//Must be a float,double,BigDec
boolean allZeros = isAllZeros(mant) && isAllZeros(exp);
try {
Float f = createFloat(str);
if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) {
return f;
}
} catch (NumberFormatException nfe) {
// ignore the bad number
}
try {
Double d = createDouble(str);
if (!(d.isInfinite() || (d.doubleValue() == 0.0D && !allZeros))) {
return d;
}
} catch (NumberFormatException nfe) {
// ignore the bad number
}
return createBigDecimal(str);
}
}
}
/**
* Utility method for {@link #createNumber(java.lang.String)}.
*
* Returns true
if s is null
.
*
* @param str the String to check
* @return if it is all zeros or null
*/
private static boolean isAllZeros(String str) {
if (str == null) {
return true;
}
for (int i = str.length() - 1; i >= 0; i--) {
if (str.charAt(i) != '0') {
return false;
}
}
return str.length() > 0;
}
//-----------------------------------------------------------------------
/**
* Convert a String
to a Float
.
*
* Returns null
if the string is null
.
*
* @param str a String
to convert, may be null
* @return converted Float
* @throws NumberFormatException if the value cannot be converted
*/
public static Float createFloat(String str) {
if (str == null) {
return null;
}
return Float.valueOf(str);
}
/**
* Convert a String
to a Double
.
*
* Returns null
if the string is null
.
*
* @param str a String
to convert, may be null
* @return converted Double
* @throws NumberFormatException if the value cannot be converted
*/
public static Double createDouble(String str) {
if (str == null) {
return null;
}
return Double.valueOf(str);
}
/**
* Convert a String
to a Integer
, handling
* hex and octal notations.
*
* Returns null
if the string is null
.
*
* @param str a String
to convert, may be null
* @return converted Integer
* @throws NumberFormatException if the value cannot be converted
*/
public static Integer createInteger(String str) {
if (str == null) {
return null;
}
// decode() handles 0xAABD and 0777 (hex and octal) as well.
return Integer.decode(str);
}
/**
* Convert a String
to a Long
.
*
* Returns null
if the string is null
.
*
* @param str a String
to convert, may be null
* @return converted Long
* @throws NumberFormatException if the value cannot be converted
*/
public static Long createLong(String str) {
if (str == null) {
return null;
}
return Long.valueOf(str);
}
/**
* Convert a String
to a BigInteger
.
*
* Returns null
if the string is null
.
*
* @param str a String
to convert, may be null
* @return converted BigInteger
* @throws NumberFormatException if the value cannot be converted
*/
public static BigInteger createBigInteger(String str) {
if (str == null) {
return null;
}
return new BigInteger(str);
}
/**
* Convert a String
to a BigDecimal
.
*
* Returns null
if the string is null
.
*
* @param str a String
to convert, may be null
* @return converted BigDecimal
* @throws NumberFormatException if the value cannot be converted
*/
public static BigDecimal createBigDecimal(String str) {
if (str == null) {
return null;
}
// handle JDK1.3.1 bug where "" throws IndexOutOfBoundsException
if (StringUtils.isBlank(str)) {
throw new NumberFormatException("A blank string is not a valid number");
}
return new BigDecimal(str);
}
// Min in array
//--------------------------------------------------------------------
/**
* Returns the minimum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
*/
public static long min(long[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns min
long min = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] < min) {
min = array[i];
}
}
return min;
}
/**
* Returns the minimum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
*/
public static int min(int[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns min
int min = array[0];
for (int j = 1; j < array.length; j++) {
if (array[j] < min) {
min = array[j];
}
}
return min;
}
/**
* Returns the minimum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
*/
public static short min(short[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns min
short min = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] < min) {
min = array[i];
}
}
return min;
}
/**
* Returns the minimum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
*/
public static byte min(byte[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns min
byte min = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] < min) {
min = array[i];
}
}
return min;
}
/**
* Returns the minimum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
* @see IEEE754rUtils#min(double[]) IEEE754rUtils for a version of this method that handles NaN differently
*/
public static double min(double[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns min
double min = array[0];
for (int i = 1; i < array.length; i++) {
if (Double.isNaN(array[i])) {
return Double.NaN;
}
if (array[i] < min) {
min = array[i];
}
}
return min;
}
/**
* Returns the minimum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
* @see IEEE754rUtils#min(float[]) IEEE754rUtils for a version of this method that handles NaN differently
*/
public static float min(float[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns min
float min = array[0];
for (int i = 1; i < array.length; i++) {
if (Float.isNaN(array[i])) {
return Float.NaN;
}
if (array[i] < min) {
min = array[i];
}
}
return min;
}
// Max in array
//--------------------------------------------------------------------
/**
* Returns the maximum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
*/
public static long max(long[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns max
long max = array[0];
for (int j = 1; j < array.length; j++) {
if (array[j] > max) {
max = array[j];
}
}
return max;
}
/**
* Returns the maximum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
*/
public static int max(int[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns max
int max = array[0];
for (int j = 1; j < array.length; j++) {
if (array[j] > max) {
max = array[j];
}
}
return max;
}
/**
* Returns the maximum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
*/
public static short max(short[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns max
short max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
return max;
}
/**
* Returns the maximum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
*/
public static byte max(byte[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns max
byte max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
return max;
}
/**
* Returns the maximum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
* @see IEEE754rUtils#max(double[]) IEEE754rUtils for a version of this method that handles NaN differently
*/
public static double max(double[] array) {
// Validates input
if (array== null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns max
double max = array[0];
for (int j = 1; j < array.length; j++) {
if (Double.isNaN(array[j])) {
return Double.NaN;
}
if (array[j] > max) {
max = array[j];
}
}
return max;
}
/**
* Returns the maximum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if array
is null
* @throws IllegalArgumentException if array
is empty
* @see IEEE754rUtils#max(float[]) IEEE754rUtils for a version of this method that handles NaN differently
*/
public static float max(float[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns max
float max = array[0];
for (int j = 1; j < array.length; j++) {
if (Float.isNaN(array[j])) {
return Float.NaN;
}
if (array[j] > max) {
max = array[j];
}
}
return max;
}
// 3 param min
//-----------------------------------------------------------------------
/**
* Gets the minimum of three long
values.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
*/
public static long min(long a, long b, long c) {
if (b < a) {
a = b;
}
if (c < a) {
a = c;
}
return a;
}
/**
* Gets the minimum of three int
values.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
*/
public static int min(int a, int b, int c) {
if (b < a) {
a = b;
}
if (c < a) {
a = c;
}
return a;
}
/**
* Gets the minimum of three short
values.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
*/
public static short min(short a, short b, short c) {
if (b < a) {
a = b;
}
if (c < a) {
a = c;
}
return a;
}
/**
* Gets the minimum of three byte
values.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
*/
public static byte min(byte a, byte b, byte c) {
if (b < a) {
a = b;
}
if (c < a) {
a = c;
}
return a;
}
/**
* Gets the minimum of three double
values.
*
* If any value is NaN
, NaN
is
* returned. Infinity is handled.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
* @see IEEE754rUtils#min(double, double, double) for a version of this method that handles NaN differently
*/
public static double min(double a, double b, double c) {
return Math.min(Math.min(a, b), c);
}
/**
* Gets the minimum of three float
values.
*
* If any value is NaN
, NaN
is
* returned. Infinity is handled.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
* @see IEEE754rUtils#min(float, float, float) for a version of this method that handles NaN differently
*/
public static float min(float a, float b, float c) {
return Math.min(Math.min(a, b), c);
}
// 3 param max
//-----------------------------------------------------------------------
/**
* Gets the maximum of three long
values.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
*/
public static long max(long a, long b, long c) {
if (b > a) {
a = b;
}
if (c > a) {
a = c;
}
return a;
}
/**
* Gets the maximum of three int
values.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
*/
public static int max(int a, int b, int c) {
if (b > a) {
a = b;
}
if (c > a) {
a = c;
}
return a;
}
/**
* Gets the maximum of three short
values.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
*/
public static short max(short a, short b, short c) {
if (b > a) {
a = b;
}
if (c > a) {
a = c;
}
return a;
}
/**
* Gets the maximum of three byte
values.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
*/
public static byte max(byte a, byte b, byte c) {
if (b > a) {
a = b;
}
if (c > a) {
a = c;
}
return a;
}
/**
* Gets the maximum of three double
values.
*
* If any value is NaN
, NaN
is
* returned. Infinity is handled.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
* @see IEEE754rUtils#max(double, double, double) for a version of this method that handles NaN differently
*/
public static double max(double a, double b, double c) {
return Math.max(Math.max(a, b), c);
}
/**
* Gets the maximum of three float
values.
*
* If any value is NaN
, NaN
is
* returned. Infinity is handled.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
* @see IEEE754rUtils#max(float, float, float) for a version of this method that handles NaN differently
*/
public static float max(float a, float b, float c) {
return Math.max(Math.max(a, b), c);
}
//-----------------------------------------------------------------------
/**
* Compares two doubles
for order.
*
* This method is more comprehensive than the standard Java greater
* than, less than and equals operators.
*
* - It returns
-1
if the first value is less than the second.
* - It returns
+1
if the first value is greater than the second.
* - It returns
0
if the values are equal.
*
*
*
* The ordering is as follows, largest to smallest:
*
* - NaN
*
- Positive infinity
*
- Maximum double
*
- Normal positive numbers
*
- +0.0
*
- -0.0
*
- Normal negative numbers
*
- Minimum double (
-Double.MAX_VALUE
)
* - Negative infinity
*
*
*
* Comparing NaN
with NaN
will
* return 0
.
*
* @param lhs the first double
* @param rhs the second double
* @return -1
if lhs is less, +1
if greater,
* 0
if equal to rhs
*/
public static int compare(double lhs, double rhs) {
if (lhs < rhs) {
return -1;
}
if (lhs > rhs) {
return +1;
}
// Need to compare bits to handle 0.0 == -0.0 being true
// compare should put -0.0 < +0.0
// Two NaNs are also == for compare purposes
// where NaN == NaN is false
long lhsBits = Double.doubleToLongBits(lhs);
long rhsBits = Double.doubleToLongBits(rhs);
if (lhsBits == rhsBits) {
return 0;
}
// Something exotic! A comparison to NaN or 0.0 vs -0.0
// Fortunately NaN's long is > than everything else
// Also negzeros bits < poszero
// NAN: 9221120237041090560
// MAX: 9218868437227405311
// NEGZERO: -9223372036854775808
if (lhsBits < rhsBits) {
return -1;
} else {
return +1;
}
}
/**
* Compares two floats for order.
*
* This method is more comprehensive than the standard Java greater than,
* less than and equals operators.
*
* - It returns
-1
if the first value is less than the second.
* - It returns
+1
if the first value is greater than the second.
* - It returns
0
if the values are equal.
*
*
* The ordering is as follows, largest to smallest:
*
* - NaN
*
- Positive infinity
*
- Maximum float
*
- Normal positive numbers
*
- +0.0
*
- -0.0
*
- Normal negative numbers
*
- Minimum float (
-Float.MAX_VALUE
)
* - Negative infinity
*
*
* Comparing NaN
with NaN
will return
* 0
.
*
* @param lhs the first float
* @param rhs the second float
* @return -1
if lhs is less, +1
if greater,
* 0
if equal to rhs
*/
public static int compare(float lhs, float rhs) {
if (lhs < rhs) {
return -1;
}
if (lhs > rhs) {
return +1;
}
//Need to compare bits to handle 0.0 == -0.0 being true
// compare should put -0.0 < +0.0
// Two NaNs are also == for compare purposes
// where NaN == NaN is false
int lhsBits = Float.floatToIntBits(lhs);
int rhsBits = Float.floatToIntBits(rhs);
if (lhsBits == rhsBits) {
return 0;
}
//Something exotic! A comparison to NaN or 0.0 vs -0.0
//Fortunately NaN's int is > than everything else
//Also negzeros bits < poszero
//NAN: 2143289344
//MAX: 2139095039
//NEGZERO: -2147483648
if (lhsBits < rhsBits) {
return -1;
} else {
return +1;
}
}
//-----------------------------------------------------------------------
/**
* Checks whether the String
contains only
* digit characters.
*
* Null
and empty String will return
* false
.
*
* @param str the String
to check
* @return true
if str contains only unicode numeric
*/
public static boolean isDigits(String str) {
if (StringUtils.isEmpty(str)) {
return false;
}
for (int i = 0; i < str.length(); i++) {
if (!Character.isDigit(str.charAt(i))) {
return false;
}
}
return true;
}
/**
* Checks whether the String a valid Java number.
*
* Valid numbers include hexadecimal marked with the 0x
* qualifier, scientific notation and numbers marked with a type
* qualifier (e.g. 123L).
*
* Null
and empty String will return
* false
.
*
* @param str the String
to check
* @return true
if the string is a correctly formatted number
*/
public static boolean isNumber(String str) {
if (StringUtils.isEmpty(str)) {
return false;
}
char[] chars = str.toCharArray();
int sz = chars.length;
boolean hasExp = false;
boolean hasDecPoint = false;
boolean allowSigns = false;
boolean foundDigit = false;
// deal with any possible sign up front
int start = (chars[0] == '-') ? 1 : 0;
if (sz > start + 1) {
if (chars[start] == '0' && chars[start + 1] == 'x') {
int i = start + 2;
if (i == sz) {
return false; // str == "0x"
}
// checking hex (it can't be anything else)
for (; i < chars.length; i++) {
if ((chars[i] < '0' || chars[i] > '9')
&& (chars[i] < 'a' || chars[i] > 'f')
&& (chars[i] < 'A' || chars[i] > 'F')) {
return false;
}
}
return true;
}
}
sz--; // don't want to loop to the last char, check it afterwords
// for type qualifiers
int i = start;
// loop to the next to last char or to the last char if we need another digit to
// make a valid number (e.g. chars[0..5] = "1234E")
while (i < sz || (i < sz + 1 && allowSigns && !foundDigit)) {
if (chars[i] >= '0' && chars[i] <= '9') {
foundDigit = true;
allowSigns = false;
} else if (chars[i] == '.') {
if (hasDecPoint || hasExp) {
// two decimal points or dec in exponent
return false;
}
hasDecPoint = true;
} else if (chars[i] == 'e' || chars[i] == 'E') {
// we've already taken care of hex.
if (hasExp) {
// two E's
return false;
}
if (!foundDigit) {
return false;
}
hasExp = true;
allowSigns = true;
} else if (chars[i] == '+' || chars[i] == '-') {
if (!allowSigns) {
return false;
}
allowSigns = false;
foundDigit = false; // we need a digit after the E
} else {
return false;
}
i++;
}
if (i < chars.length) {
if (chars[i] >= '0' && chars[i] <= '9') {
// no type qualifier, OK
return true;
}
if (chars[i] == 'e' || chars[i] == 'E') {
// can't have an E at the last byte
return false;
}
if (chars[i] == '.') {
if (hasDecPoint || hasExp) {
// two decimal points or dec in exponent
return false;
}
// single trailing decimal point after non-exponent is ok
return foundDigit;
}
if (!allowSigns
&& (chars[i] == 'd'
|| chars[i] == 'D'
|| chars[i] == 'f'
|| chars[i] == 'F')) {
return foundDigit;
}
if (chars[i] == 'l'
|| chars[i] == 'L') {
// not allowing L with an exponent
return foundDigit && !hasExp;
}
// last character is illegal
return false;
}
// allowSigns is true iff the val ends in 'E'
// found digit it to make sure weird stuff like '.' and '1E-' doesn't pass
return !allowSigns && foundDigit;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/math/package.html 100644 0 0 2170 11513702442 24140 0 ustar 0 0
Extends {@link java.math} for business mathematical classes. This package is intended for business
mathematical use, not scientific use. See Commons Math
for a more complete set of mathematical classes.
@since 2.0
These classes are immutable, and therefore thread-safe.
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/math/RandomUtils.java 100644 0 0 13127 11513702442 25007 0 ustar 0 0 /*
* 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.lang.math;
import java.util.Random;
/**
* RandomUtils
is a wrapper that supports all possible
* {@link java.util.Random} methods via the {@link java.lang.Math#random()}
* method and its system-wide Random
object.
*
* @author Gary D. Gregory
* @since 2.0
* @version $Id: RandomUtils.java 906320 2010-02-04 01:41:10Z sebb $
*/
public class RandomUtils {
/**
* An instance of {@link JVMRandom}.
*/
public static final Random JVM_RANDOM = new JVMRandom();
// should be possible for JVM_RANDOM?
// public static void nextBytes(byte[]) {
// public synchronized double nextGaussian();
// }
/**
*
Returns the next pseudorandom, uniformly distributed int value
* from the Math.random() sequence.
* N.B. All values are >= 0.
* @return the random int
*/
public static int nextInt() {
return nextInt(JVM_RANDOM);
}
/**
* Returns the next pseudorandom, uniformly distributed int value
* from the given random
sequence.
*
* @param random the Random sequence generator.
* @return the random int
*/
public static int nextInt(Random random) {
return random.nextInt();
}
/**
* Returns a pseudorandom, uniformly distributed int value
* between 0
(inclusive) and the specified value
* (exclusive), from the Math.random() sequence.
*
* @param n the specified exclusive max-value
* @return the random int
*/
public static int nextInt(int n) {
return nextInt(JVM_RANDOM, n);
}
/**
* Returns a pseudorandom, uniformly distributed int value
* between 0
(inclusive) and the specified value
* (exclusive), from the given Random sequence.
*
* @param random the Random sequence generator.
* @param n the specified exclusive max-value
* @return the random int
*/
public static int nextInt(Random random, int n) {
// check this cannot return 'n'
return random.nextInt(n);
}
/**
* Returns the next pseudorandom, uniformly distributed long value
* from the Math.random() sequence.
* N.B. All values are >= 0.
* @return the random long
*/
public static long nextLong() {
return nextLong(JVM_RANDOM);
}
/**
* Returns the next pseudorandom, uniformly distributed long value
* from the given Random sequence.
*
* @param random the Random sequence generator.
* @return the random long
*/
public static long nextLong(Random random) {
return random.nextLong();
}
/**
* Returns the next pseudorandom, uniformly distributed boolean value
* from the Math.random() sequence.
*
* @return the random boolean
*/
public static boolean nextBoolean() {
return nextBoolean(JVM_RANDOM);
}
/**
* Returns the next pseudorandom, uniformly distributed boolean value
* from the given random sequence.
*
* @param random the Random sequence generator.
* @return the random boolean
*/
public static boolean nextBoolean(Random random) {
return random.nextBoolean();
}
/**
* Returns the next pseudorandom, uniformly distributed float value
* between 0.0
and 1.0
from the Math.random()
* sequence.
*
* @return the random float
*/
public static float nextFloat() {
return nextFloat(JVM_RANDOM);
}
/**
* Returns the next pseudorandom, uniformly distributed float value
* between 0.0
and 1.0
from the given Random
* sequence.
*
* @param random the Random sequence generator.
* @return the random float
*/
public static float nextFloat(Random random) {
return random.nextFloat();
}
/**
* Returns the next pseudorandom, uniformly distributed float value
* between 0.0
and 1.0
from the Math.random()
* sequence.
*
* @return the random double
*/
public static double nextDouble() {
return nextDouble(JVM_RANDOM);
}
/**
* Returns the next pseudorandom, uniformly distributed float value
* between 0.0
and 1.0
from the given Random
* sequence.
*
* @param random the Random sequence generator.
* @return the random double
*/
public static double nextDouble(Random random) {
return random.nextDouble();
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/math/Range.java 100644 0 0 37123 11513702442 23604 0 ustar 0 0 /*
* 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.lang.math;
import org.apache.commons.lang.text.StrBuilder;
/**
* Range
represents a range of numbers of the same type.
*
* Specific subclasses hold the range values as different types. Each
* subclass should be immutable and {@link java.io.Serializable Serializable}
* if possible.
*
* @author Apache Software Foundation
* @since 2.0
* @version $Id: Range.java 1057072 2011-01-10 01:55:57Z niallp $
*/
public abstract class Range {
/**
* Constructs a new range.
*/
public Range() {
super();
}
// Accessors
//--------------------------------------------------------------------
/**
* Gets the minimum number in this range.
*
* @return the minimum number in this range
*/
public abstract Number getMinimumNumber();
/**
* Gets the minimum number in this range as a long
.
*
* This implementation uses the {@link #getMinimumNumber()} method.
* Subclasses may be able to optimise this.
*
* @return the minimum number in this range
*/
public long getMinimumLong() {
return getMinimumNumber().longValue();
}
/**
* Gets the minimum number in this range as a int
.
*
* This implementation uses the {@link #getMinimumNumber()} method.
* Subclasses may be able to optimise this.
*
* @return the minimum number in this range
*/
public int getMinimumInteger() {
return getMinimumNumber().intValue();
}
/**
* Gets the minimum number in this range as a double
.
*
* This implementation uses the {@link #getMinimumNumber()} method.
* Subclasses may be able to optimise this.
*
* @return the minimum number in this range
*/
public double getMinimumDouble() {
return getMinimumNumber().doubleValue();
}
/**
* Gets the minimum number in this range as a float
.
*
* This implementation uses the {@link #getMinimumNumber()} method.
* Subclasses may be able to optimise this.
*
* @return the minimum number in this range
*/
public float getMinimumFloat() {
return getMinimumNumber().floatValue();
}
/**
* Gets the maximum number in this range.
*
* @return the maximum number in this range
*/
public abstract Number getMaximumNumber();
/**
* Gets the maximum number in this range as a long
.
*
* This implementation uses the {@link #getMaximumNumber()} method.
* Subclasses may be able to optimise this.
*
* @return the maximum number in this range
*/
public long getMaximumLong() {
return getMaximumNumber().longValue();
}
/**
* Gets the maximum number in this range as a int
.
*
* This implementation uses the {@link #getMaximumNumber()} method.
* Subclasses may be able to optimise this.
*
* @return the maximum number in this range
*/
public int getMaximumInteger() {
return getMaximumNumber().intValue();
}
/**
* Gets the maximum number in this range as a double
.
*
* This implementation uses the {@link #getMaximumNumber()} method.
* Subclasses may be able to optimise this.
*
* @return the maximum number in this range
*/
public double getMaximumDouble() {
return getMaximumNumber().doubleValue();
}
/**
* Gets the maximum number in this range as a float
.
*
* This implementation uses the {@link #getMaximumNumber()} method.
* Subclasses may be able to optimise this.
*
* @return the maximum number in this range
*/
public float getMaximumFloat() {
return getMaximumNumber().floatValue();
}
// Include tests
//--------------------------------------------------------------------
/**
* Tests whether the specified Number
occurs within
* this range.
*
* The exact comparison implementation varies by subclass. It is
* intended that an int
specific subclass will compare using
* int
comparison.
*
* null
is handled and returns false
.
*
* @param number the number to test, may be null
* @return true
if the specified number occurs within this range
* @throws IllegalArgumentException if the Number
cannot be compared
*/
public abstract boolean containsNumber(Number number);
/**
* Tests whether the specified Number
occurs within
* this range using long
comparison..
*
* null
is handled and returns false
.
*
* This implementation forwards to the {@link #containsLong(long)} method.
*
* @param value the long to test, may be null
* @return true
if the specified number occurs within this
* range by long
comparison
*/
public boolean containsLong(Number value) {
if (value == null) {
return false;
}
return containsLong(value.longValue());
}
/**
* Tests whether the specified long
occurs within
* this range using long
comparison.
*
* This implementation uses the {@link #getMinimumLong()} and
* {@link #getMaximumLong()} methods and should be good for most uses.
*
* @param value the long to test
* @return true
if the specified number occurs within this
* range by long
comparison
*/
public boolean containsLong(long value) {
return value >= getMinimumLong() && value <= getMaximumLong();
}
/**
* Tests whether the specified Number
occurs within
* this range using int
comparison..
*
* null
is handled and returns false
.
*
* This implementation forwards to the {@link #containsInteger(int)} method.
*
* @param value the integer to test, may be null
* @return true
if the specified number occurs within this
* range by int
comparison
*/
public boolean containsInteger(Number value) {
if (value == null) {
return false;
}
return containsInteger(value.intValue());
}
/**
* Tests whether the specified int
occurs within
* this range using int
comparison.
*
* This implementation uses the {@link #getMinimumInteger()} and
* {@link #getMaximumInteger()} methods and should be good for most uses.
*
* @param value the int to test
* @return true
if the specified number occurs within this
* range by int
comparison
*/
public boolean containsInteger(int value) {
return value >= getMinimumInteger() && value <= getMaximumInteger();
}
/**
* Tests whether the specified Number
occurs within
* this range using double
comparison..
*
* null
is handled and returns false
.
*
* This implementation forwards to the {@link #containsDouble(double)} method.
*
* @param value the double to test, may be null
* @return true
if the specified number occurs within this
* range by double
comparison
*/
public boolean containsDouble(Number value) {
if (value == null) {
return false;
}
return containsDouble(value.doubleValue());
}
/**
* Tests whether the specified double
occurs within
* this range using double
comparison.
*
* This implementation uses the {@link #getMinimumDouble()} and
* {@link #getMaximumDouble()} methods and should be good for most uses.
*
* @param value the double to test
* @return true
if the specified number occurs within this
* range by double
comparison
*/
public boolean containsDouble(double value) {
int compareMin = NumberUtils.compare(getMinimumDouble(), value);
int compareMax = NumberUtils.compare(getMaximumDouble(), value);
return compareMin <= 0 && compareMax >= 0;
}
/**
* Tests whether the specified Number
occurs within
* this range using float
comparison.
*
* null
is handled and returns false
.
*
* This implementation forwards to the {@link #containsFloat(float)} method.
*
* @param value the float to test, may be null
* @return true
if the specified number occurs within this
* range by float
comparison
*/
public boolean containsFloat(Number value) {
if (value == null) {
return false;
}
return containsFloat(value.floatValue());
}
/**
* Tests whether the specified float
occurs within
* this range using float
comparison.
*
* This implementation uses the {@link #getMinimumFloat()} and
* {@link #getMaximumFloat()} methods and should be good for most uses.
*
* @param value the float to test
* @return true
if the specified number occurs within this
* range by float
comparison
*/
public boolean containsFloat(float value) {
int compareMin = NumberUtils.compare(getMinimumFloat(), value);
int compareMax = NumberUtils.compare(getMaximumFloat(), value);
return compareMin <= 0 && compareMax >= 0;
}
// Range tests
//--------------------------------------------------------------------
/**
* Tests whether the specified range occurs entirely within this range.
*
* The exact comparison implementation varies by subclass. It is
* intended that an int
specific subclass will compare using
* int
comparison.
*
* null
is handled and returns false
.
*
* This implementation uses the {@link #containsNumber(Number)} method.
* Subclasses may be able to optimise this.
*
* @param range the range to test, may be null
* @return true
if the specified range occurs entirely within
* this range; otherwise, false
* @throws IllegalArgumentException if the Range
cannot be compared
*/
public boolean containsRange(Range range) {
if (range == null) {
return false;
}
return containsNumber(range.getMinimumNumber())
&& containsNumber(range.getMaximumNumber());
}
/**
* Tests whether the specified range overlaps with this range.
*
* The exact comparison implementation varies by subclass. It is
* intended that an int
specific subclass will compare using
* int
comparison.
*
* null
is handled and returns false
.
*
* This implementation uses the {@link #containsNumber(Number)} and
* {@link #containsRange(Range)} methods.
* Subclasses may be able to optimise this.
*
* @param range the range to test, may be null
* @return true
if the specified range overlaps with this
* range; otherwise, false
* @throws IllegalArgumentException if the Range
cannot be compared
*/
public boolean overlapsRange(Range range) {
if (range == null) {
return false;
}
return range.containsNumber(getMinimumNumber())
|| range.containsNumber(getMaximumNumber())
|| containsNumber(range.getMinimumNumber());
}
// Basics
//--------------------------------------------------------------------
/**
* Compares this range to another object to test if they are equal.
.
*
* To be equal, the class, minimum and maximum must be equal.
*
* This implementation uses the {@link #getMinimumNumber()} and
* {@link #getMaximumNumber()} methods.
* Subclasses may be able to optimise this.
*
* @param obj the reference object with which to compare
* @return true
if this object is equal
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj == null || obj.getClass() != getClass()) {
return false;
} else {
Range range = (Range) obj;
return getMinimumNumber().equals(range.getMinimumNumber()) &&
getMaximumNumber().equals(range.getMaximumNumber());
}
}
/**
* Gets a hashCode for the range.
*
* This implementation uses the {@link #getMinimumNumber()} and
* {@link #getMaximumNumber()} methods.
* Subclasses may be able to optimise this.
*
* @return a hash code value for this object
*/
public int hashCode() {
int result = 17;
result = 37 * result + getClass().hashCode();
result = 37 * result + getMinimumNumber().hashCode();
result = 37 * result + getMaximumNumber().hashCode();
return result;
}
/**
* Gets the range as a String
.
*
* The format of the String is 'Range[min,max]'.
*
* This implementation uses the {@link #getMinimumNumber()} and
* {@link #getMaximumNumber()} methods.
* Subclasses may be able to optimise this.
*
* @return the String
representation of this range
*/
public String toString() {
StrBuilder buf = new StrBuilder(32);
buf.append("Range[");
buf.append(getMinimumNumber());
buf.append(',');
buf.append(getMaximumNumber());
buf.append(']');
return buf.toString();
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/mutable/Mutable.java 100644 0 0 3754 11513702444 24626 0 ustar 0 0 /*
* 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.lang.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.
*
* @author Apache Software Foundation
* @author Matthew Hawthorne
* @since 2.1
* @version $Id: Mutable.java 905636 2010-02-02 14:03:32Z niallp $
*/
public interface Mutable {
/**
* Gets the value of this mutable.
*
* @return the stored value
*/
Object getValue();
/**
* Sets the value of this mutable.
*
* @param value
* the value to store
* @throws NullPointerException
* if the object is null and null is invalid
* @throws ClassCastException
* if the type is invalid
*/
void setValue(Object value);
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/mutable/MutableBoolean.java 100644 0 0 13653 11513702444 26145 0 ustar 0 0 /*
* 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.lang.mutable;
import java.io.Serializable;
import org.apache.commons.lang.BooleanUtils;
/**
* A mutable boolean
wrapper.
*
* @see Boolean
* @since 2.2
* @author Apache Software Foundation
* @version $Id: MutableBoolean.java 905707 2010-02-02 16:59:59Z niallp $
*/
public class MutableBoolean implements Mutable, Serializable, Comparable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = -4830728138360036487L;
/** The mutable value. */
private boolean value;
/**
* Constructs a new MutableBoolean with the default value of false.
*/
public MutableBoolean() {
super();
}
/**
* Constructs a new MutableBoolean with the specified value.
*
* @param value the initial value to store
*/
public MutableBoolean(boolean value) {
super();
this.value = value;
}
/**
* Constructs a new MutableBoolean with the specified value.
*
* @param value the initial value to store, not null
* @throws NullPointerException if the object is null
*/
public MutableBoolean(Boolean value) {
super();
this.value = value.booleanValue();
}
//-----------------------------------------------------------------------
/**
* Gets the value as a Boolean instance.
*
* @return the value as a Boolean, never null
*/
public Object getValue() {
return BooleanUtils.toBooleanObject(this.value);
}
/**
* Sets the value.
*
* @param value the value to set
*/
public void setValue(boolean value) {
this.value = value;
}
/**
* Sets the value from any Boolean instance.
*
* @param value the value to set, not null
* @throws NullPointerException if the object is null
*/
public void setValue(Object value) {
setValue(((Boolean) value).booleanValue());
}
//-----------------------------------------------------------------------
/**
* Checks if the current value is 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 BooleanUtils.toBooleanObject(this.value);
}
//-----------------------------------------------------------------------
/**
* 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.
*/
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
*/
public int hashCode() {
return value ? Boolean.TRUE.hashCode() : Boolean.FALSE.hashCode();
}
//-----------------------------------------------------------------------
/**
* Compares this mutable to another in ascending order.
*
* @param obj 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(Object obj) {
MutableBoolean other = (MutableBoolean) obj;
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
*/
public String toString() {
return String.valueOf(value);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/mutable/MutableByte.java 100644 0 0 20042 11513702444 25457 0 ustar 0 0 /*
* 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.lang.mutable;
/**
* A mutable byte
wrapper.
*
* @see Byte
* @since 2.1
* @author Apache Software Foundation
* @version $Id: MutableByte.java 905707 2010-02-02 16:59:59Z niallp $
*/
public class MutableByte extends Number implements Comparable, Mutable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = -1585823265L;
/** The mutable value. */
private byte value;
/**
* Constructs a new MutableByte with the default value of zero.
*/
public MutableByte() {
super();
}
/**
* Constructs a new MutableByte with the specified value.
*
* @param value the initial value to store
*/
public MutableByte(byte value) {
super();
this.value = value;
}
/**
* Constructs a new MutableByte with the specified value.
*
* @param value the initial value to store, not null
* @throws NullPointerException if the object is null
*/
public MutableByte(Number value) {
super();
this.value = value.byteValue();
}
/**
* Constructs a new MutableByte parsing the given string.
*
* @param value the string to parse, not null
* @throws NumberFormatException if the string cannot be parsed into a byte
* @since 2.5
*/
public MutableByte(String value) throws NumberFormatException {
super();
this.value = Byte.parseByte(value);
}
//-----------------------------------------------------------------------
/**
* Gets the value as a Byte instance.
*
* @return the value as a Byte, never null
*/
public Object getValue() {
return new Byte(this.value);
}
/**
* Sets the value.
*
* @param value the value to set
*/
public void setValue(byte value) {
this.value = value;
}
/**
* Sets the value from any Number instance.
*
* @param value the value to set, not null
* @throws NullPointerException if the object is null
* @throws ClassCastException if the type is not a {@link Number}
*/
public void setValue(Object value) {
setValue(((Number) value).byteValue());
}
//-----------------------------------------------------------------------
/**
* Increments the value.
*
* @since Commons Lang 2.2
*/
public void increment() {
value++;
}
/**
* Decrements the value.
*
* @since Commons Lang 2.2
*/
public void decrement() {
value--;
}
//-----------------------------------------------------------------------
/**
* Adds a value to the value of this instance.
*
* @param operand the value to add, not null
* @since Commons Lang 2.2
*/
public void add(byte operand) {
this.value += operand;
}
/**
* Adds a value to the value of this instance.
*
* @param operand the value to add, not null
* @throws NullPointerException if the object is null
* @since Commons Lang 2.2
*/
public void add(Number operand) {
this.value += operand.byteValue();
}
/**
* Subtracts a value from the value of this instance.
*
* @param operand the value to subtract, not null
* @since Commons Lang 2.2
*/
public void subtract(byte operand) {
this.value -= operand;
}
/**
* Subtracts a value from the value of this instance.
*
* @param operand the value to subtract, not null
* @throws NullPointerException if the object is null
* @since Commons Lang 2.2
*/
public void subtract(Number operand) {
this.value -= operand.byteValue();
}
//-----------------------------------------------------------------------
// shortValue relies on Number implementation
/**
* Returns the value of this MutableByte as a byte.
*
* @return the numeric value represented by this object after conversion to type byte.
*/
public byte byteValue() {
return value;
}
/**
* Returns the value of this MutableByte as an int.
*
* @return the numeric value represented by this object after conversion to type int.
*/
public int intValue() {
return value;
}
/**
* Returns the value of this MutableByte as a long.
*
* @return the numeric value represented by this object after conversion to type long.
*/
public long longValue() {
return value;
}
/**
* Returns the value of this MutableByte as a float.
*
* @return the numeric value represented by this object after conversion to type float.
*/
public float floatValue() {
return value;
}
/**
* Returns the value of this MutableByte as a double.
*
* @return the numeric value represented by this object after conversion to type double.
*/
public double doubleValue() {
return value;
}
//-----------------------------------------------------------------------
/**
* Gets this mutable as an instance of Byte.
*
* @return a Byte instance containing the value from this mutable
*/
public Byte toByte() {
return new Byte(byteValue());
}
//-----------------------------------------------------------------------
/**
* Compares this object to the specified object. The result is 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.
*/
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
*/
public int hashCode() {
return value;
}
//-----------------------------------------------------------------------
/**
* Compares this mutable to another in ascending order.
*
* @param obj the other mutable to compare to, not null
* @return negative if this is less, zero if equal, positive if greater
* @throws ClassCastException if the argument is not a MutableByte
*/
public int compareTo(Object obj) {
MutableByte other = (MutableByte) obj;
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
*/
public String toString() {
return String.valueOf(value);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/mutable/MutableDouble.java 100644 0 0 23430 11513702444 25772 0 ustar 0 0 /*
* 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.lang.mutable;
import org.apache.commons.lang.math.NumberUtils;
/**
* A mutable double
wrapper.
*
* @see Double
* @since 2.1
* @author Apache Software Foundation
* @version $Id: MutableDouble.java 905707 2010-02-02 16:59:59Z niallp $
*/
public class MutableDouble extends Number implements Comparable, Mutable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 1587163916L;
/** The mutable value. */
private double value;
/**
* Constructs a new MutableDouble with the default value of zero.
*/
public MutableDouble() {
super();
}
/**
* Constructs a new MutableDouble with the specified value.
*
* @param value the initial value to store
*/
public MutableDouble(double value) {
super();
this.value = value;
}
/**
* Constructs a new MutableDouble with the specified value.
*
* @param value the initial value to store, not null
* @throws NullPointerException if the object is null
*/
public MutableDouble(Number value) {
super();
this.value = value.doubleValue();
}
/**
* Constructs a new MutableDouble parsing the given string.
*
* @param value the string to parse, not null
* @throws NumberFormatException if the string cannot be parsed into a double
* @since 2.5
*/
public MutableDouble(String value) throws NumberFormatException {
super();
this.value = Double.parseDouble(value);
}
//-----------------------------------------------------------------------
/**
* Gets the value as a Double instance.
*
* @return the value as a Double, never null
*/
public Object getValue() {
return new Double(this.value);
}
/**
* Sets the value.
*
* @param value the value to set
*/
public void setValue(double value) {
this.value = value;
}
/**
* Sets the value from any Number instance.
*
* @param value the value to set, not null
* @throws NullPointerException if the object is null
* @throws ClassCastException if the type is not a {@link Number}
*/
public void setValue(Object value) {
setValue(((Number) value).doubleValue());
}
//-----------------------------------------------------------------------
/**
* Checks whether the double value is the special NaN value.
*
* @return true if NaN
*/
public boolean isNaN() {
return Double.isNaN(value);
}
/**
* Checks whether the double value is infinite.
*
* @return true if infinite
*/
public boolean isInfinite() {
return Double.isInfinite(value);
}
//-----------------------------------------------------------------------
/**
* Increments the value.
*
* @since Commons Lang 2.2
*/
public void increment() {
value++;
}
/**
* Decrements the value.
*
* @since Commons Lang 2.2
*/
public void decrement() {
value--;
}
//-----------------------------------------------------------------------
/**
* Adds a value to the value of this instance.
*
* @param operand the value to add
* @since Commons Lang 2.2
*/
public void add(double operand) {
this.value += operand;
}
/**
* Adds a value to the value of this instance.
*
* @param operand the value to add, not null
* @throws NullPointerException if the object is null
* @since Commons Lang 2.2
*/
public void add(Number operand) {
this.value += operand.doubleValue();
}
/**
* Subtracts a value from the value of this instance.
*
* @param operand the value to subtract, not null
* @since Commons Lang 2.2
*/
public void subtract(double operand) {
this.value -= operand;
}
/**
* Subtracts a value from the value of this instance.
*
* @param operand the value to subtract, not null
* @throws NullPointerException if the object is null
* @since Commons Lang 2.2
*/
public void subtract(Number operand) {
this.value -= operand.doubleValue();
}
//-----------------------------------------------------------------------
// shortValue and bytValue rely on Number implementation
/**
* Returns the value of this MutableDouble as an int.
*
* @return the numeric value represented by this object after conversion to type int.
*/
public int intValue() {
return (int) value;
}
/**
* Returns the value of this MutableDouble as a long.
*
* @return the numeric value represented by this object after conversion to type long.
*/
public long longValue() {
return (long) value;
}
/**
* Returns the value of this MutableDouble as a float.
*
* @return the numeric value represented by this object after conversion to type float.
*/
public float floatValue() {
return (float) value;
}
/**
* Returns the value of this MutableDouble as a double.
*
* @return the numeric value represented by this object after conversion to type double.
*/
public double doubleValue() {
return value;
}
//-----------------------------------------------------------------------
/**
* Gets this mutable as an instance of Double.
*
* @return a Double instance containing the value from this mutable, never null
*/
public Double toDouble() {
return new Double(doubleValue());
}
//-----------------------------------------------------------------------
/**
* Compares this object against the specified object. The result is 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.
*
* Note that in most cases, for two instances of class Double
,d1
and d2
,
* the value of d1.equals(d2)
is true
if and only if
*
*
* d1.doubleValue() == d2.doubleValue()
*
*
*
*
* also has the value true
. However, there are two exceptions:
*
* - If
d1
and d2
both represent Double.NaN
, then the
* equals
method returns true
, even though Double.NaN==Double.NaN
has
* the value false
.
* - If
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.
*
*
* @param obj the object to compare with, null returns false
* @return true
if the objects are the same; false
otherwise.
*/
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
*/
public int hashCode() {
long bits = Double.doubleToLongBits(value);
return (int) (bits ^ (bits >>> 32));
}
//-----------------------------------------------------------------------
/**
* Compares this mutable to another in ascending order.
*
* @param obj the other mutable to compare to, not null
* @return negative if this is less, zero if equal, positive if greater
* @throws ClassCastException if the argument is not a MutableDouble
*/
public int compareTo(Object obj) {
MutableDouble other = (MutableDouble) obj;
double anotherVal = other.value;
return NumberUtils.compare(value, anotherVal);
}
//-----------------------------------------------------------------------
/**
* Returns the String value of this mutable.
*
* @return the mutable value as a string
*/
public String toString() {
return String.valueOf(value);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/mutable/MutableFloat.java 100644 0 0 23233 11513702444 25626 0 ustar 0 0 /*
* 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.lang.mutable;
import org.apache.commons.lang.math.NumberUtils;
/**
* A mutable float
wrapper.
*
* @see Float
* @since 2.1
* @author Apache Software Foundation
* @version $Id: MutableFloat.java 905707 2010-02-02 16:59:59Z niallp $
*/
public class MutableFloat extends Number implements Comparable, Mutable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 5787169186L;
/** The mutable value. */
private float value;
/**
* Constructs a new MutableFloat with the default value of zero.
*/
public MutableFloat() {
super();
}
/**
* Constructs a new MutableFloat with the specified value.
*
* @param value the initial value to store
*/
public MutableFloat(float value) {
super();
this.value = value;
}
/**
* Constructs a new MutableFloat with the specified value.
*
* @param value the initial value to store, not null
* @throws NullPointerException if the object is null
*/
public MutableFloat(Number value) {
super();
this.value = value.floatValue();
}
/**
* Constructs a new MutableFloat parsing the given string.
*
* @param value the string to parse, not null
* @throws NumberFormatException if the string cannot be parsed into a float
* @since 2.5
*/
public MutableFloat(String value) throws NumberFormatException {
super();
this.value = Float.parseFloat(value);
}
//-----------------------------------------------------------------------
/**
* Gets the value as a Float instance.
*
* @return the value as a Float, never null
*/
public Object getValue() {
return new Float(this.value);
}
/**
* Sets the value.
*
* @param value the value to set
*/
public void setValue(float value) {
this.value = value;
}
/**
* Sets the value from any Number instance.
*
* @param value the value to set, not null
* @throws NullPointerException if the object is null
* @throws ClassCastException if the type is not a {@link Number}
*/
public void setValue(Object value) {
setValue(((Number) value).floatValue());
}
//-----------------------------------------------------------------------
/**
* Checks whether the float value is the special NaN value.
*
* @return true if NaN
*/
public boolean isNaN() {
return Float.isNaN(value);
}
/**
* Checks whether the float value is infinite.
*
* @return true if infinite
*/
public boolean isInfinite() {
return Float.isInfinite(value);
}
//-----------------------------------------------------------------------
/**
* Increments the value.
*
* @since Commons Lang 2.2
*/
public void increment() {
value++;
}
/**
* Decrements the value.
*
* @since Commons Lang 2.2
*/
public void decrement() {
value--;
}
//-----------------------------------------------------------------------
/**
* Adds a value to the value of this instance.
*
* @param operand the value to add, not null
* @since Commons Lang 2.2
*/
public void add(float operand) {
this.value += operand;
}
/**
* Adds a value to the value of this instance.
*
* @param operand the value to add, not null
* @throws NullPointerException if the object is null
* @since Commons Lang 2.2
*/
public void add(Number operand) {
this.value += operand.floatValue();
}
/**
* Subtracts a value from the value of this instance.
*
* @param operand the value to subtract
* @since Commons Lang 2.2
*/
public void subtract(float operand) {
this.value -= operand;
}
/**
* Subtracts a value from the value of this instance.
*
* @param operand the value to subtract, not null
* @throws NullPointerException if the object is null
* @since Commons Lang 2.2
*/
public void subtract(Number operand) {
this.value -= operand.floatValue();
}
//-----------------------------------------------------------------------
// shortValue and bytValue rely on Number implementation
/**
* Returns the value of this MutableFloat as an int.
*
* @return the numeric value represented by this object after conversion to type int.
*/
public int intValue() {
return (int) value;
}
/**
* Returns the value of this MutableFloat as a long.
*
* @return the numeric value represented by this object after conversion to type long.
*/
public long longValue() {
return (long) value;
}
/**
* Returns the value of this MutableFloat as a float.
*
* @return the numeric value represented by this object after conversion to type float.
*/
public float floatValue() {
return value;
}
/**
* Returns the value of this MutableFloat as a double.
*
* @return the numeric value represented by this object after conversion to type double.
*/
public double doubleValue() {
return value;
}
//-----------------------------------------------------------------------
/**
* Gets this mutable as an instance of Float.
*
* @return a Float instance containing the value from this mutable, never null
*/
public Float toFloat() {
return new Float(floatValue());
}
//-----------------------------------------------------------------------
/**
* Compares this object against some other object. The result is true
if and only if the argument is
* not null
and is a Float
object that represents a float
that has the
* identical bit pattern to the bit pattern of the float
represented by this object. For this
* purpose, two float values are considered to be the same if and only if the method
* {@link Float#floatToIntBits(float)}returns the same int value when applied to each.
*
* Note that in most cases, for two instances of class Float
,f1
and f2
,
* the value of f1.equals(f2)
is true
if and only if
*
*
* f1.floatValue() == f2.floatValue()
*
*
*
*
* also has the value true
. However, there are two exceptions:
*
* - If
f1
and f2
both represent Float.NaN
, then the
* equals
method returns true
, even though Float.NaN==Float.NaN
has
* the value false
.
* - If
f1
represents +0.0f
while f2
represents -0.0f
,
* or vice versa, the equal
test has the value false
, even though
* 0.0f==-0.0f
has the value true
.
*
* This definition allows hashtables to operate properly.
*
* @param obj the object to compare with, null returns false
* @return true
if the objects are the same; false
otherwise.
* @see java.lang.Float#floatToIntBits(float)
*/
public boolean equals(Object obj) {
return (obj instanceof MutableFloat)
&& (Float.floatToIntBits(((MutableFloat) obj).value) == Float.floatToIntBits(value));
}
/**
* Returns a suitable hash code for this mutable.
*
* @return a suitable hash code
*/
public int hashCode() {
return Float.floatToIntBits(value);
}
//-----------------------------------------------------------------------
/**
* Compares this mutable to another in ascending order.
*
* @param obj the other mutable to compare to, not null
* @return negative if this is less, zero if equal, positive if greater
*/
public int compareTo(Object obj) {
MutableFloat other = (MutableFloat) obj;
float anotherVal = other.value;
return NumberUtils.compare(value, anotherVal);
}
//-----------------------------------------------------------------------
/**
* Returns the String value of this mutable.
*
* @return the mutable value as a string
*/
public String toString() {
return String.valueOf(value);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/mutable/MutableInt.java 100644 0 0 17507 11513702444 25322 0 ustar 0 0 /*
* 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.lang.mutable;
/**
* A mutable int
wrapper.
*
* @see Integer
* @since 2.1
* @author Apache Software Foundation
* @version $Id: MutableInt.java 905707 2010-02-02 16:59:59Z niallp $
*/
public class MutableInt extends Number implements Comparable, Mutable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 512176391864L;
/** The mutable value. */
private int value;
/**
* Constructs a new MutableInt with the default value of zero.
*/
public MutableInt() {
super();
}
/**
* Constructs a new MutableInt with the specified value.
*
* @param value the initial value to store
*/
public MutableInt(int value) {
super();
this.value = value;
}
/**
* Constructs a new MutableInt with the specified value.
*
* @param value the initial value to store, not null
* @throws NullPointerException if the object is null
*/
public MutableInt(Number value) {
super();
this.value = value.intValue();
}
/**
* Constructs a new MutableInt parsing the given string.
*
* @param value the string to parse, not null
* @throws NumberFormatException if the string cannot be parsed into an int
* @since 2.5
*/
public MutableInt(String value) throws NumberFormatException {
super();
this.value = Integer.parseInt(value);
}
//-----------------------------------------------------------------------
/**
* Gets the value as a Integer instance.
*
* @return the value as a Integer, never null
*/
public Object getValue() {
return new Integer(this.value);
}
/**
* Sets the value.
*
* @param value the value to set
*/
public void setValue(int value) {
this.value = value;
}
/**
* Sets the value from any Number instance.
*
* @param value the value to set, not null
* @throws NullPointerException if the object is null
* @throws ClassCastException if the type is not a {@link Number}
*/
public void setValue(Object value) {
setValue(((Number) value).intValue());
}
//-----------------------------------------------------------------------
/**
* Increments the value.
*
* @since Commons Lang 2.2
*/
public void increment() {
value++;
}
/**
* Decrements the value.
*
* @since Commons Lang 2.2
*/
public void decrement() {
value--;
}
//-----------------------------------------------------------------------
/**
* Adds a value to the value of this instance.
*
* @param operand the value to add, not null
* @since Commons Lang 2.2
*/
public void add(int operand) {
this.value += operand;
}
/**
* Adds a value to the value of this instance.
*
* @param operand the value to add, not null
* @throws NullPointerException if the object is null
* @since Commons Lang 2.2
*/
public void add(Number operand) {
this.value += operand.intValue();
}
/**
* Subtracts a value from the value of this instance.
*
* @param operand the value to subtract, not null
* @since Commons Lang 2.2
*/
public void subtract(int operand) {
this.value -= operand;
}
/**
* Subtracts a value from the value of this instance.
*
* @param operand the value to subtract, not null
* @throws NullPointerException if the object is null
* @since Commons Lang 2.2
*/
public void subtract(Number operand) {
this.value -= operand.intValue();
}
//-----------------------------------------------------------------------
// shortValue and bytValue rely on Number implementation
/**
* Returns the value of this MutableInt as an int.
*
* @return the numeric value represented by this object after conversion to type int.
*/
public int intValue() {
return value;
}
/**
* Returns the value of this MutableInt as a long.
*
* @return the numeric value represented by this object after conversion to type long.
*/
public long longValue() {
return value;
}
/**
* Returns the value of this MutableInt as a float.
*
* @return the numeric value represented by this object after conversion to type float.
*/
public float floatValue() {
return value;
}
/**
* Returns the value of this MutableInt as a double.
*
* @return the numeric value represented by this object after conversion to type double.
*/
public double doubleValue() {
return value;
}
//-----------------------------------------------------------------------
/**
* Gets this mutable as an instance of Integer.
*
* @return a Integer instance containing the value from this mutable, never null
*/
public Integer toInteger() {
return new Integer(intValue());
}
//-----------------------------------------------------------------------
/**
* Compares this object to the specified object. The result is true
if and only if the argument is
* not null
and is a MutableInt
object that contains the same int
value
* as this object.
*
* @param obj the object to compare with, null returns false
* @return true
if the objects are the same; false
otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof MutableInt) {
return value == ((MutableInt) obj).intValue();
}
return false;
}
/**
* Returns a suitable hash code for this mutable.
*
* @return a suitable hash code
*/
public int hashCode() {
return value;
}
//-----------------------------------------------------------------------
/**
* Compares this mutable to another in ascending order.
*
* @param obj the other mutable to compare to, not null
* @return negative if this is less, zero if equal, positive if greater
* @throws ClassCastException if the argument is not a MutableInt
*/
public int compareTo(Object obj) {
MutableInt other = (MutableInt) obj;
int 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
*/
public String toString() {
return String.valueOf(value);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/mutable/MutableLong.java 100644 0 0 17552 11513702444 25467 0 ustar 0 0 /*
* 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.lang.mutable;
/**
* A mutable long
wrapper.
*
* @see Long
* @since 2.1
* @author Apache Software Foundation
* @version $Id: MutableLong.java 905707 2010-02-02 16:59:59Z niallp $
*/
public class MutableLong extends Number implements Comparable, Mutable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 62986528375L;
/** The mutable value. */
private long value;
/**
* Constructs a new MutableLong with the default value of zero.
*/
public MutableLong() {
super();
}
/**
* Constructs a new MutableLong with the specified value.
*
* @param value the initial value to store
*/
public MutableLong(long value) {
super();
this.value = value;
}
/**
* Constructs a new MutableLong with the specified value.
*
* @param value the initial value to store, not null
* @throws NullPointerException if the object is null
*/
public MutableLong(Number value) {
super();
this.value = value.longValue();
}
/**
* Constructs a new MutableLong parsing the given string.
*
* @param value the string to parse, not null
* @throws NumberFormatException if the string cannot be parsed into a long
* @since 2.5
*/
public MutableLong(String value) throws NumberFormatException {
super();
this.value = Long.parseLong(value);
}
//-----------------------------------------------------------------------
/**
* Gets the value as a Long instance.
*
* @return the value as a Long, never null
*/
public Object getValue() {
return new Long(this.value);
}
/**
* Sets the value.
*
* @param value the value to set
*/
public void setValue(long value) {
this.value = value;
}
/**
* Sets the value from any Number instance.
*
* @param value the value to set, not null
* @throws NullPointerException if the object is null
* @throws ClassCastException if the type is not a {@link Number}
*/
public void setValue(Object value) {
setValue(((Number) value).longValue());
}
//-----------------------------------------------------------------------
/**
* Increments the value.
*
* @since Commons Lang 2.2
*/
public void increment() {
value++;
}
/**
* Decrements the value.
*
* @since Commons Lang 2.2
*/
public void decrement() {
value--;
}
//-----------------------------------------------------------------------
/**
* Adds a value to the value of this instance.
*
* @param operand the value to add, not null
* @since Commons Lang 2.2
*/
public void add(long operand) {
this.value += operand;
}
/**
* Adds a value to the value of this instance.
*
* @param operand the value to add, not null
* @throws NullPointerException if the object is null
* @since Commons Lang 2.2
*/
public void add(Number operand) {
this.value += operand.longValue();
}
/**
* Subtracts a value from the value of this instance.
*
* @param operand the value to subtract, not null
* @since Commons Lang 2.2
*/
public void subtract(long operand) {
this.value -= operand;
}
/**
* Subtracts a value from the value of this instance.
*
* @param operand the value to subtract, not null
* @throws NullPointerException if the object is null
* @since Commons Lang 2.2
*/
public void subtract(Number operand) {
this.value -= operand.longValue();
}
//-----------------------------------------------------------------------
// shortValue and bytValue rely on Number implementation
/**
* Returns the value of this MutableLong as an int.
*
* @return the numeric value represented by this object after conversion to type int.
*/
public int intValue() {
return (int) value;
}
/**
* Returns the value of this MutableLong as a long.
*
* @return the numeric value represented by this object after conversion to type long.
*/
public long longValue() {
return value;
}
/**
* Returns the value of this MutableLong as a float.
*
* @return the numeric value represented by this object after conversion to type float.
*/
public float floatValue() {
return value;
}
/**
* Returns the value of this MutableLong as a double.
*
* @return the numeric value represented by this object after conversion to type double.
*/
public double doubleValue() {
return value;
}
//-----------------------------------------------------------------------
/**
* Gets this mutable as an instance of Long.
*
* @return a Long instance containing the value from this mutable, never null
*/
public Long toLong() {
return new Long(longValue());
}
//-----------------------------------------------------------------------
/**
* Compares this object to the specified object. The result is true
if and only if the argument
* is not null
and is a MutableLong
object that contains the same long
* value as this object.
*
* @param obj the object to compare with, null returns false
* @return true
if the objects are the same; false
otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof MutableLong) {
return value == ((MutableLong) obj).longValue();
}
return false;
}
/**
* Returns a suitable hash code for this mutable.
*
* @return a suitable hash code
*/
public int hashCode() {
return (int) (value ^ (value >>> 32));
}
//-----------------------------------------------------------------------
/**
* Compares this mutable to another in ascending order.
*
* @param obj the other mutable to compare to, not null
* @return negative if this is less, zero if equal, positive if greater
* @throws ClassCastException if the argument is not a MutableLong
*/
public int compareTo(Object obj) {
MutableLong other = (MutableLong) obj;
long 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
*/
public String toString() {
return String.valueOf(value);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/mutable/MutableObject.java 100644 0 0 7007 11513702444 25750 0 ustar 0 0 /*
* 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.lang.mutable;
import java.io.Serializable;
/**
* A mutable Object
wrapper.
*
* @since 2.1
* @author Apache Software Foundation
* @version $Id: MutableObject.java 905636 2010-02-02 14:03:32Z niallp $
*/
public class MutableObject implements Mutable, Serializable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 86241875189L;
/** The mutable value. */
private Object value;
/**
* Constructs a new MutableObject with the default value of null
.
*/
public MutableObject() {
super();
}
/**
* Constructs a new MutableObject with the specified value.
*
* @param value the initial value to store
*/
public MutableObject(Object value) {
super();
this.value = value;
}
//-----------------------------------------------------------------------
/**
* Gets the value.
*
* @return the value, may be null
*/
public Object getValue() {
return this.value;
}
/**
* Sets the value.
*
* @param value the value to set
*/
public void setValue(Object value) {
this.value = value;
}
//-----------------------------------------------------------------------
/**
* Compares this object against the specified object. The result is true
if and only if the argument
* is not null
and is a MutableObject
object that contains the same Object
* value as this object.
*
* @param obj the object to compare with, null returns false
* @return true
if the objects are the same; false
otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof MutableObject) {
Object other = ((MutableObject) obj).value;
return value == other || (value != null && value.equals(other));
}
return false;
}
/**
* Returns the value's hash code or 0
if the value is null
.
*
* @return the value's hash code or 0
if the value is null
.
*/
public int hashCode() {
return value == null ? 0 : value.hashCode();
}
//-----------------------------------------------------------------------
/**
* Returns the String value of this mutable.
*
* @return the mutable value as a string
*/
public String toString() {
return value == null ? "null" : value.toString();
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/mutable/MutableShort.java 100644 0 0 20137 11513702444 25660 0 ustar 0 0 /*
* 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.lang.mutable;
/**
* A mutable short
wrapper.
*
* @see Short
* @since 2.1
* @author Apache Software Foundation
* @version $Id: MutableShort.java 905707 2010-02-02 16:59:59Z niallp $
*/
public class MutableShort extends Number implements Comparable, Mutable {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = -2135791679L;
/** The mutable value. */
private short value;
/**
* Constructs a new MutableShort with the default value of zero.
*/
public MutableShort() {
super();
}
/**
* Constructs a new MutableShort with the specified value.
*
* @param value the initial value to store
*/
public MutableShort(short value) {
super();
this.value = value;
}
/**
* Constructs a new MutableShort with the specified value.
*
* @param value the initial value to store, not null
* @throws NullPointerException if the object is null
*/
public MutableShort(Number value) {
super();
this.value = value.shortValue();
}
/**
* Constructs a new MutableShort parsing the given string.
*
* @param value the string to parse, not null
* @throws NumberFormatException if the string cannot be parsed into a short
* @since 2.5
*/
public MutableShort(String value) throws NumberFormatException {
super();
this.value = Short.parseShort(value);
}
//-----------------------------------------------------------------------
/**
* Gets the value as a Short instance.
*
* @return the value as a Short, never null
*/
public Object getValue() {
return new Short(this.value);
}
/**
* Sets the value.
*
* @param value the value to set
*/
public void setValue(short value) {
this.value = value;
}
/**
* Sets the value from any Number instance.
*
* @param value the value to set, not null
* @throws NullPointerException if the object is null
* @throws ClassCastException if the type is not a {@link Number}
*/
public void setValue(Object value) {
setValue(((Number) value).shortValue());
}
//-----------------------------------------------------------------------
/**
* Increments the value.
*
* @since Commons Lang 2.2
*/
public void increment() {
value++;
}
/**
* Decrements the value.
*
* @since Commons Lang 2.2
*/
public void decrement() {
value--;
}
//-----------------------------------------------------------------------
/**
* Adds a value to the value of this instance.
*
* @param operand the value to add, not null
* @since Commons Lang 2.2
*/
public void add(short operand) {
this.value += operand;
}
/**
* Adds a value to the value of this instance.
*
* @param operand the value to add, not null
* @throws NullPointerException if the object is null
* @since Commons Lang 2.2
*/
public void add(Number operand) {
this.value += operand.shortValue();
}
/**
* Subtracts a value from the value of this instance.
*
* @param operand the value to subtract, not null
* @since Commons Lang 2.2
*/
public void subtract(short operand) {
this.value -= operand;
}
/**
* Subtracts a value from the value of this instance.
*
* @param operand the value to subtract, not null
* @throws NullPointerException if the object is null
* @since Commons Lang 2.2
*/
public void subtract(Number operand) {
this.value -= operand.shortValue();
}
//-----------------------------------------------------------------------
// bytValue relies on Number implementation
/**
* Returns the value of this MutableShort as a short.
*
* @return the numeric value represented by this object after conversion to type short.
*/
public short shortValue() {
return value;
}
/**
* Returns the value of this MutableShort as an int.
*
* @return the numeric value represented by this object after conversion to type int.
*/
public int intValue() {
return value;
}
/**
* Returns the value of this MutableShort as a long.
*
* @return the numeric value represented by this object after conversion to type long.
*/
public long longValue() {
return value;
}
/**
* Returns the value of this MutableShort as a float.
*
* @return the numeric value represented by this object after conversion to type float.
*/
public float floatValue() {
return value;
}
/**
* Returns the value of this MutableShort as a double.
*
* @return the numeric value represented by this object after conversion to type double.
*/
public double doubleValue() {
return value;
}
//-----------------------------------------------------------------------
/**
* Gets this mutable as an instance of Short.
*
* @return a Short instance containing the value from this mutable, never null
*/
public Short toShort() {
return new Short(shortValue());
}
//-----------------------------------------------------------------------
/**
* Compares this object to the specified object. The result is true
if and only if the argument
* is not null
and is a MutableShort
object that contains the same short
* value as this object.
*
* @param obj the object to compare with, null returns false
* @return true
if the objects are the same; false
otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof MutableShort) {
return value == ((MutableShort) obj).shortValue();
}
return false;
}
/**
* Returns a suitable hash code for this mutable.
*
* @return a suitable hash code
*/
public int hashCode() {
return value;
}
//-----------------------------------------------------------------------
/**
* Compares this mutable to another in ascending order.
*
* @param obj the other mutable to compare to, not null
* @return negative if this is less, zero if equal, positive if greater
* @throws ClassCastException if the argument is not a MutableShort
*/
public int compareTo(Object obj) {
MutableShort other = (MutableShort) obj;
short 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
*/
public String toString() {
return String.valueOf(value);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/mutable/package.html 100644 0 0 2031 11513702444 24636 0 ustar 0 0
Provides typed mutable wrappers to primitive values and Object.
@since 2.1
These classes are not thread-safe.
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/NotImplementedException.java 100644 0 0 23330 11513702446 26421 0 ustar 0 0 /*
* 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.lang;
import java.io.PrintStream;
import java.io.PrintWriter;
import org.apache.commons.lang.exception.Nestable;
import org.apache.commons.lang.exception.NestableDelegate;
/**
* Thrown to indicate that a block of code has not been implemented.
* This exception supplements UnsupportedOperationException
* by providing a more semantically rich description of the problem.
*
* NotImplementedException
represents the case where the
* author has yet to implement the logic at this point in the program.
* This can act as an exception based TODO tag.
* Because this logic might be within a catch block, this exception
* suports exception chaining.
*
*
* public void foo() {
* try {
* // do something that throws an Exception
* } catch (Exception ex) {
* // don't know what to do here yet
* throw new NotImplementedException("TODO", ex);
* }
* }
*
*
* @author Apache Software Foundation
* @author Matthew Hawthorne
* @since 2.0
* @version $Id: NotImplementedException.java 905636 2010-02-02 14:03:32Z niallp $
*/
public class NotImplementedException
extends UnsupportedOperationException implements Nestable {
private static final String DEFAULT_MESSAGE = "Code is not implemented";
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = -6894122266938754088L;
/**
* The exception helper to delegate nested exception handling to.
*/
private NestableDelegate delegate = new NestableDelegate(this);
/**
* Holds the reference to the exception or error that caused
* this exception to be thrown.
*/
private Throwable cause;
//-----------------------------------------------------------------------
/**
* Constructs a new NotImplementedException
with default message.
*
* @since 2.1
*/
public NotImplementedException() {
super(DEFAULT_MESSAGE);
}
/**
* Constructs a new NotImplementedException
with specified
* detail message.
*
* @param msg the error message.
*/
public NotImplementedException(String msg) {
super(msg == null ? DEFAULT_MESSAGE : msg);
}
/**
* Constructs a new NotImplementedException
with specified
* nested Throwable
and default message.
*
* @param cause the exception that caused this exception to be thrown
* @since 2.1
*/
public NotImplementedException(Throwable cause) {
super(DEFAULT_MESSAGE);
this.cause = cause;
}
/**
* Constructs a new NotImplementedException
with specified
* detail message and nested Throwable
.
*
* @param msg the error message
* @param cause the exception that caused this exception to be thrown
* @since 2.1
*/
public NotImplementedException(String msg, Throwable cause) {
super(msg == null ? DEFAULT_MESSAGE : msg);
this.cause = cause;
}
/**
* Constructs a new NotImplementedException
referencing the specified class.
*
* @param clazz
* the Class
that has not implemented the method
*/
public NotImplementedException(Class clazz) {
super(clazz == null ? DEFAULT_MESSAGE : DEFAULT_MESSAGE + " in " + clazz);
}
// -----------------------------------------------------------------------
/**
* Gets the root cause of this exception.
* @return the root cause of this exception.
*
* @since 2.1
*/
public Throwable getCause() {
return cause;
}
/**
* Gets the combined the error message of this and any nested errors.
*
* @return the error message
* @since 2.1
*/
public String getMessage() {
if (super.getMessage() != null) {
return super.getMessage();
} else if (cause != null) {
return cause.toString();
} else {
return null;
}
}
/**
* Returns the error message of the Throwable
in the chain
* of Throwable
s at the specified index, numbered from 0.
*
* @param index the index of the Throwable
in the chain
* @return the error message, or null if the Throwable
at the
* specified index in the chain does not contain a message
* @throws IndexOutOfBoundsException if the index
argument is
* negative or not less than the count of Throwable
s in the chain
* @since 2.1
*/
public String getMessage(int index) {
if (index == 0) {
return super.getMessage();
}
return delegate.getMessage(index);
}
/**
* Returns the error message of this and any nested Throwable
objects.
* Each throwable returns a message, a null string is included in the array if
* there is no message for a particular Throwable
.
*
* @return the error messages
* @since 2.1
*/
public String[] getMessages() {
return delegate.getMessages();
}
/**
* Returns the Throwable
in the chain by index.
*
* @param index the index to retrieve
* @return the Throwable
* @throws IndexOutOfBoundsException if the index
argument is
* negative or not less than the count of Throwable
s in the chain
* @since 2.1
*/
public Throwable getThrowable(int index) {
return delegate.getThrowable(index);
}
/**
* Returns the number of nested Throwable
s represented by
* this Nestable
, including this Nestable
.
*
* @return the throwable count
* @since 2.1
*/
public int getThrowableCount() {
return delegate.getThrowableCount();
}
/**
* Returns this Nestable
and any nested Throwable
s
* in an array of Throwable
s, one element for each
* Throwable
.
*
* @return the Throwable
s
* @since 2.1
*/
public Throwable[] getThrowables() {
return delegate.getThrowables();
}
/**
* Returns the index of the first occurrence of the specified type.
* If there is no match, -1
is returned.
*
* @param type the type to search for
* @return index of the first occurrence of the type in the chain, or -1 if
* the type is not found
* @since 2.1
*/
public int indexOfThrowable(Class type) {
return delegate.indexOfThrowable(type, 0);
}
/**
* Returns the index of the first occurrence of the specified type starting
* from the specified index. If there is no match, -1
is returned.
*
* @param type the type to search for
* @param fromIndex the index of the starting position in the chain to be searched
* @return index of the first occurrence of the type in the chain, or -1 if
* the type is not found
* @throws IndexOutOfBoundsException if the fromIndex
argument
* is negative or not less than the count of Throwable
s in the chain
* @since 2.1
*/
public int indexOfThrowable(Class type, int fromIndex) {
return delegate.indexOfThrowable(type, fromIndex);
}
/**
* Prints the stack trace of this exception.
* Includes information from the exception, if any, which caused this exception.
*
* @since 2.1
*/
public void printStackTrace() {
delegate.printStackTrace();
}
/**
* Prints the stack trace of this exception to the specified stream.
* Includes information from the exception, if any, which caused this exception.
*
* @param out the stream to write to
* @since 2.1
*/
public void printStackTrace(PrintStream out) {
delegate.printStackTrace(out);
}
/**
* Prints the stack trace of this exception to the specified writer.
* Includes information from the exception, if any, which caused this exception.
*
* @param out the writer to write to
* @since 2.1
*/
public void printStackTrace(PrintWriter out) {
delegate.printStackTrace(out);
}
/**
* Prints the stack trace for this exception only (root cause not included)
* using the specified writer.
*
* @param out the writer to write to
* @since 2.1
*/
public final void printPartialStackTrace(PrintWriter out) {
super.printStackTrace(out);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/NullArgumentException.java 100644 0 0 4611 11513702445 26072 0 ustar 0 0 /*
* 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.lang;
/**
* Thrown to indicate that an argument was null
and should
* not have been.
* This exception supplements the standard IllegalArgumentException
* by providing a more semantically rich description of the problem.
*
* NullArgumentException
represents the case where a method takes
* in a parameter that must not be null
.
* Some coding standards would use NullPointerException
for this case,
* others will use IllegalArgumentException
.
* Thus this exception would be used in place of
* IllegalArgumentException
, yet it still extends it.
*
*
* public void foo(String str) {
* if (str == null) {
* throw new NullArgumentException("str");
* }
* // do something with the string
* }
*
*
* @author Apache Software Foundation
* @author Matthew Hawthorne
* @since 2.0
* @version $Id: NullArgumentException.java 905636 2010-02-02 14:03:32Z niallp $
*/
public class NullArgumentException extends IllegalArgumentException {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 1174360235354917591L;
/**
* Instantiates with the given argument name.
*
* @param argName the name of the argument that was null
.
*/
public NullArgumentException(String argName) {
super((argName == null ? "Argument" : argName) + " must not be null.");
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/NumberRange.java 100644 0 0 16067 11513702445 24033 0 ustar 0 0 /*
* 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.lang;
import org.apache.commons.lang.text.StrBuilder;
/**
* Represents a range of {@link Number} objects.
*
* This class uses double
comparisons. This means that it
* is unsuitable for dealing with large Long
, BigDecimal
* or BigInteger
numbers.
*
* @author Apache Software Foundation
* @author Christopher Elkins
* @since 1.0
* @version $Revision: 1057072 $ $Date: 2011-01-10 01:55:57 +0000 (Mon, 10 Jan 2011) $
*
* @deprecated Use one of the Range classes in org.apache.commons.lang.math.
* Class will be removed in Commons Lang 3.0.
*
*/
public final class NumberRange {
/* The minimum number in this range. */
private final Number min;
/* The maximum number in this range. */
private final Number max;
/**
* Constructs a new NumberRange
using
* number
as both the minimum and maximum in
* this range.
*
* @param num the number to use for this range
* @throws NullPointerException if the number is null
*/
public NumberRange(Number num) {
if (num == null) {
throw new NullPointerException("The number must not be null");
}
this.min = num;
this.max = num;
}
/**
* Constructs a new NumberRange
with the specified
* minimum and maximum numbers.
*
* If the maximum is less than the minimum, the range will be constructed
* from the minimum value to the minimum value, not what you would expect!.
*
* @param min the minimum number in this range
* @param max the maximum number in this range
* @throws NullPointerException if either the minimum or maximum number is
* null
*/
public NumberRange(Number min, Number max) {
if (min == null) {
throw new NullPointerException("The minimum value must not be null");
} else if (max == null) {
throw new NullPointerException("The maximum value must not be null");
}
if (max.doubleValue() < min.doubleValue()) {
this.min = this.max = min;
} else {
this.min = min;
this.max = max;
}
}
/**
* Returns the minimum number in this range.
*
* @return the minimum number in this range
*/
public Number getMinimum() {
return min;
}
/**
* Returns the maximum number in this range.
*
* @return the maximum number in this range
*/
public Number getMaximum() {
return max;
}
/**
* Tests whether the specified number
occurs within
* this range using double
comparison.
*
* @param number the number to test
* @return true
if the specified number occurs within this
* range; otherwise, false
*/
public boolean includesNumber(Number number) {
if (number == null) {
return false;
} else {
return !(min.doubleValue() > number.doubleValue()) &&
!(max.doubleValue() < number.doubleValue());
}
}
/**
* Tests whether the specified range occurs entirely within this
* range using double
comparison.
*
* @param range the range to test
* @return true
if the specified range occurs entirely within
* this range; otherwise, false
*/
public boolean includesRange(NumberRange range) {
if (range == null) {
return false;
} else {
return includesNumber(range.min) && includesNumber(range.max);
}
}
/**
* Tests whether the specified range overlaps with this range
* using double
comparison.
*
* @param range the range to test
* @return true
if the specified range overlaps with this
* range; otherwise, false
*/
public boolean overlaps(NumberRange range) {
if (range == null) {
return false;
} else {
return range.includesNumber(min) || range.includesNumber(max) ||
includesRange(range);
}
}
/**
* Indicates whether some other Object
is
* "equal" to this one.
*
* @param obj the reference object with which to compare
* @return true
if this object is the same as the obj
* argument; false
otherwise
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (!(obj instanceof NumberRange)) {
return false;
} else {
NumberRange range = (NumberRange)obj;
return min.equals(range.min) && max.equals(range.max);
}
}
/**
* Returns a hash code value for this object.
*
* @return a hash code value for this object
*/
public int hashCode() {
int result = 17;
result = 37 * result + min.hashCode();
result = 37 * result + max.hashCode();
return result;
}
/**
* Returns the string representation of this range.
*
* This string is the string representation of the minimum and
* maximum numbers in the range, separated by a hyphen. If a number
* is negative, then it is enclosed in parentheses.
*
* @return the string representation of this range
*/
public String toString() {
StrBuilder sb = new StrBuilder();
if (min.doubleValue() < 0) {
sb.append('(')
.append(min)
.append(')');
} else {
sb.append(min);
}
sb.append('-');
if (max.doubleValue() < 0) {
sb.append('(')
.append(max)
.append(')');
} else {
sb.append(max);
}
return sb.toString();
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/NumberUtils.java 100644 0 0 61075 11513702446 24077 0 ustar 0 0 /*
* 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.lang;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
* Provides extra functionality for Java Number classes.
*
* @author Apache Software Foundation
* @author Rand McNeely
* @author Steve Downey
* @author Eric Pugh
* @author Phil Steitz
* @since 1.0
* @version $Id: NumberUtils.java 905636 2010-02-02 14:03:32Z niallp $
*
* @deprecated Moved to org.apache.commons.lang.math.
* Class will be removed in Commons Lang 3.0.
*/
public final class NumberUtils {
// DEPRECATED CLASS !!!
/**
* NumberUtils
instances should NOT be constructed in standard programming.
* Instead, the class should be used as NumberUtils.stringToInt("6");
.
*
* This constructor is public to permit tools that require a JavaBean instance
* to operate.
*/
public NumberUtils() {
super();
}
//--------------------------------------------------------------------
/**
* Convert a String
to an int
, returning
* zero
if the conversion fails.
*
* @param str the string to convert
* @return the int represented by the string, or zero
if
* conversion fails
*/
public static int stringToInt(String str) {
return stringToInt(str, 0);
}
/**
* Convert a String
to an int
, returning a
* default value if the conversion fails.
*
* @param str the string to convert
* @param defaultValue the default value
* @return the int represented by the string, or the default if conversion fails
*/
public static int stringToInt(String str, int defaultValue) {
try {
return Integer.parseInt(str);
} catch (NumberFormatException nfe) {
return defaultValue;
}
}
//--------------------------------------------------------------------
// must handle Long, Float, Integer, Float, Short,
// BigDecimal, BigInteger and Byte
// useful methods:
// Byte.decode(String)
// Byte.valueOf(String,int radix)
// Byte.valueOf(String)
// Double.valueOf(String)
// Float.valueOf(String)
// new Float(String)
// Integer.valueOf(String,int radix)
// Integer.valueOf(String)
// Integer.decode(String)
// Integer.getInteger(String)
// Integer.getInteger(String,int val)
// Integer.getInteger(String,Integer val)
// new Integer(String)
// new Double(String)
// new Byte(String)
// new Long(String)
// Long.getLong(String)
// Long.getLong(String,int)
// Long.getLong(String,Integer)
// Long.valueOf(String,int)
// Long.valueOf(String)
// new Short(String)
// Short.decode(String)
// Short.valueOf(String,int)
// Short.valueOf(String)
// new BigDecimal(String)
// new BigInteger(String)
// new BigInteger(String,int radix)
// Possible inputs:
// 45 45.5 45E7 4.5E7 Hex Oct Binary xxxF xxxD xxxf xxxd
// plus minus everything. Prolly more. A lot are not separable.
/**
* Turns a string value into a java.lang.Number.
*
* First, the value is examined for a type qualifier on the end
* ('f','F','d','D','l','L'
). If it is found, it starts
* trying to create successively larger types from the type specified
* until one is found that can hold the value.
*
* If a type specifier is not found, it will check for a decimal point
* and then try successively larger types from Integer
to
* BigInteger
and from Float
to
* BigDecimal
.
*
* If the string starts with 0x
or -0x
, it
* will be interpreted as a hexadecimal integer. Values with leading
* 0
's will not be interpreted as octal.
*
* @param val String containing a number
* @return Number created from the string
* @throws NumberFormatException if the value cannot be converted
*/
public static Number createNumber(String val) throws NumberFormatException {
if (val == null) {
return null;
}
if (val.length() == 0) {
throw new NumberFormatException("\"\" is not a valid number.");
}
if (val.length() == 1 && !Character.isDigit(val.charAt(0))) {
throw new NumberFormatException(val + " is not a valid number.");
}
if (val.startsWith("--")) {
// this is protection for poorness in java.lang.BigDecimal.
// it accepts this as a legal value, but it does not appear
// to be in specification of class. OS X Java parses it to
// a wrong value.
return null;
}
if (val.startsWith("0x") || val.startsWith("-0x")) {
return createInteger(val);
}
char lastChar = val.charAt(val.length() - 1);
String mant;
String dec;
String exp;
int decPos = val.indexOf('.');
int expPos = val.indexOf('e') + val.indexOf('E') + 1;
if (decPos > -1) {
if (expPos > -1) {
if (expPos < decPos) {
throw new NumberFormatException(val + " is not a valid number.");
}
dec = val.substring(decPos + 1, expPos);
} else {
dec = val.substring(decPos + 1);
}
mant = val.substring(0, decPos);
} else {
if (expPos > -1) {
mant = val.substring(0, expPos);
} else {
mant = val;
}
dec = null;
}
if (!Character.isDigit(lastChar)) {
if (expPos > -1 && expPos < val.length() - 1) {
exp = val.substring(expPos + 1, val.length() - 1);
} else {
exp = null;
}
//Requesting a specific type..
String numeric = val.substring(0, val.length() - 1);
boolean allZeros = isAllZeros(mant) && isAllZeros(exp);
switch (lastChar) {
case 'l' :
case 'L' :
if (dec == null
&& exp == null
&& (numeric.charAt(0) == '-' && isDigits(numeric.substring(1)) || isDigits(numeric))) {
try {
return createLong(numeric);
} catch (NumberFormatException nfe) {
//Too big for a long
}
return createBigInteger(numeric);
}
throw new NumberFormatException(val + " is not a valid number.");
case 'f' :
case 'F' :
try {
Float f = NumberUtils.createFloat(numeric);
if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) {
//If it's too big for a float or the float value = 0 and the string
//has non-zeros in it, then float does not have the precision we want
return f;
}
} catch (NumberFormatException e) {
// ignore the bad number
}
//$FALL-THROUGH$
case 'd' :
case 'D' :
try {
Double d = NumberUtils.createDouble(numeric);
if (!(d.isInfinite() || (d.floatValue() == 0.0D && !allZeros))) {
return d;
}
} catch (NumberFormatException nfe) {
// empty catch
}
try {
return createBigDecimal(numeric);
} catch (NumberFormatException e) {
// empty catch
}
//$FALL-THROUGH$
default :
throw new NumberFormatException(val + " is not a valid number.");
}
} else {
//User doesn't have a preference on the return type, so let's start
//small and go from there...
if (expPos > -1 && expPos < val.length() - 1) {
exp = val.substring(expPos + 1, val.length());
} else {
exp = null;
}
if (dec == null && exp == null) {
//Must be an int,long,bigint
try {
return createInteger(val);
} catch (NumberFormatException nfe) {
// empty catch
}
try {
return createLong(val);
} catch (NumberFormatException nfe) {
// empty catch
}
return createBigInteger(val);
} else {
//Must be a float,double,BigDec
boolean allZeros = isAllZeros(mant) && isAllZeros(exp);
try {
Float f = createFloat(val);
if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) {
return f;
}
} catch (NumberFormatException nfe) {
// empty catch
}
try {
Double d = createDouble(val);
if (!(d.isInfinite() || (d.doubleValue() == 0.0D && !allZeros))) {
return d;
}
} catch (NumberFormatException nfe) {
// empty catch
}
return createBigDecimal(val);
}
}
}
/**
* Utility method for {@link #createNumber(java.lang.String)}.
*
* Returns true
if s is null
.
*
* @param s the String to check
* @return if it is all zeros or null
*/
private static boolean isAllZeros(String s) {
if (s == null) {
return true;
}
for (int i = s.length() - 1; i >= 0; i--) {
if (s.charAt(i) != '0') {
return false;
}
}
return s.length() > 0;
}
//--------------------------------------------------------------------
/**
* Convert a String
to a Float
.
*
* @param val a String
to convert
* @return converted Float
* @throws NumberFormatException if the value cannot be converted
*/
public static Float createFloat(String val) {
return Float.valueOf(val);
}
/**
* Convert a String
to a Double
.
*
* @param val a String
to convert
* @return converted Double
* @throws NumberFormatException if the value cannot be converted
*/
public static Double createDouble(String val) {
return Double.valueOf(val);
}
/**
* Convert a String
to a Integer
, handling
* hex and octal notations.
*
* @param val a String
to convert
* @return converted Integer
* @throws NumberFormatException if the value cannot be converted
*/
public static Integer createInteger(String val) {
// decode() handles 0xAABD and 0777 (hex and octal) as well.
return Integer.decode(val);
}
/**
* Convert a String
to a Long
.
*
* @param val a String
to convert
* @return converted Long
* @throws NumberFormatException if the value cannot be converted
*/
public static Long createLong(String val) {
return Long.valueOf(val);
}
/**
* Convert a String
to a BigInteger
.
*
* @param val a String
to convert
* @return converted BigInteger
* @throws NumberFormatException if the value cannot be converted
*/
public static BigInteger createBigInteger(String val) {
BigInteger bi = new BigInteger(val);
return bi;
}
/**
* Convert a String
to a BigDecimal
.
*
* @param val a String
to convert
* @return converted BigDecimal
* @throws NumberFormatException if the value cannot be converted
*/
public static BigDecimal createBigDecimal(String val) {
BigDecimal bd = new BigDecimal(val);
return bd;
}
//--------------------------------------------------------------------
/**
* Gets the minimum of three long
values.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
*/
public static long minimum(long a, long b, long c) {
if (b < a) {
a = b;
}
if (c < a) {
a = c;
}
return a;
}
/**
* Gets the minimum of three int
values.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
*/
public static int minimum(int a, int b, int c) {
if (b < a) {
a = b;
}
if (c < a) {
a = c;
}
return a;
}
/**
* Gets the maximum of three long
values.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
*/
public static long maximum(long a, long b, long c) {
if (b > a) {
a = b;
}
if (c > a) {
a = c;
}
return a;
}
/**
* Gets the maximum of three int
values.
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
*/
public static int maximum(int a, int b, int c) {
if (b > a) {
a = b;
}
if (c > a) {
a = c;
}
return a;
}
//--------------------------------------------------------------------
/**
* Compares two doubles
for order.
*
* This method is more comprehensive than the standard Java greater
* than, less than and equals operators.
*
* - It returns
-1
if the first value is less than the second.
* - It returns
+1
if the first value is greater than the second.
* - It returns
0
if the values are equal.
*
*
*
* The ordering is as follows, largest to smallest:
*
* - NaN
*
- Positive infinity
*
- Maximum double
*
- Normal positive numbers
*
- +0.0
*
- -0.0
*
- Normal negative numbers
*
- Minimum double (-Double.MAX_VALUE)
*
- Negative infinity
*
*
*
* Comparing NaN
with NaN
will
* return 0
.
*
* @param lhs the first double
* @param rhs the second double
* @return -1
if lhs is less, +1
if greater,
* 0
if equal to rhs
*/
public static int compare(double lhs, double rhs) {
if (lhs < rhs) {
return -1;
}
if (lhs > rhs) {
return +1;
}
// Need to compare bits to handle 0.0 == -0.0 being true
// compare should put -0.0 < +0.0
// Two NaNs are also == for compare purposes
// where NaN == NaN is false
long lhsBits = Double.doubleToLongBits(lhs);
long rhsBits = Double.doubleToLongBits(rhs);
if (lhsBits == rhsBits) {
return 0;
}
// Something exotic! A comparison to NaN or 0.0 vs -0.0
// Fortunately NaN's long is > than everything else
// Also negzeros bits < poszero
// NAN: 9221120237041090560
// MAX: 9218868437227405311
// NEGZERO: -9223372036854775808
if (lhsBits < rhsBits) {
return -1;
} else {
return +1;
}
}
/**
* Compares two floats for order.
*
* This method is more comprehensive than the standard Java greater than,
* less than and equals operators.
*
* - It returns
-1
if the first value is less than the second.
* - It returns
+1
if the first value is greater than the second.
* - It returns
0
if the values are equal.
*
*
* The ordering is as follows, largest to smallest:
*
* - NaN
*
- Positive infinity
*
- Maximum float
*
- Normal positive numbers
*
- +0.0
*
- -0.0
*
- Normal negative numbers
*
- Minimum float (-Float.MAX_VALUE)
*
- Negative infinity
*
*
* Comparing NaN
with NaN
will return
* 0
.
*
* @param lhs the first float
* @param rhs the second float
* @return -1
if lhs is less, +1
if greater,
* 0
if equal to rhs
*/
public static int compare(float lhs, float rhs) {
if (lhs < rhs) {
return -1;
}
if (lhs > rhs) {
return +1;
}
//Need to compare bits to handle 0.0 == -0.0 being true
// compare should put -0.0 < +0.0
// Two NaNs are also == for compare purposes
// where NaN == NaN is false
int lhsBits = Float.floatToIntBits(lhs);
int rhsBits = Float.floatToIntBits(rhs);
if (lhsBits == rhsBits) {
return 0;
}
//Something exotic! A comparison to NaN or 0.0 vs -0.0
//Fortunately NaN's int is > than everything else
//Also negzeros bits < poszero
//NAN: 2143289344
//MAX: 2139095039
//NEGZERO: -2147483648
if (lhsBits < rhsBits) {
return -1;
} else {
return +1;
}
}
//--------------------------------------------------------------------
/**
* Checks whether the String
contains only
* digit characters.
*
* Null
and empty String will return
* false
.
*
* @param str the String
to check
* @return true
if str contains only unicode numeric
*/
public static boolean isDigits(String str) {
if ((str == null) || (str.length() == 0)) {
return false;
}
for (int i = 0; i < str.length(); i++) {
if (!Character.isDigit(str.charAt(i))) {
return false;
}
}
return true;
}
/**
* Checks whether the String a valid Java number.
*
* Valid numbers include hexadecimal marked with the 0x
* qualifier, scientific notation and numbers marked with a type
* qualifier (e.g. 123L).
*
* Null
and empty String will return
* false
.
*
* @param str the String
to check
* @return true
if the string is a correctly formatted number
*/
public static boolean isNumber(String str) {
if (StringUtils.isEmpty(str)) {
return false;
}
char[] chars = str.toCharArray();
int sz = chars.length;
boolean hasExp = false;
boolean hasDecPoint = false;
boolean allowSigns = false;
boolean foundDigit = false;
// deal with any possible sign up front
int start = (chars[0] == '-') ? 1 : 0;
if (sz > start + 1) {
if (chars[start] == '0' && chars[start + 1] == 'x') {
int i = start + 2;
if (i == sz) {
return false; // str == "0x"
}
// checking hex (it can't be anything else)
for (; i < chars.length; i++) {
if ((chars[i] < '0' || chars[i] > '9')
&& (chars[i] < 'a' || chars[i] > 'f')
&& (chars[i] < 'A' || chars[i] > 'F')) {
return false;
}
}
return true;
}
}
sz--; // don't want to loop to the last char, check it afterwords
// for type qualifiers
int i = start;
// loop to the next to last char or to the last char if we need another digit to
// make a valid number (e.g. chars[0..5] = "1234E")
while (i < sz || (i < sz + 1 && allowSigns && !foundDigit)) {
if (chars[i] >= '0' && chars[i] <= '9') {
foundDigit = true;
allowSigns = false;
} else if (chars[i] == '.') {
if (hasDecPoint || hasExp) {
// two decimal points or dec in exponent
return false;
}
hasDecPoint = true;
} else if (chars[i] == 'e' || chars[i] == 'E') {
// we've already taken care of hex.
if (hasExp) {
// two E's
return false;
}
if (!foundDigit) {
return false;
}
hasExp = true;
allowSigns = true;
} else if (chars[i] == '+' || chars[i] == '-') {
if (!allowSigns) {
return false;
}
allowSigns = false;
foundDigit = false; // we need a digit after the E
} else {
return false;
}
i++;
}
if (i < chars.length) {
if (chars[i] >= '0' && chars[i] <= '9') {
// no type qualifier, OK
return true;
}
if (chars[i] == 'e' || chars[i] == 'E') {
// can't have an E at the last byte
return false;
}
if (!allowSigns
&& (chars[i] == 'd'
|| chars[i] == 'D'
|| chars[i] == 'f'
|| chars[i] == 'F')) {
return foundDigit;
}
if (chars[i] == 'l'
|| chars[i] == 'L') {
// not allowing L with an exponent
return foundDigit && !hasExp;
}
// last character is illegal
return false;
}
// allowSigns is true iff the val ends in 'E'
// found digit it to make sure weird stuff like '.' and '1E-' doesn't pass
return !allowSigns && foundDigit;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/ObjectUtils.java 100644 0 0 45112 11513702445 24046 0 ustar 0 0 /*
* 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.lang;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import org.apache.commons.lang.exception.CloneFailedException;
import org.apache.commons.lang.reflect.MethodUtils;
/**
* Operations on Object
.
*
* This class tries to handle null
input gracefully.
* An exception will generally not be thrown for a null
input.
* Each method documents its behaviour in more detail.
*
* #ThreadSafe#
* @author Apache Software Foundation
* @author Nissim Karpenstein
* @author Janek Bogucki
* @author Daniel L. Rall
* @author Gary Gregory
* @author Mario Winterer
* @author David J. M. Karlsen
* @since 1.0
* @version $Id: ObjectUtils.java 1057434 2011-01-11 01:27:37Z niallp $
*/
//@Immutable
public class ObjectUtils {
/**
* Singleton used as a null
placeholder where
* null
has another meaning.
*
* For example, in a HashMap
the
* {@link java.util.HashMap#get(java.lang.Object)} method returns
* null
if the Map
contains
* null
or if there is no matching key. The
* Null
placeholder can be used to distinguish between
* these two cases.
*
* Another example is Hashtable
, where null
* cannot be stored.
*
* This instance is Serializable.
*/
public static final Null NULL = new Null();
/**
* ObjectUtils
instances should NOT be constructed in
* standard programming. Instead, the class should be used as
* 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
* 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 object the Object
to test, may be null
* @param defaultValue the default value to return, may be null
* @return object
if it is not null
, defaultValue otherwise
*/
public static Object defaultIfNull(Object object, Object defaultValue) {
return object != null ? object : defaultValue;
}
/**
* Compares two objects for equality, where either one or both
* objects may be 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 null
* @param object2 the second object, may be null
* @return 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 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 null
* @param object2 the second object, may be null
* @return false
if the values of both objects are the same
* @since 2.6
*/
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 null
.
*
*
* ObjectUtils.hashCode(null) = 0
* ObjectUtils.hashCode(obj) = obj.hashCode()
*
*
* @param obj the object to obtain the hash code of, may be null
* @return the hash code of the object, or zero if null
* @since 2.1
*/
public static int hashCode(Object obj) {
return (obj == null) ? 0 : obj.hashCode();
}
// Identity ToString
//-----------------------------------------------------------------------
/**
* Gets the toString that would be produced by Object
* if a class did not override toString itself. null
* will return 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
* null
* @return the default toString text, or null
if
* 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 Object
* if a class did not override toString itself. 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)));
}
/**
* Appends the toString that would be produced by Object
* if a class did not override toString itself. null
* will return null
.
*
*
* ObjectUtils.appendIdentityToString(*, null) = null
* ObjectUtils.appendIdentityToString(null, "") = "java.lang.String@1e23"
* ObjectUtils.appendIdentityToString(null, Boolean.TRUE) = "java.lang.Boolean@7fa"
* ObjectUtils.appendIdentityToString(buf, Boolean.TRUE) = buf.append("java.lang.Boolean@7fa")
*
*
* @param buffer the buffer to append to, may be null
* @param object the object to create a toString for, may be null
* @return the default toString text, or null
if
* null
passed in
* @since 2.0
* @deprecated The design of this method is bad - see LANG-360. Instead, use identityToString(StringBuffer, Object).
*/
public static StringBuffer appendIdentityToString(StringBuffer buffer, Object object) {
if (object == null) {
return null;
}
if (buffer == null) {
buffer = new StringBuffer();
}
return buffer
.append(object.getClass().getName())
.append('@')
.append(Integer.toHexString(System.identityHashCode(object)));
}
// ToString
//-----------------------------------------------------------------------
/**
* Gets the toString
of an Object
returning
* an empty string ("") if 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 toString
, may be null
* @return the passed in Object's toString, or nullStr if null
input
* @since 2.0
*/
public static String toString(Object obj) {
return obj == null ? "" : obj.toString();
}
/**
* Gets the toString
of an Object
returning
* a specified text if 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 toString
, may be null
* @param nullStr the String to return if null
input, may be null
* @return the passed in Object's toString, or nullStr if null
input
* @since 2.0
*/
public static String toString(Object obj, String nullStr) {
return obj == null ? nullStr : obj.toString();
}
// Min/Max
//-----------------------------------------------------------------------
/**
* Null safe comparison of Comparables.
*
* @param c1 the first comparable, may be null
* @param c2 the second comparable, may be null
* @return
*
* - If both objects are non-null and unequal, the lesser object.
*
- If both objects are non-null and equal, c1.
*
- If one of the comparables is null, the non-null object.
*
- If both the comparables are null, null is returned.
*
*/
public static Object min(Comparable c1, Comparable c2) {
return (compare(c1, c2, true) <= 0 ? c1 : c2);
}
/**
* Null safe comparison of Comparables.
*
* @param c1 the first comparable, may be null
* @param c2 the second comparable, may be null
* @return
*
* - If both objects are non-null and unequal, the greater object.
*
- If both objects are non-null and equal, c1.
*
- If one of the comparables is null, the non-null object.
*
- If both the comparables are null, null is returned.
*
*/
public static Object max(Comparable c1, Comparable c2) {
return (compare(c1, c2, false) >= 0 ? c1 : c2);
}
/**
* Null safe comparison of Comparables.
* {@code null} is assumed to be less than a non-{@code null} value.
*
* @param c1 the first comparable, may be null
* @param c2 the second comparable, may be null
* @return a negative value if c1 < c2, zero if c1 = c2
* and a positive value if c1 > c2
* @since 2.6
*/
public static int compare(Comparable c1, Comparable c2) {
return compare(c1, c2, false);
}
/**
* Null safe comparison of Comparables.
*
* @param c1 the first comparable, may be null
* @param c2 the second comparable, may be null
* @param nullGreater if true null
is considered greater
* than a Non-null
value or if false null
is
* considered less than a Non-null
value
* @return a negative value if c1 < c2, zero if c1 = c2
* and a positive value if c1 > c2
* @see java.util.Comparator#compare(Object, Object)
* @since 2.6
*/
public static int compare(Comparable c1, Comparable c2, boolean nullGreater) {
if (c1 == c2) {
return 0;
} else if (c1 == null) {
return (nullGreater ? 1 : -1);
} else if (c2 == null) {
return (nullGreater ? -1 : 1);
}
return c1.compareTo(c2);
}
/**
* Clone an object.
*
* @param o the object to clone
* @return the clone if the object implements {@link Cloneable} otherwise null
* @throws CloneFailedException if the object is cloneable and the clone operation fails
* @since 2.6
*/
public static Object clone(final Object o) {
if (o instanceof Cloneable) {
final Object result;
if (o.getClass().isArray()) {
final Class componentType = o.getClass().getComponentType();
if (!componentType.isPrimitive()) {
result = ((Object[])o).clone();
} else {
int length = Array.getLength(o);
result = Array.newInstance(componentType, length);
while (length-- > 0) {
Array.set(result, length, Array.get(o, length));
}
}
} else {
try {
result = MethodUtils.invokeMethod(o, "clone", null);
} catch (final NoSuchMethodException e) {
throw new CloneFailedException("Cloneable type "
+ o.getClass().getName()
+ " has no clone method", e);
} catch (final IllegalAccessException e) {
throw new CloneFailedException("Cannot clone Cloneable type "
+ o.getClass().getName(), e);
} catch (final InvocationTargetException e) {
throw new CloneFailedException("Exception cloning Cloneable type "
+ o.getClass().getName(), e.getTargetException());
}
}
return result;
}
return null;
}
/**
* Clone an object if possible. This method is similar to {@link #clone(Object)}, but will
* return the provided instance as the return value instead of 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.
*
* @param o the object to clone
* @return the clone if the object implements {@link Cloneable} otherwise the object itself
* @throws CloneFailedException if the object is cloneable and the clone operation fails
* @since 2.6
*/
public static Object cloneIfPossible(final Object o) {
final Object clone = clone(o);
return clone == null ? o : clone;
}
// Null
//-----------------------------------------------------------------------
/**
* Class used as a null placeholder where null
* has another meaning.
*
* For example, in a HashMap
the
* {@link java.util.HashMap#get(java.lang.Object)} method returns
* null
if the Map
contains
* null
or if there is no matching key. The
* Null
placeholder can be used to distinguish between
* these two cases.
*
* Another example is Hashtable
, where 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;
}
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/overview.html 100644 0 0 1607 11513702446 23472 0 ustar 0 0
This document is the API specification for the Apache Commons Lang library.
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/package.html 100644 0 0 2112 11513702446 23207 0 ustar 0 0
Provides highly reusable static utility methods, chiefly concerned
with adding value to the {@link java.lang} classes.
@since 1.0
Most of these classes are immutable and thus thread-safe.
However Charset is not currently guaranteed thread-safe under all circumstances.
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/RandomStringUtils.java 100644 0 0 31072 11513702445 25247 0 ustar 0 0 /*
* 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.lang;
import java.util.Random;
/**
* Operations for random String
s.
* Currently private high surrogate characters are ignored.
* These are unicode characters that fall between the values 56192 (db80)
* and 56319 (dbff) as we don't know how to handle them.
* High and low surrogates are correctly dealt with - that is if a
* high surrogate is randomly chosen, 55296 (d800) to 56191 (db7f)
* then it is followed by a low surrogate. If a low surrogate is chosen,
* 56320 (dc00) to 57343 (dfff) then it is placed after a randomly
* chosen high surrogate.
*
* #ThreadSafe#
* @author Apache Software Foundation
* @author Steven Caswell
* @author Gary Gregory
* @author Phil Steitz
* @since 1.0
* @version $Id: RandomStringUtils.java 1056988 2011-01-09 17:58:53Z niallp $
*/
public class RandomStringUtils {
/**
* Random object used by random method. This has to be not local
* to the random method so as to not return the same value in the
* same millisecond.
*/
private static final Random RANDOM = new Random();
/**
* RandomStringUtils
instances should NOT be constructed in
* standard programming. Instead, the class should be used as
* RandomStringUtils.random(5);
.
*
* This constructor is public to permit tools that require a JavaBean instance
* to operate.
*/
public RandomStringUtils() {
super();
}
// Random
//-----------------------------------------------------------------------
/**
* Creates a random string whose length is the number of characters
* specified.
*
* Characters will be chosen from the set of all characters.
*
* @param count the length of random string to create
* @return the random string
*/
public static String random(int count) {
return random(count, false, false);
}
/**
* Creates a random string whose length is the number of characters
* specified.
*
* Characters will be chosen from the set of characters whose
* ASCII value is between 32
and 126
(inclusive).
*
* @param count the length of random string to create
* @return the random string
*/
public static String randomAscii(int count) {
return random(count, 32, 127, false, false);
}
/**
* Creates a random string whose length is the number of characters
* specified.
*
* Characters will be chosen from the set of alphabetic
* characters.
*
* @param count the length of random string to create
* @return the random string
*/
public static String randomAlphabetic(int count) {
return random(count, true, false);
}
/**
* Creates a random string whose length is the number of characters
* specified.
*
* Characters will be chosen from the set of alpha-numeric
* characters.
*
* @param count the length of random string to create
* @return the random string
*/
public static String randomAlphanumeric(int count) {
return random(count, true, true);
}
/**
* Creates a random string whose length is the number of characters
* specified.
*
* Characters will be chosen from the set of numeric
* characters.
*
* @param count the length of random string to create
* @return the random string
*/
public static String randomNumeric(int count) {
return random(count, false, true);
}
/**
* Creates a random string whose length is the number of characters
* specified.
*
* Characters will be chosen from the set of alpha-numeric
* characters as indicated by the arguments.
*
* @param count the length of random string to create
* @param letters if true
, generated string will include
* alphabetic characters
* @param numbers if true
, generated string will include
* numeric characters
* @return the random string
*/
public static String random(int count, boolean letters, boolean numbers) {
return random(count, 0, 0, letters, numbers);
}
/**
* Creates a random string whose length is the number of characters
* specified.
*
* Characters will be chosen from the set of alpha-numeric
* characters as indicated by the arguments.
*
* @param count the length of random string to create
* @param start the position in set of chars to start at
* @param end the position in set of chars to end before
* @param letters if true
, generated string will include
* alphabetic characters
* @param numbers if true
, generated string will include
* numeric characters
* @return the random string
*/
public static String random(int count, int start, int end, boolean letters, boolean numbers) {
return random(count, start, end, letters, numbers, null, RANDOM);
}
/**
* Creates a random string based on a variety of options, using
* default source of randomness.
*
* This method has exactly the same semantics as
* {@link #random(int,int,int,boolean,boolean,char[],Random)}, but
* instead of using an externally supplied source of randomness, it uses
* the internal static {@link Random} instance.
*
* @param count the length of random string to create
* @param start the position in set of chars to start at
* @param end the position in set of chars to end before
* @param letters only allow letters?
* @param numbers only allow numbers?
* @param chars the set of chars to choose randoms from.
* If null
, then it will use the set of all chars.
* @return the random string
* @throws ArrayIndexOutOfBoundsException if there are not
* (end - start) + 1
characters in the set array.
*/
public static String random(int count, int start, int end, boolean letters, boolean numbers, char[] chars) {
return random(count, start, end, letters, numbers, chars, RANDOM);
}
/**
* Creates a random string based on a variety of options, using
* supplied source of randomness.
*
* If start and end are both 0
, start and end are set
* to ' '
and 'z'
, the ASCII printable
* characters, will be used, unless letters and numbers are both
* false
, in which case, start and end are set to
* 0
and Integer.MAX_VALUE
.
*
*
If set is not null
, characters between start and
* end are chosen.
*
* This method accepts a user-supplied {@link Random}
* instance to use as a source of randomness. By seeding a single
* {@link Random} instance with a fixed seed and using it for each call,
* the same random sequence of strings can be generated repeatedly
* and predictably.
*
* @param count the length of random string to create
* @param start the position in set of chars to start at
* @param end the position in set of chars to end before
* @param letters only allow letters?
* @param numbers only allow numbers?
* @param chars the set of chars to choose randoms from.
* If null
, then it will use the set of all chars.
* @param random a source of randomness.
* @return the random string
* @throws ArrayIndexOutOfBoundsException if there are not
* (end - start) + 1
characters in the set array.
* @throws IllegalArgumentException if count
< 0.
* @since 2.0
*/
public static String random(int count, int start, int end, boolean letters, boolean numbers,
char[] chars, Random random) {
if (count == 0) {
return "";
} else if (count < 0) {
throw new IllegalArgumentException("Requested random string length " + count + " is less than 0.");
}
if ((start == 0) && (end == 0)) {
end = 'z' + 1;
start = ' ';
if (!letters && !numbers) {
start = 0;
end = Integer.MAX_VALUE;
}
}
char[] buffer = new char[count];
int gap = end - start;
while (count-- != 0) {
char ch;
if (chars == null) {
ch = (char) (random.nextInt(gap) + start);
} else {
ch = chars[random.nextInt(gap) + start];
}
if ((letters && Character.isLetter(ch))
|| (numbers && Character.isDigit(ch))
|| (!letters && !numbers))
{
if(ch >= 56320 && ch <= 57343) {
if(count == 0) {
count++;
} else {
// low surrogate, insert high surrogate after putting it in
buffer[count] = ch;
count--;
buffer[count] = (char) (55296 + random.nextInt(128));
}
} else if(ch >= 55296 && ch <= 56191) {
if(count == 0) {
count++;
} else {
// high surrogate, insert low surrogate before putting it in
buffer[count] = (char) (56320 + random.nextInt(128));
count--;
buffer[count] = ch;
}
} else if(ch >= 56192 && ch <= 56319) {
// private high surrogate, no effing clue, so skip it
count++;
} else {
buffer[count] = ch;
}
} else {
count++;
}
}
return new String(buffer);
}
/**
* Creates a random string whose length is the number of characters
* specified.
*
* Characters will be chosen from the set of characters
* specified.
*
* @param count the length of random string to create
* @param chars the String containing the set of characters to use,
* may be null
* @return the random string
* @throws IllegalArgumentException if count
< 0.
*/
public static String random(int count, String chars) {
if (chars == null) {
return random(count, 0, 0, false, false, null, RANDOM);
}
return random(count, chars.toCharArray());
}
/**
* Creates a random string whose length is the number of characters
* specified.
*
* Characters will be chosen from the set of characters specified.
*
* @param count the length of random string to create
* @param chars the character array containing the set of characters to use,
* may be null
* @return the random string
* @throws IllegalArgumentException if count
< 0.
*/
public static String random(int count, char[] chars) {
if (chars == null) {
return random(count, 0, 0, false, false, null, RANDOM);
}
return random(count, 0, chars.length, false, false, chars, RANDOM);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/reflect/ConstructorUtils.java 100644 0 0 36050 11513702443 26610 0 ustar 0 0 /*
* 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.lang.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.ClassUtils;
/**
* Utility reflection methods focussed on constructors, modelled after
* {@link MethodUtils}.
*
* Known Limitations
Accessing Public Constructors In A Default
* Access Superclass
There is an issue when invoking public constructors
* contained in a default access superclass. Reflection locates these
* constructors fine and correctly assigns them as public. However, an
* IllegalAccessException
is thrown if the constructors is
* invoked.
*
* ConstructorUtils
contains a workaround for this situation. It
* will attempt to call setAccessible
on this constructor. If this
* call succeeds, then the method can be invoked as normal. This call will only
* succeed when the application has sufficient security privilages. If this call
* fails then a warning will be logged and the method may fail.
*
* @author Apache Software Foundation
* @author Craig R. McClanahan
* @author Ralph Schaer
* @author Chris Audley
* @author Rey Francois
* @author Gregor Rayman
* @author Jan Sorensen
* @author Robert Burrell Donkin
* @author Rodney Waldhoff
* @since 2.5
* @version $Id: ConstructorUtils.java 1056863 2011-01-09 02:00:25Z niallp $
*/
public class ConstructorUtils {
/**
* ConstructorUtils instances should NOT be constructed in standard
* programming. Instead, the class should be used as
* ConstructorUtils.invokeConstructor(cls, args)
.
*
* This constructor is public to permit tools that require a JavaBean
* instance to operate.
*/
public ConstructorUtils() {
super();
}
/**
* Returns new instance of klazz
created using the actual
* arguments args
. The formal parameter types are inferred from
* the actual values of args
. See
* {@link #invokeExactConstructor(Class, Object[], Class[])} for more
* details.
*
* The signatures should be assignment compatible.
*
* @param cls the class to be constructed.
* @param arg the actual argument
* @return new instance of klazz
*
* @throws NoSuchMethodException If the constructor cannot be found
* @throws IllegalAccessException If an error occurs accessing the constructor
* @throws InvocationTargetException If an error occurs invoking the constructor
* @throws InstantiationException If an error occurs instantiating the class
*
* @see #invokeConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
*/
public static Object invokeConstructor(Class cls, Object arg)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
return invokeConstructor(cls, new Object[] { arg });
}
/**
* Returns new instance of klazz
created using the actual
* arguments args
. The formal parameter types are inferred from
* the actual values of args
. See
* {@link #invokeExactConstructor(Class, Object[], Class[])} for more
* details.
* The signatures should be assignment compatible.
*
* @param cls the class to be constructed.
* @param args actual argument array
* @return new instance of klazz
*
* @throws NoSuchMethodException If the constructor cannot be found
* @throws IllegalAccessException If an error occurs accessing the
* constructor
* @throws InvocationTargetException If an error occurs invoking the
* constructor
* @throws InstantiationException If an error occurs instantiating the class
*
* @see #invokeConstructor(java.lang.Class, java.lang.Object[],
* java.lang.Class[])
*/
public static Object invokeConstructor(Class cls, Object[] args)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
InstantiationException {
if (null == args) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
Class parameterTypes[] = new Class[args.length];
for (int i = 0; i < args.length; i++) {
parameterTypes[i] = args[i].getClass();
}
return invokeConstructor(cls, args, parameterTypes);
}
/**
* Returns new instance of klazz
created using constructor
* with signature parameterTypes
and actual arguments
* args
.
*
* The signatures should be assignment compatible.
*
* @param cls the class to be constructed.
* @param args actual argument array
* @param parameterTypes parameter types array
* @return new instance of klazz
*
* @throws NoSuchMethodException if matching constructor cannot be found
* @throws IllegalAccessException thrown on the constructor's invocation
* @throws InvocationTargetException thrown on the constructor's invocation
* @throws InstantiationException thrown on the constructor's invocation
* @see Constructor#newInstance
*/
public static Object invokeConstructor(Class cls, Object[] args, Class[] parameterTypes)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
InstantiationException {
if (parameterTypes == null) {
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
Constructor ctor = getMatchingAccessibleConstructor(cls, parameterTypes);
if (null == ctor) {
throw new NoSuchMethodException("No such accessible constructor on object: "
+ cls.getName());
}
return ctor.newInstance(args);
}
/**
* Returns new instance of klazz
created using the actual
* arguments args
. The formal parameter types are inferred from
* the actual values of args
. See
* {@link #invokeExactConstructor(Class, Object[], Class[])} for more
* details.
*
* The signatures should match exactly.
*
* @param cls the class to be constructed.
* @param arg the actual argument
* @return new instance of klazz
*
* @throws NoSuchMethodException If the constructor cannot be found
* @throws IllegalAccessException If an error occurs accessing the constructor
* @throws InvocationTargetException If an error occurs invoking the constructor
* @throws InstantiationException If an error occurs instantiating the class
*
* @see #invokeExactConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
*/
public static Object invokeExactConstructor(Class cls, Object arg)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
return invokeExactConstructor(cls, new Object[] { arg });
}
/**
* Returns new instance of klazz
created using the actual
* arguments args
. The formal parameter types are inferred from
* the actual values of args
. See
* {@link #invokeExactConstructor(Class, Object[], Class[])} for more
* details.
*
* The signatures should match exactly.
*
* @param cls the class to be constructed.
* @param args actual argument array
* @return new instance of klazz
*
* @throws NoSuchMethodException If the constructor cannot be found
* @throws IllegalAccessException If an error occurs accessing the
* constructor
* @throws InvocationTargetException If an error occurs invoking the
* constructor
* @throws InstantiationException If an error occurs instantiating the class
*
* @see #invokeExactConstructor(java.lang.Class, java.lang.Object[],
* java.lang.Class[])
*/
public static Object invokeExactConstructor(Class cls, Object[] args)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
InstantiationException {
if (null == args) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
int arguments = args.length;
Class parameterTypes[] = new Class[arguments];
for (int i = 0; i < arguments; i++) {
parameterTypes[i] = args[i].getClass();
}
return invokeExactConstructor(cls, args, parameterTypes);
}
/**
* Returns new instance of klazz
created using constructor
* with signature parameterTypes
and actual arguments
* args
.
*
* The signatures should match exactly.
*
* @param cls the class to be constructed.
* @param args actual argument array
* @param parameterTypes parameter types array
* @return new instance of klazz
*
* @throws NoSuchMethodException if matching constructor cannot be found
* @throws IllegalAccessException thrown on the constructor's invocation
* @throws InvocationTargetException thrown on the constructor's invocation
* @throws InstantiationException thrown on the constructor's invocation
* @see Constructor#newInstance
*/
public static Object invokeExactConstructor(Class cls, Object[] args,
Class[] parameterTypes) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
if (parameterTypes == null) {
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
Constructor ctor = getAccessibleConstructor(cls, parameterTypes);
if (null == ctor) {
throw new NoSuchMethodException("No such accessible constructor on object: "
+ cls.getName());
}
return ctor.newInstance(args);
}
/**
* Returns a constructor with single argument.
* @param cls the class to be constructed
* @param parameterType The constructor parameter type
* @return null if matching accessible constructor can not be found.
* @see Class#getConstructor
* @see #getAccessibleConstructor(java.lang.reflect.Constructor)
*/
public static Constructor getAccessibleConstructor(Class cls,
Class parameterType) {
return getAccessibleConstructor(cls, new Class[] { parameterType });
}
/**
* Returns a constructor given a class and signature.
* @param cls the class to be constructed
* @param parameterTypes the parameter array
* @return null if matching accessible constructor can not be found
* @see Class#getConstructor
* @see #getAccessibleConstructor(java.lang.reflect.Constructor)
*/
public static Constructor getAccessibleConstructor(Class cls,
Class[] parameterTypes) {
try {
return getAccessibleConstructor(cls.getConstructor(parameterTypes));
} catch (NoSuchMethodException e) {
return (null);
}
}
/**
* Returns accessible version of the given constructor.
* @param ctor prototype constructor object.
* @return null
if accessible constructor can not be found.
* @see java.lang.SecurityManager
*/
public static Constructor getAccessibleConstructor(Constructor ctor) {
return MemberUtils.isAccessible(ctor)
&& Modifier.isPublic(ctor.getDeclaringClass().getModifiers()) ? ctor : null;
}
/**
* Find an accessible constructor with compatible parameters. Compatible
* parameters mean that every method parameter is assignable from the given
* parameters. In other words, it finds constructor that will take the
* parameters given.
*
* First it checks if there is constructor matching the exact signature.
* If no such, all the constructors of the class are tested if their
* signatures are assignment compatible with the parameter types. The first
* matching constructor is returned.
*
* @param cls find constructor for this class
* @param parameterTypes find method with compatible parameters
* @return a valid Constructor object. If there's no matching constructor,
* returns null
.
*/
public static Constructor getMatchingAccessibleConstructor(Class cls,
Class[] parameterTypes) {
// see if we can find the constructor directly
// most of the time this works and it's much faster
try {
Constructor ctor = cls.getConstructor(parameterTypes);
MemberUtils.setAccessibleWorkaround(ctor);
return ctor;
} catch (NoSuchMethodException e) { /* SWALLOW */
}
Constructor result = null;
// search through all constructors
Constructor[] ctors = cls.getConstructors();
// return best match:
for (int i = 0; i < ctors.length; i++) {
// compare parameters
if (ClassUtils.isAssignable(parameterTypes, ctors[i].getParameterTypes(), true)) {
// get accessible version of constructor
Constructor ctor = getAccessibleConstructor(ctors[i]);
if (ctor != null) {
MemberUtils.setAccessibleWorkaround(ctor);
if (result == null
|| MemberUtils.compareParameterTypes(ctor.getParameterTypes(), result
.getParameterTypes(), parameterTypes) < 0) {
result = ctor;
}
}
}
}
return result;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/reflect/FieldUtils.java 100644 0 0 64204 11513702443 25310 0 ustar 0 0 /*
* 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.lang.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import org.apache.commons.lang.ClassUtils;
/**
* Utilities for working with fields by reflection. Adapted and refactored
* from the dormant [reflect] Commons sandbox component.
*
* The ability is provided to break the scoping restrictions coded by the
* programmer. This can allow fields to be changed that shouldn't be. This
* facility should be used with care.
*
* @author Apache Software Foundation
* @author Matt Benson
* @since 2.5
* @version $Id: FieldUtils.java 1057009 2011-01-09 19:48:06Z niallp $
*/
public class FieldUtils {
/**
* FieldUtils instances should NOT be constructed in standard programming.
*
* This constructor is public to permit tools that require a JavaBean instance
* to operate.
*/
public FieldUtils() {
super();
}
/**
* Gets an accessible Field
by name respecting scope.
* Superclasses/interfaces will be considered.
*
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
*/
public static Field getField(Class cls, String fieldName) {
Field field = getField(cls, fieldName, false);
MemberUtils.setAccessibleWorkaround(field);
return field;
}
/**
* Gets an accessible Field
by name breaking scope
* if requested. Superclasses/interfaces will be considered.
*
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @param forceAccess whether to break scope restrictions using the
* setAccessible
method. False
will only
* match public fields.
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
*/
public static Field getField(final Class cls, String fieldName, boolean forceAccess) {
if (cls == null) {
throw new IllegalArgumentException("The class must not be null");
}
if (fieldName == null) {
throw new IllegalArgumentException("The field name must not be null");
}
// Sun Java 1.3 has a bugged implementation of getField hence we write the
// code ourselves
// getField() will return the Field object with the declaring class
// set correctly to the class that declares the field. Thus requesting the
// field on a subclass will return the field from the superclass.
//
// priority order for lookup:
// searchclass private/protected/package/public
// superclass protected/package/public
// private/different package blocks access to further superclasses
// implementedinterface public
// check up the superclass hierarchy
for (Class acls = cls; acls != null; acls = acls.getSuperclass()) {
try {
Field field = acls.getDeclaredField(fieldName);
// getDeclaredField checks for non-public scopes as well
// and it returns accurate results
if (!Modifier.isPublic(field.getModifiers())) {
if (forceAccess) {
field.setAccessible(true);
} else {
continue;
}
}
return field;
} catch (NoSuchFieldException ex) {
// ignore
}
}
// check the public interface case. This must be manually searched for
// incase there is a public supersuperclass field hidden by a private/package
// superclass field.
Field match = null;
for (Iterator intf = ClassUtils.getAllInterfaces(cls).iterator(); intf
.hasNext();) {
try {
Field test = ((Class) intf.next()).getField(fieldName);
if (match != null) {
throw new IllegalArgumentException(
"Reference to field "
+ fieldName
+ " is ambiguous relative to "
+ cls
+ "; a matching field exists on two or more implemented interfaces.");
}
match = test;
} catch (NoSuchFieldException ex) {
// ignore
}
}
return match;
}
/**
* Gets an accessible Field
by name respecting scope.
* Only the specified class will be considered.
*
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
*/
public static Field getDeclaredField(Class cls, String fieldName) {
return getDeclaredField(cls, fieldName, false);
}
/**
* Gets an accessible Field
by name breaking scope
* if requested. Only the specified class will be considered.
*
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @param forceAccess whether to break scope restrictions using the
* setAccessible
method. False will only match public fields.
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
*/
public static Field getDeclaredField(Class cls, String fieldName, boolean forceAccess) {
if (cls == null) {
throw new IllegalArgumentException("The class must not be null");
}
if (fieldName == null) {
throw new IllegalArgumentException("The field name must not be null");
}
try {
// only consider the specified class by using getDeclaredField()
Field field = cls.getDeclaredField(fieldName);
if (!MemberUtils.isAccessible(field)) {
if (forceAccess) {
field.setAccessible(true);
} else {
return null;
}
}
return field;
} catch (NoSuchFieldException e) {
}
return null;
}
/**
* Read an accessible static Field.
* @param field to read
* @return the field value
* @throws IllegalArgumentException if the field is null or not static
* @throws IllegalAccessException if the field is not accessible
*/
public static Object readStaticField(Field field) throws IllegalAccessException {
return readStaticField(field, false);
}
/**
* Read a static Field.
* @param field to read
* @param forceAccess whether to break scope restrictions using the
* setAccessible
method.
* @return the field value
* @throws IllegalArgumentException if the field is null or not static
* @throws IllegalAccessException if the field is not made accessible
*/
public static Object readStaticField(Field field, boolean forceAccess) throws IllegalAccessException {
if (field == null) {
throw new IllegalArgumentException("The field must not be null");
}
if (!Modifier.isStatic(field.getModifiers())) {
throw new IllegalArgumentException("The field '" + field.getName() + "' is not static");
}
return readField(field, (Object) null, forceAccess);
}
/**
* Read the named public static field. Superclasses will be considered.
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @return the value of the field
* @throws IllegalArgumentException if the class or field name is null
* @throws IllegalAccessException if the field is not accessible
*/
public static Object readStaticField(Class cls, String fieldName) throws IllegalAccessException {
return readStaticField(cls, fieldName, false);
}
/**
* Read the named static field. Superclasses will be considered.
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @param forceAccess whether to break scope restrictions using the
* setAccessible
method. False
will only
* match public fields.
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
* @throws IllegalAccessException if the field is not made accessible
*/
public static Object readStaticField(Class cls, String fieldName, boolean forceAccess) throws IllegalAccessException {
Field field = getField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate field " + fieldName + " on " + cls);
}
//already forced access above, don't repeat it here:
return readStaticField(field, false);
}
/**
* Gets a static Field value by name. The field must be public.
* Only the specified class will be considered.
*
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @return the value of the field
* @throws IllegalArgumentException if the class or field name is null
* @throws IllegalAccessException if the field is not accessible
*/
public static Object readDeclaredStaticField(Class cls, String fieldName) throws IllegalAccessException {
return readDeclaredStaticField(cls, fieldName, false);
}
/**
* Gets a static Field value by name. Only the specified class will
* be considered.
*
* @param cls the class to reflect, must not be null
* @param fieldName the field name to obtain
* @param forceAccess whether to break scope restrictions using the
* setAccessible
method. False
will only
* match public fields.
* @return the Field object
* @throws IllegalArgumentException if the class or field name is null
* @throws IllegalAccessException if the field is not made accessible
*/
public static Object readDeclaredStaticField(Class cls, String fieldName, boolean forceAccess)
throws IllegalAccessException {
Field field = getDeclaredField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate declared field " + cls.getName() + "." + fieldName);
}
//already forced access above, don't repeat it here:
return readStaticField(field, false);
}
/**
* Read an accessible Field.
* @param field the field to use
* @param target the object to call on, may be null for static fields
* @return the field value
* @throws IllegalArgumentException if the field is null
* @throws IllegalAccessException if the field is not accessible
*/
public static Object readField(Field field, Object target) throws IllegalAccessException {
return readField(field, target, false);
}
/**
* Read a Field.
* @param field the field to use
* @param target the object to call on, may be null for static fields
* @param forceAccess whether to break scope restrictions using the
* setAccessible
method.
* @return the field value
* @throws IllegalArgumentException if the field is null
* @throws IllegalAccessException if the field is not made accessible
*/
public static Object readField(Field field, Object target, boolean forceAccess) throws IllegalAccessException {
if (field == null) {
throw new IllegalArgumentException("The field must not be null");
}
if (forceAccess && !field.isAccessible()) {
field.setAccessible(true);
} else {
MemberUtils.setAccessibleWorkaround(field);
}
return field.get(target);
}
/**
* Read the named public field. Superclasses will be considered.
* @param target the object to reflect, must not be null
* @param fieldName the field name to obtain
* @return the value of the field
* @throws IllegalArgumentException if the class or field name is null
* @throws IllegalAccessException if the named field is not public
*/
public static Object readField(Object target, String fieldName) throws IllegalAccessException {
return readField(target, fieldName, false);
}
/**
* Read the named field. Superclasses will be considered.
* @param target the object to reflect, must not be null
* @param fieldName the field name to obtain
* @param forceAccess whether to break scope restrictions using the
* setAccessible
method. False
will only
* match public fields.
* @return the field value
* @throws IllegalArgumentException if the class or field name is null
* @throws IllegalAccessException if the named field is not made accessible
*/
public static Object readField(Object target, String fieldName, boolean forceAccess) throws IllegalAccessException {
if (target == null) {
throw new IllegalArgumentException("target object must not be null");
}
Class cls = target.getClass();
Field field = getField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate field " + fieldName + " on " + cls);
}
//already forced access above, don't repeat it here:
return readField(field, target);
}
/**
* Read the named public field. Only the class of the specified object will be considered.
* @param target the object to reflect, must not be null
* @param fieldName the field name to obtain
* @return the value of the field
* @throws IllegalArgumentException if the class or field name is null
* @throws IllegalAccessException if the named field is not public
*/
public static Object readDeclaredField(Object target, String fieldName) throws IllegalAccessException {
return readDeclaredField(target, fieldName, false);
}
/**
*
Gets a Field value by name. Only the class of the specified
* object will be considered.
*
* @param target the object to reflect, must not be null
* @param fieldName the field name to obtain
* @param forceAccess whether to break scope restrictions using the
* setAccessible
method. False
will only
* match public fields.
* @return the Field object
* @throws IllegalArgumentException if target
or fieldName
is null
* @throws IllegalAccessException if the field is not made accessible
*/
public static Object readDeclaredField(Object target, String fieldName, boolean forceAccess) throws IllegalAccessException {
if (target == null) {
throw new IllegalArgumentException("target object must not be null");
}
Class cls = target.getClass();
Field field = getDeclaredField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate declared field " + cls.getName() + "." + fieldName);
}
//already forced access above, don't repeat it here:
return readField(field, target);
}
/**
* Write a public static Field.
* @param field to write
* @param value to set
* @throws IllegalArgumentException if the field is null or not static
* @throws IllegalAccessException if the field is not public or is final
*/
public static void writeStaticField(Field field, Object value) throws IllegalAccessException {
writeStaticField(field, value, false);
}
/**
* Write a static Field.
* @param field to write
* @param value to set
* @param forceAccess whether to break scope restrictions using the
* setAccessible
method. False
will only
* match public fields.
* @throws IllegalArgumentException if the field is null or not static
* @throws IllegalAccessException if the field is not made accessible or is final
*/
public static void writeStaticField(Field field, Object value, boolean forceAccess) throws IllegalAccessException {
if (field == null) {
throw new IllegalArgumentException("The field must not be null");
}
if (!Modifier.isStatic(field.getModifiers())) {
throw new IllegalArgumentException("The field '" + field.getName() + "' is not static");
}
writeField(field, (Object) null, value, forceAccess);
}
/**
* Write a named public static Field. Superclasses will be considered.
* @param cls Class on which the Field is to be found
* @param fieldName to write
* @param value to set
* @throws IllegalArgumentException if the field cannot be located or is not static
* @throws IllegalAccessException if the field is not public or is final
*/
public static void writeStaticField(Class cls, String fieldName, Object value) throws IllegalAccessException {
writeStaticField(cls, fieldName, value, false);
}
/**
* Write a named static Field. Superclasses will be considered.
* @param cls Class on which the Field is to be found
* @param fieldName to write
* @param value to set
* @param forceAccess whether to break scope restrictions using the
* setAccessible
method. False
will only
* match public fields.
* @throws IllegalArgumentException if the field cannot be located or is not static
* @throws IllegalAccessException if the field is not made accessible or is final
*/
public static void writeStaticField(Class cls, String fieldName, Object value, boolean forceAccess)
throws IllegalAccessException {
Field field = getField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate field " + fieldName + " on " + cls);
}
//already forced access above, don't repeat it here:
writeStaticField(field, value);
}
/**
* Write a named public static Field. Only the specified class will be considered.
* @param cls Class on which the Field is to be found
* @param fieldName to write
* @param value to set
* @throws IllegalArgumentException if the field cannot be located or is not static
* @throws IllegalAccessException if the field is not public or is final
*/
public static void writeDeclaredStaticField(Class cls, String fieldName, Object value)
throws IllegalAccessException {
writeDeclaredStaticField(cls, fieldName, value, false);
}
/**
* Write a named static Field. Only the specified class will be considered.
* @param cls Class on which the Field is to be found
* @param fieldName to write
* @param value to set
* @param forceAccess whether to break scope restrictions using the
* setAccessible
method. False
will only
* match public fields.
* @throws IllegalArgumentException if the field cannot be located or is not static
* @throws IllegalAccessException if the field is not made accessible or is final
*/
public static void writeDeclaredStaticField(Class cls, String fieldName, Object value, boolean forceAccess)
throws IllegalAccessException {
Field field = getDeclaredField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate declared field " + cls.getName() + "." + fieldName);
}
//already forced access above, don't repeat it here:
writeField(field, (Object) null, value);
}
/**
* Write an accessible field.
* @param field to write
* @param target the object to call on, may be null for static fields
* @param value to set
* @throws IllegalArgumentException if the field is null
* @throws IllegalAccessException if the field is not accessible or is final
*/
public static void writeField(Field field, Object target, Object value) throws IllegalAccessException {
writeField(field, target, value, false);
}
/**
* Write a field.
* @param field to write
* @param target the object to call on, may be null for static fields
* @param value to set
* @param forceAccess whether to break scope restrictions using the
* setAccessible
method. False
will only
* match public fields.
* @throws IllegalArgumentException if the field is null
* @throws IllegalAccessException if the field is not made accessible or is final
*/
public static void writeField(Field field, Object target, Object value, boolean forceAccess) throws IllegalAccessException {
if (field == null) {
throw new IllegalArgumentException("The field must not be null");
}
if (forceAccess && !field.isAccessible()) {
field.setAccessible(true);
} else {
MemberUtils.setAccessibleWorkaround(field);
}
field.set(target, value);
}
/**
* Write a public field. Superclasses will be considered.
* @param target the object to reflect, must not be null
* @param fieldName the field name to obtain
* @param value to set
* @throws IllegalArgumentException if target
or fieldName
is null
* @throws IllegalAccessException if the field is not accessible
*/
public static void writeField(Object target, String fieldName, Object value) throws IllegalAccessException {
writeField(target, fieldName, value, false);
}
/**
* Write a field. Superclasses will be considered.
* @param target the object to reflect, must not be null
* @param fieldName the field name to obtain
* @param value to set
* @param forceAccess whether to break scope restrictions using the
* setAccessible
method. False
will only
* match public fields.
* @throws IllegalArgumentException if target
or fieldName
is null
* @throws IllegalAccessException if the field is not made accessible
*/
public static void writeField(Object target, String fieldName, Object value, boolean forceAccess)
throws IllegalAccessException {
if (target == null) {
throw new IllegalArgumentException("target object must not be null");
}
Class cls = target.getClass();
Field field = getField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate declared field " + cls.getName() + "." + fieldName);
}
//already forced access above, don't repeat it here:
writeField(field, target, value);
}
/**
* Write a public field. Only the specified class will be considered.
* @param target the object to reflect, must not be null
* @param fieldName the field name to obtain
* @param value to set
* @throws IllegalArgumentException if target
or fieldName
is null
* @throws IllegalAccessException if the field is not made accessible
*/
public static void writeDeclaredField(Object target, String fieldName, Object value) throws IllegalAccessException {
writeDeclaredField(target, fieldName, value, false);
}
/**
* Write a public field. Only the specified class will be considered.
* @param target the object to reflect, must not be null
* @param fieldName the field name to obtain
* @param value to set
* @param forceAccess whether to break scope restrictions using the
* setAccessible
method. False
will only
* match public fields.
* @throws IllegalArgumentException if target
or fieldName
is null
* @throws IllegalAccessException if the field is not made accessible
*/
public static void writeDeclaredField(Object target, String fieldName, Object value, boolean forceAccess)
throws IllegalAccessException {
if (target == null) {
throw new IllegalArgumentException("target object must not be null");
}
Class cls = target.getClass();
Field field = getDeclaredField(cls, fieldName, forceAccess);
if (field == null) {
throw new IllegalArgumentException("Cannot locate declared field " + cls.getName() + "." + fieldName);
}
//already forced access above, don't repeat it here:
writeField(field, target, value);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/reflect/MemberUtils.java 100644 0 0 20610 11513702443 25465 0 ustar 0 0 /*
* 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.lang.reflect;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.ClassUtils;
import org.apache.commons.lang.SystemUtils;
/**
* Contains common code for working with Methods/Constructors, extracted and
* refactored from MethodUtils
when it was imported from Commons
* BeanUtils.
*
* @author Apache Software Foundation
* @author Steve Cohen
* @author Matt Benson
* @since 2.5
* @version $Id: MemberUtils.java 1057013 2011-01-09 20:04:16Z niallp $
*/
abstract class MemberUtils {
// TODO extract an interface to implement compareParameterSets(...)?
private static final int ACCESS_TEST = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
private static final Method IS_SYNTHETIC;
static {
Method isSynthetic = null;
if (SystemUtils.isJavaVersionAtLeast(1.5f)) {
// cannot call synthetic methods:
try {
isSynthetic = Member.class.getMethod("isSynthetic",
ArrayUtils.EMPTY_CLASS_ARRAY);
} catch (Exception e) {
}
}
IS_SYNTHETIC = isSynthetic;
}
/** Array of primitive number types ordered by "promotability" */
private static final Class[] ORDERED_PRIMITIVE_TYPES = { Byte.TYPE, Short.TYPE,
Character.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE };
/**
* XXX Default access superclass workaround
*
* When a public class has a default access superclass with public members,
* these members are accessible. Calling them from compiled code works fine.
* Unfortunately, on some JVMs, using reflection to invoke these members
* seems to (wrongly) to prevent access even when the modifer is public.
* Calling setAccessible(true) solves the problem but will only work from
* sufficiently privileged code. Better workarounds would be gratefully
* accepted.
* @param o the AccessibleObject to set as accessible
*/
static void setAccessibleWorkaround(AccessibleObject o) {
if (o == null || o.isAccessible()) {
return;
}
Member m = (Member) o;
if (Modifier.isPublic(m.getModifiers())
&& isPackageAccess(m.getDeclaringClass().getModifiers())) {
try {
o.setAccessible(true);
} catch (SecurityException e) {
// ignore in favor of subsequent IllegalAccessException
}
}
}
/**
* Learn whether a given set of modifiers implies package access.
* @param modifiers to test
* @return true unless package/protected/private modifier detected
*/
static boolean isPackageAccess(int modifiers) {
return (modifiers & ACCESS_TEST) == 0;
}
/**
* Check a Member for basic accessibility.
* @param m Member to check
* @return true if m
is accessible
*/
static boolean isAccessible(Member m) {
return m != null && Modifier.isPublic(m.getModifiers()) && !isSynthetic(m);
}
/**
* Try to learn whether a given member, on JDK >= 1.5, is synthetic.
* @param m Member to check
* @return true if m
was introduced by the compiler.
*/
static boolean isSynthetic(Member m) {
if (IS_SYNTHETIC != null) {
try {
return ((Boolean) IS_SYNTHETIC.invoke(m, null)).booleanValue();
} catch (Exception e) {
}
}
return false;
}
/**
* Compare the relative fitness of two sets of parameter types in terms of
* matching a third set of runtime parameter types, such that a list ordered
* by the results of the comparison would return the best match first
* (least).
*
* @param left the "left" parameter set
* @param right the "right" parameter set
* @param actual the runtime parameter types to match against
* left
/right
* @return int consistent with compare
semantics
*/
static int compareParameterTypes(Class[] left, Class[] right, Class[] actual) {
float leftCost = getTotalTransformationCost(actual, left);
float rightCost = getTotalTransformationCost(actual, right);
return leftCost < rightCost ? -1 : rightCost < leftCost ? 1 : 0;
}
/**
* Returns the sum of the object transformation cost for each class in the
* source argument list.
* @param srcArgs The source arguments
* @param destArgs The destination arguments
* @return The total transformation cost
*/
private static float getTotalTransformationCost(Class[] srcArgs, Class[] destArgs) {
float totalCost = 0.0f;
for (int i = 0; i < srcArgs.length; i++) {
Class srcClass, destClass;
srcClass = srcArgs[i];
destClass = destArgs[i];
totalCost += getObjectTransformationCost(srcClass, destClass);
}
return totalCost;
}
/**
* Gets the number of steps required needed to turn the source class into
* the destination class. This represents the number of steps in the object
* hierarchy graph.
* @param srcClass The source class
* @param destClass The destination class
* @return The cost of transforming an object
*/
private static float getObjectTransformationCost(Class srcClass, Class destClass) {
if (destClass.isPrimitive()) {
return getPrimitivePromotionCost(srcClass, destClass);
}
float cost = 0.0f;
while (srcClass != null && !destClass.equals(srcClass)) {
if (destClass.isInterface() && ClassUtils.isAssignable(srcClass, destClass)) {
// slight penalty for interface match.
// we still want an exact match to override an interface match,
// but
// an interface match should override anything where we have to
// get a superclass.
cost += 0.25f;
break;
}
cost++;
srcClass = srcClass.getSuperclass();
}
/*
* If the destination class is null, we've travelled all the way up to
* an Object match. We'll penalize this by adding 1.5 to the cost.
*/
if (srcClass == null) {
cost += 1.5f;
}
return cost;
}
/**
* Get the number of steps required to promote a primitive number to another
* type.
* @param srcClass the (primitive) source class
* @param destClass the (primitive) destination class
* @return The cost of promoting the primitive
*/
private static float getPrimitivePromotionCost(final Class srcClass, final Class destClass) {
float cost = 0.0f;
Class cls = srcClass;
if (!cls.isPrimitive()) {
// slight unwrapping penalty
cost += 0.1f;
cls = ClassUtils.wrapperToPrimitive(cls);
}
for (int i = 0; cls != destClass && i < ORDERED_PRIMITIVE_TYPES.length; i++) {
if (cls == ORDERED_PRIMITIVE_TYPES[i]) {
cost += 0.1f;
if (i < ORDERED_PRIMITIVE_TYPES.length - 1) {
cls = ORDERED_PRIMITIVE_TYPES[i + 1];
}
}
}
return cost;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/reflect/MethodUtils.java 100644 0 0 71653 11513702443 25513 0 ustar 0 0 /*
* 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.lang.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.ClassUtils;
/**
*
Utility reflection methods focused on methods, originally from Commons BeanUtils.
* Differences from the BeanUtils version may be noted, especially where similar functionality
* already existed within Lang.
*
*
* Known Limitations
* Accessing Public Methods In A Default Access Superclass
* There is an issue when invoking public methods contained in a default access superclass on JREs prior to 1.4.
* Reflection locates these methods fine and correctly assigns them as public.
* However, an IllegalAccessException
is thrown if the method is invoked.
*
* MethodUtils
contains a workaround for this situation.
* It will attempt to call setAccessible
on this method.
* If this call succeeds, then the method can be invoked as normal.
* This call will only succeed when the application has sufficient security privileges.
* If this call fails then the method may fail.
*
* @author Apache Software Foundation
* @author Craig R. McClanahan
* @author Ralph Schaer
* @author Chris Audley
* @author Rey François
* @author Gregor Raýman
* @author Jan Sorensen
* @author Robert Burrell Donkin
* @author Matt Benson
* @since 2.5
* @version $Id: MethodUtils.java 911986 2010-02-19 21:19:05Z niallp $
*/
public class MethodUtils {
/**
* MethodUtils instances should NOT be constructed in standard programming.
* Instead, the class should be used as
* MethodUtils.getAccessibleMethod(method)
.
*
* This constructor is public to permit tools that require a JavaBean
* instance to operate.
*/
public MethodUtils() {
super();
}
/**
* Invoke a named method whose parameter type matches the object type.
*
* This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.
*
* This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a Boolean
object
* would match a boolean
primitive.
*
* This is a convenient wrapper for
* {@link #invokeMethod(Object object, String methodName, Object[] args)}.
*
*
* @param object invoke method on this object
* @param methodName get method with this name
* @param arg use this argument
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the method invoked
* @throws IllegalAccessException if the requested method is not accessible via reflection
*/
public static Object invokeMethod(Object object, String methodName,
Object arg) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
return invokeMethod(object, methodName, new Object[] { arg });
}
/**
* Invoke a named method whose parameter type matches the object type.
*
* This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.
*
* This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a Boolean
object
* would match a boolean
primitive.
*
* This is a convenient wrapper for
* {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}.
*
*
* @param object invoke method on this object
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the method invoked
* @throws IllegalAccessException if the requested method is not accessible via reflection
*/
public static Object invokeMethod(Object object, String methodName,
Object[] args) throws NoSuchMethodException,
IllegalAccessException, InvocationTargetException {
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
int arguments = args.length;
Class[] parameterTypes = new Class[arguments];
for (int i = 0; i < arguments; i++) {
parameterTypes[i] = args[i].getClass();
}
return invokeMethod(object, methodName, args, parameterTypes);
}
/**
* Invoke a named method whose parameter type matches the object type.
*
* This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.
*
* This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a Boolean
object
* would match a boolean
primitive.
*
* @param object invoke method on this object
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @param parameterTypes match these parameters - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the method invoked
* @throws IllegalAccessException if the requested method is not accessible via reflection
*/
public static Object invokeMethod(Object object, String methodName,
Object[] args, Class[] parameterTypes)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
if (parameterTypes == null) {
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
Method method = getMatchingAccessibleMethod(object.getClass(),
methodName, parameterTypes);
if (method == null) {
throw new NoSuchMethodException("No such accessible method: "
+ methodName + "() on object: "
+ object.getClass().getName());
}
return method.invoke(object, args);
}
/**
* Invoke a method whose parameter type matches exactly the object
* type.
*
* This is a convenient wrapper for
* {@link #invokeExactMethod(Object object,String methodName,Object [] args)}.
*
*
* @param object invoke method on this object
* @param methodName get method with this name
* @param arg use this argument
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the
* method invoked
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
public static Object invokeExactMethod(Object object, String methodName,
Object arg) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
return invokeExactMethod(object, methodName, new Object[] { arg });
}
/**
* Invoke a method whose parameter types match exactly the object
* types.
*
* This uses reflection to invoke the method obtained from a call to
* getAccessibleMethod()
.
*
* @param object invoke method on this object
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the
* method invoked
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
public static Object invokeExactMethod(Object object, String methodName,
Object[] args) throws NoSuchMethodException,
IllegalAccessException, InvocationTargetException {
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
int arguments = args.length;
Class[] parameterTypes = new Class[arguments];
for (int i = 0; i < arguments; i++) {
parameterTypes[i] = args[i].getClass();
}
return invokeExactMethod(object, methodName, args, parameterTypes);
}
/**
* Invoke a method whose parameter types match exactly the parameter
* types given.
*
* This uses reflection to invoke the method obtained from a call to
* getAccessibleMethod()
.
*
* @param object invoke method on this object
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @param parameterTypes match these parameters - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the
* method invoked
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
public static Object invokeExactMethod(Object object, String methodName,
Object[] args, Class[] parameterTypes)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
if (parameterTypes == null) {
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
Method method = getAccessibleMethod(object.getClass(), methodName,
parameterTypes);
if (method == null) {
throw new NoSuchMethodException("No such accessible method: "
+ methodName + "() on object: "
+ object.getClass().getName());
}
return method.invoke(object, args);
}
/**
* Invoke a static method whose parameter types match exactly the parameter
* types given.
*
* This uses reflection to invoke the method obtained from a call to
* {@link #getAccessibleMethod(Class, String, Class[])}.
*
* @param cls invoke static method on this class
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @param parameterTypes match these parameters - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the
* method invoked
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
public static Object invokeExactStaticMethod(Class cls, String methodName,
Object[] args, Class[] parameterTypes)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
if (parameterTypes == null) {
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
Method method = getAccessibleMethod(cls, methodName, parameterTypes);
if (method == null) {
throw new NoSuchMethodException("No such accessible method: "
+ methodName + "() on class: " + cls.getName());
}
return method.invoke(null, args);
}
/**
* Invoke a named static method whose parameter type matches the object type.
*
* This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.
*
* This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a Boolean
class
* would match a boolean
primitive.
*
* This is a convenient wrapper for
* {@link #invokeStaticMethod(Class objectClass,String methodName,Object [] args)}.
*
*
* @param cls invoke static method on this class
* @param methodName get method with this name
* @param arg use this argument
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the
* method invoked
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
public static Object invokeStaticMethod(Class cls, String methodName,
Object arg) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
return invokeStaticMethod(cls, methodName, new Object[] { arg });
}
/**
* Invoke a named static method whose parameter type matches the object type.
*
* This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.
*
* This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a Boolean
class
* would match a boolean
primitive.
*
* This is a convenient wrapper for
* {@link #invokeStaticMethod(Class objectClass,String methodName,Object [] args,Class[] parameterTypes)}.
*
*
* @param cls invoke static method on this class
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the
* method invoked
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
public static Object invokeStaticMethod(Class cls, String methodName,
Object[] args) throws NoSuchMethodException,
IllegalAccessException, InvocationTargetException {
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
int arguments = args.length;
Class[] parameterTypes = new Class[arguments];
for (int i = 0; i < arguments; i++) {
parameterTypes[i] = args[i].getClass();
}
return invokeStaticMethod(cls, methodName, args, parameterTypes);
}
/**
* Invoke a named static method whose parameter type matches the object type.
*
* This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.
*
* This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a Boolean
class
* would match a boolean
primitive.
*
*
* @param cls invoke static method on this class
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @param parameterTypes match these parameters - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the
* method invoked
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
public static Object invokeStaticMethod(Class cls, String methodName,
Object[] args, Class[] parameterTypes)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
if (parameterTypes == null) {
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
Method method = getMatchingAccessibleMethod(cls, methodName,
parameterTypes);
if (method == null) {
throw new NoSuchMethodException("No such accessible method: "
+ methodName + "() on class: " + cls.getName());
}
return method.invoke(null, args);
}
/**
* Invoke a static method whose parameter type matches exactly the object
* type.
*
* This is a convenient wrapper for
* {@link #invokeExactStaticMethod(Class objectClass,String methodName,Object [] args)}.
*
*
* @param cls invoke static method on this class
* @param methodName get method with this name
* @param arg use this argument
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the
* method invoked
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
public static Object invokeExactStaticMethod(Class cls, String methodName,
Object arg) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
return invokeExactStaticMethod(cls, methodName, new Object[] { arg });
}
/**
* Invoke a static method whose parameter types match exactly the object
* types.
*
* This uses reflection to invoke the method obtained from a call to
* {@link #getAccessibleMethod(Class, String, Class[])}.
*
* @param cls invoke static method on this class
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the
* method invoked
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
public static Object invokeExactStaticMethod(Class cls, String methodName,
Object[] args) throws NoSuchMethodException,
IllegalAccessException, InvocationTargetException {
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
int arguments = args.length;
Class[] parameterTypes = new Class[arguments];
for (int i = 0; i < arguments; i++) {
parameterTypes[i] = args[i].getClass();
}
return invokeExactStaticMethod(cls, methodName, args, parameterTypes);
}
/**
* Return an accessible method (that is, one that can be invoked via
* reflection) with given name and a single parameter. If no such method
* can be found, return null
.
* Basically, a convenience wrapper that constructs a Class
* array for you.
*
* @param cls get method from this class
* @param methodName get method with this name
* @param parameterType taking this type of parameter
* @return The accessible method
*/
public static Method getAccessibleMethod(Class cls, String methodName,
Class parameterType) {
return getAccessibleMethod(cls, methodName,
new Class[] { parameterType });
}
/**
* Return an accessible method (that is, one that can be invoked via
* reflection) with given name and parameters. If no such method
* can be found, return null
.
* This is just a convenient wrapper for
* {@link #getAccessibleMethod(Method method)}.
*
* @param cls get method from this class
* @param methodName get method with this name
* @param parameterTypes with these parameters types
* @return The accessible method
*/
public static Method getAccessibleMethod(Class cls, String methodName,
Class[] parameterTypes) {
try {
return getAccessibleMethod(cls.getMethod(methodName,
parameterTypes));
} catch (NoSuchMethodException e) {
return (null);
}
}
/**
* Return an accessible method (that is, one that can be invoked via
* reflection) that implements the specified Method. If no such method
* can be found, return null
.
*
* @param method The method that we wish to call
* @return The accessible method
*/
public static Method getAccessibleMethod(Method method) {
if (!MemberUtils.isAccessible(method)) {
return null;
}
// If the declaring class is public, we are done
Class cls = method.getDeclaringClass();
if (Modifier.isPublic(cls.getModifiers())) {
return method;
}
String methodName = method.getName();
Class[] parameterTypes = method.getParameterTypes();
// Check the implemented interfaces and subinterfaces
method = getAccessibleMethodFromInterfaceNest(cls, methodName,
parameterTypes);
// Check the superclass chain
if (method == null) {
method = getAccessibleMethodFromSuperclass(cls, methodName,
parameterTypes);
}
return method;
}
/**
* Return an accessible method (that is, one that can be invoked via
* reflection) by scanning through the superclasses. If no such method
* can be found, return null
.
*
* @param cls Class to be checked
* @param methodName Method name of the method we wish to call
* @param parameterTypes The parameter type signatures
* @return the accessible method or null
if not found
*/
private static Method getAccessibleMethodFromSuperclass(Class cls,
String methodName, Class[] parameterTypes) {
Class parentClass = cls.getSuperclass();
while (parentClass != null) {
if (Modifier.isPublic(parentClass.getModifiers())) {
try {
return parentClass.getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
return null;
}
}
parentClass = parentClass.getSuperclass();
}
return null;
}
/**
* Return an accessible method (that is, one that can be invoked via
* reflection) that implements the specified method, by scanning through
* all implemented interfaces and subinterfaces. If no such method
* can be found, return null
.
*
* There isn't any good reason why this method must be private.
* It is because there doesn't seem any reason why other classes should
* call this rather than the higher level methods.
*
* @param cls Parent class for the interfaces to be checked
* @param methodName Method name of the method we wish to call
* @param parameterTypes The parameter type signatures
* @return the accessible method or null
if not found
*/
private static Method getAccessibleMethodFromInterfaceNest(Class cls,
String methodName, Class[] parameterTypes) {
Method method = null;
// Search up the superclass chain
for (; cls != null; cls = cls.getSuperclass()) {
// Check the implemented interfaces of the parent class
Class[] interfaces = cls.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
// Is this interface public?
if (!Modifier.isPublic(interfaces[i].getModifiers())) {
continue;
}
// Does the method exist on this interface?
try {
method = interfaces[i].getDeclaredMethod(methodName,
parameterTypes);
} catch (NoSuchMethodException e) {
/*
* Swallow, if no method is found after the loop then this
* method returns null.
*/
}
if (method != null) {
break;
}
// Recursively check our parent interfaces
method = getAccessibleMethodFromInterfaceNest(interfaces[i],
methodName, parameterTypes);
if (method != null) {
break;
}
}
}
return method;
}
/**
* Find an accessible method that matches the given name and has compatible parameters.
* Compatible parameters mean that every method parameter is assignable from
* the given parameters.
* In other words, it finds a method with the given name
* that will take the parameters given.
*
*
This method is used by
* {@link
* #invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)}.
*
*
This method can match primitive parameter by passing in wrapper classes.
* For example, a Boolean
will match a primitive boolean
* parameter.
*
* @param cls find method in this class
* @param methodName find method with this name
* @param parameterTypes find method with most compatible parameters
* @return The accessible method
*/
public static Method getMatchingAccessibleMethod(Class cls,
String methodName, Class[] parameterTypes) {
try {
Method method = cls.getMethod(methodName, parameterTypes);
MemberUtils.setAccessibleWorkaround(method);
return method;
} catch (NoSuchMethodException e) { /* SWALLOW */
}
// search through all methods
Method bestMatch = null;
Method[] methods = cls.getMethods();
for (int i = 0, size = methods.length; i < size; i++) {
if (methods[i].getName().equals(methodName)) {
// compare parameters
if (ClassUtils.isAssignable(parameterTypes, methods[i]
.getParameterTypes(), true)) {
// get accessible version of method
Method accessibleMethod = getAccessibleMethod(methods[i]);
if (accessibleMethod != null) {
if (bestMatch == null
|| MemberUtils.compareParameterTypes(
accessibleMethod.getParameterTypes(),
bestMatch.getParameterTypes(),
parameterTypes) < 0) {
bestMatch = accessibleMethod;
}
}
}
}
}
if (bestMatch != null) {
MemberUtils.setAccessibleWorkaround(bestMatch);
}
return bestMatch;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/reflect/package.html 100644 0 0 2075 11513702443 24640 0 ustar 0 0
Accumulates common high-level uses of the java.lang.reflect
APIs.
@since 2.5
These classes are immutable, and therefore thread-safe.
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/SerializationException.java 100644 0 0 5206 11513702446 26274 0 ustar 0 0 /*
* 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.lang;
import org.apache.commons.lang.exception.NestableRuntimeException;
/**
* Exception thrown when the Serialization process fails.
*
* The original error is wrapped within this one.
*
* @author Apache Software Foundation
* @since 1.0
* @version $Id: SerializationException.java 905636 2010-02-02 14:03:32Z niallp $
*/
public class SerializationException extends NestableRuntimeException {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 4029025366392702726L;
/**
* Constructs a new SerializationException
without specified
* detail message.
*/
public SerializationException() {
super();
}
/**
* Constructs a new SerializationException
with specified
* detail message.
*
* @param msg The error message.
*/
public SerializationException(String msg) {
super(msg);
}
/**
* Constructs a new SerializationException
with specified
* nested Throwable
.
*
* @param cause The Exception
or Error
* that caused this exception to be thrown.
*/
public SerializationException(Throwable cause) {
super(cause);
}
/**
* Constructs a new SerializationException
with specified
* detail message and nested Throwable
.
*
* @param msg The error message.
* @param cause The Exception
or Error
* that caused this exception to be thrown.
*/
public SerializationException(String msg, Throwable cause) {
super(msg, cause);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/SerializationUtils.java 100644 0 0 17030 11513702446 25454 0 ustar 0 0 /*
* 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.lang;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
/**
* Assists with the serialization process and performs additional functionality based
* on serialization.
*
*
* - Deep clone using serialization
*
- Serialize managing finally and IOException
*
- Deserialize managing finally and IOException
*
*
* This class throws exceptions for invalid null
inputs.
* Each method documents its behaviour in more detail.
*
* #ThreadSafe#
* @author Apache Software Foundation
* @author Nissim Karpenstein
* @author Janek Bogucki
* @author Daniel L. Rall
* @author Jeff Varszegi
* @author Gary Gregory
* @since 1.0
* @version $Id: SerializationUtils.java 1056988 2011-01-09 17:58:53Z niallp $
*/
public class SerializationUtils {
/**
* SerializationUtils instances should NOT be constructed in standard programming.
* Instead, the class should be used as SerializationUtils.clone(object)
.
*
* This constructor is public to permit tools that require a JavaBean instance
* to operate.
* @since 2.0
*/
public SerializationUtils() {
super();
}
// Clone
//-----------------------------------------------------------------------
/**
* Deep clone an Object
using serialization.
*
* This is many times slower than writing clone methods by hand
* on all objects in your object graph. However, for complex object
* graphs, or for those that don't support deep cloning this can
* be a simple alternative implementation. Of course all the objects
* must be Serializable
.
*
* @param object the Serializable
object to clone
* @return the cloned object
* @throws SerializationException (runtime) if the serialization fails
*/
public static Object clone(Serializable object) {
return deserialize(serialize(object));
}
// Serialize
//-----------------------------------------------------------------------
/**
* Serializes an Object
to the specified stream.
*
* The stream will be closed once the object is written.
* This avoids the need for a finally clause, and maybe also exception
* handling, in the application code.
*
* The stream passed in is not buffered internally within this method.
* This is the responsibility of your application if desired.
*
* @param obj the object to serialize to bytes, may be null
* @param outputStream the stream to write to, must not be null
* @throws IllegalArgumentException if outputStream
is null
* @throws SerializationException (runtime) if the serialization fails
*/
public static void serialize(Serializable obj, OutputStream outputStream) {
if (outputStream == null) {
throw new IllegalArgumentException("The OutputStream must not be null");
}
ObjectOutputStream out = null;
try {
// stream closed in the finally
out = new ObjectOutputStream(outputStream);
out.writeObject(obj);
} catch (IOException ex) {
throw new SerializationException(ex);
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException ex) {
// ignore close exception
}
}
}
/**
* Serializes an Object
to a byte array for
* storage/serialization.
*
* @param obj the object to serialize to bytes
* @return a byte[] with the converted Serializable
* @throws SerializationException (runtime) if the serialization fails
*/
public static byte[] serialize(Serializable obj) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
serialize(obj, baos);
return baos.toByteArray();
}
// Deserialize
//-----------------------------------------------------------------------
/**
* Deserializes an Object
from the specified stream.
*
* The stream will be closed once the object is written. This
* avoids the need for a finally clause, and maybe also exception
* handling, in the application code.
*
* The stream passed in is not buffered internally within this method.
* This is the responsibility of your application if desired.
*
* @param inputStream the serialized object input stream, must not be null
* @return the deserialized object
* @throws IllegalArgumentException if inputStream
is null
* @throws SerializationException (runtime) if the serialization fails
*/
public static Object deserialize(InputStream inputStream) {
if (inputStream == null) {
throw new IllegalArgumentException("The InputStream must not be null");
}
ObjectInputStream in = null;
try {
// stream closed in the finally
in = new ObjectInputStream(inputStream);
return in.readObject();
} catch (ClassNotFoundException ex) {
throw new SerializationException(ex);
} catch (IOException ex) {
throw new SerializationException(ex);
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
// ignore close exception
}
}
}
/**
* Deserializes a single Object
from an array of bytes.
*
* @param objectData the serialized object, must not be null
* @return the deserialized object
* @throws IllegalArgumentException if objectData
is null
* @throws SerializationException (runtime) if the serialization fails
*/
public static Object deserialize(byte[] objectData) {
if (objectData == null) {
throw new IllegalArgumentException("The byte[] must not be null");
}
ByteArrayInputStream bais = new ByteArrayInputStream(objectData);
return deserialize(bais);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/StringEscapeUtils.java 100644 0 0 103214 11513702446 25246 0 ustar 0 0 /*
* 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.lang;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Locale;
import org.apache.commons.lang.exception.NestableRuntimeException;
import org.apache.commons.lang.text.StrBuilder;
/**
* Escapes and unescapes String
s for
* Java, Java Script, HTML, XML, and SQL.
*
* #ThreadSafe#
* @author Apache Software Foundation
* @author Apache Jakarta Turbine
* @author Purple Technology
* @author Alexander Day Chaffee
* @author Antony Riley
* @author Helge Tesgaard
* @author Sean Brown
* @author Gary Gregory
* @author Phil Steitz
* @author Pete Gieser
* @since 2.0
* @version $Id: StringEscapeUtils.java 1057072 2011-01-10 01:55:57Z niallp $
*/
public class StringEscapeUtils {
private static final char CSV_DELIMITER = ',';
private static final char CSV_QUOTE = '"';
private static final String CSV_QUOTE_STR = String.valueOf(CSV_QUOTE);
private static final char[] CSV_SEARCH_CHARS = new char[] {CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, CharUtils.LF};
/**
* StringEscapeUtils
instances should NOT be constructed in
* standard programming.
*
* Instead, the class should be used as:
*
StringEscapeUtils.escapeJava("foo");
*
* This constructor is public to permit tools that require a JavaBean
* instance to operate.
*/
public StringEscapeUtils() {
super();
}
// Java and JavaScript
//--------------------------------------------------------------------------
/**
* Escapes the characters in a String
using Java String rules.
*
* Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.)
*
* So a tab becomes the characters '\\'
and
* 't'
.
*
* The only difference between Java strings and JavaScript strings
* is that in JavaScript, a single quote must be escaped.
*
* Example:
*
* input string: He didn't say, "Stop!"
* output string: He didn't say, \"Stop!\"
*
*
*
* @param str String to escape values in, may be null
* @return String with escaped values, null
if null string input
*/
public static String escapeJava(String str) {
return escapeJavaStyleString(str, false, false);
}
/**
* Escapes the characters in a String
using Java String rules to
* a Writer
.
*
* A null
string input has no effect.
*
* @see #escapeJava(java.lang.String)
* @param out Writer to write escaped string into
* @param str String to escape values in, may be null
* @throws IllegalArgumentException if the Writer is null
* @throws IOException if error occurs on underlying Writer
*/
public static void escapeJava(Writer out, String str) throws IOException {
escapeJavaStyleString(out, str, false, false);
}
/**
* Escapes the characters in a String
using JavaScript String rules.
* Escapes any values it finds into their JavaScript String form.
* Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.)
*
* So a tab becomes the characters '\\'
and
* 't'
.
*
* The only difference between Java strings and JavaScript strings
* is that in JavaScript, a single quote must be escaped.
*
* Example:
*
* input string: He didn't say, "Stop!"
* output string: He didn\'t say, \"Stop!\"
*
*
*
* @param str String to escape values in, may be null
* @return String with escaped values, null
if null string input
*/
public static String escapeJavaScript(String str) {
return escapeJavaStyleString(str, true, true);
}
/**
* Escapes the characters in a String
using JavaScript String rules
* to a Writer
.
*
* A null
string input has no effect.
*
* @see #escapeJavaScript(java.lang.String)
* @param out Writer to write escaped string into
* @param str String to escape values in, may be null
* @throws IllegalArgumentException if the Writer is null
* @throws IOException if error occurs on underlying Writer
**/
public static void escapeJavaScript(Writer out, String str) throws IOException {
escapeJavaStyleString(out, str, true, true);
}
/**
* Worker method for the {@link #escapeJavaScript(String)} method.
*
* @param str String to escape values in, may be null
* @param escapeSingleQuotes escapes single quotes if true
* @param escapeForwardSlash TODO
* @return the escaped string
*/
private static String escapeJavaStyleString(String str, boolean escapeSingleQuotes, boolean escapeForwardSlash) {
if (str == null) {
return null;
}
try {
StringWriter writer = new StringWriter(str.length() * 2);
escapeJavaStyleString(writer, str, escapeSingleQuotes, escapeForwardSlash);
return writer.toString();
} catch (IOException ioe) {
// this should never ever happen while writing to a StringWriter
throw new UnhandledException(ioe);
}
}
/**
* Worker method for the {@link #escapeJavaScript(String)} method.
*
* @param out write to receieve the escaped string
* @param str String to escape values in, may be null
* @param escapeSingleQuote escapes single quotes if true
* @param escapeForwardSlash TODO
* @throws IOException if an IOException occurs
*/
private static void escapeJavaStyleString(Writer out, String str, boolean escapeSingleQuote,
boolean escapeForwardSlash) throws IOException {
if (out == null) {
throw new IllegalArgumentException("The Writer must not be null");
}
if (str == null) {
return;
}
int sz;
sz = str.length();
for (int i = 0; i < sz; i++) {
char ch = str.charAt(i);
// handle unicode
if (ch > 0xfff) {
out.write("\\u" + hex(ch));
} else if (ch > 0xff) {
out.write("\\u0" + hex(ch));
} else if (ch > 0x7f) {
out.write("\\u00" + hex(ch));
} else if (ch < 32) {
switch (ch) {
case '\b' :
out.write('\\');
out.write('b');
break;
case '\n' :
out.write('\\');
out.write('n');
break;
case '\t' :
out.write('\\');
out.write('t');
break;
case '\f' :
out.write('\\');
out.write('f');
break;
case '\r' :
out.write('\\');
out.write('r');
break;
default :
if (ch > 0xf) {
out.write("\\u00" + hex(ch));
} else {
out.write("\\u000" + hex(ch));
}
break;
}
} else {
switch (ch) {
case '\'' :
if (escapeSingleQuote) {
out.write('\\');
}
out.write('\'');
break;
case '"' :
out.write('\\');
out.write('"');
break;
case '\\' :
out.write('\\');
out.write('\\');
break;
case '/' :
if (escapeForwardSlash) {
out.write('\\');
}
out.write('/');
break;
default :
out.write(ch);
break;
}
}
}
}
/**
* Returns an upper case hexadecimal String
for the given
* character.
*
* @param ch The character to convert.
* @return An upper case hexadecimal String
*/
private static String hex(char ch) {
return Integer.toHexString(ch).toUpperCase(Locale.ENGLISH);
}
/**
* Unescapes any Java literals found in the String
.
* For example, it will turn a sequence of '\'
and
* 'n'
into a newline character, unless the '\'
* is preceded by another '\'
.
*
* @param str the String
to unescape, may be null
* @return a new unescaped String
, null
if null string input
*/
public static String unescapeJava(String str) {
if (str == null) {
return null;
}
try {
StringWriter writer = new StringWriter(str.length());
unescapeJava(writer, str);
return writer.toString();
} catch (IOException ioe) {
// this should never ever happen while writing to a StringWriter
throw new UnhandledException(ioe);
}
}
/**
* Unescapes any Java literals found in the String
to a
* Writer
.
*
* For example, it will turn a sequence of '\'
and
* 'n'
into a newline character, unless the '\'
* is preceded by another '\'
.
*
* A null
string input has no effect.
*
* @param out the Writer
used to output unescaped characters
* @param str the String
to unescape, may be null
* @throws IllegalArgumentException if the Writer is null
* @throws IOException if error occurs on underlying Writer
*/
public static void unescapeJava(Writer out, String str) throws IOException {
if (out == null) {
throw new IllegalArgumentException("The Writer must not be null");
}
if (str == null) {
return;
}
int sz = str.length();
StrBuilder unicode = new StrBuilder(4);
boolean hadSlash = false;
boolean inUnicode = false;
for (int i = 0; i < sz; i++) {
char ch = str.charAt(i);
if (inUnicode) {
// if in unicode, then we're reading unicode
// values in somehow
unicode.append(ch);
if (unicode.length() == 4) {
// unicode now contains the four hex digits
// which represents our unicode character
try {
int value = Integer.parseInt(unicode.toString(), 16);
out.write((char) value);
unicode.setLength(0);
inUnicode = false;
hadSlash = false;
} catch (NumberFormatException nfe) {
throw new NestableRuntimeException("Unable to parse unicode value: " + unicode, nfe);
}
}
continue;
}
if (hadSlash) {
// handle an escaped value
hadSlash = false;
switch (ch) {
case '\\':
out.write('\\');
break;
case '\'':
out.write('\'');
break;
case '\"':
out.write('"');
break;
case 'r':
out.write('\r');
break;
case 'f':
out.write('\f');
break;
case 't':
out.write('\t');
break;
case 'n':
out.write('\n');
break;
case 'b':
out.write('\b');
break;
case 'u':
{
// uh-oh, we're in unicode country....
inUnicode = true;
break;
}
default :
out.write(ch);
break;
}
continue;
} else if (ch == '\\') {
hadSlash = true;
continue;
}
out.write(ch);
}
if (hadSlash) {
// then we're in the weird case of a \ at the end of the
// string, let's output it anyway.
out.write('\\');
}
}
/**
* Unescapes any JavaScript literals found in the String
.
*
* For example, it will turn a sequence of '\'
and 'n'
* into a newline character, unless the '\'
is preceded by another
* '\'
.
*
* @see #unescapeJava(String)
* @param str the String
to unescape, may be null
* @return A new unescaped String
, null
if null string input
*/
public static String unescapeJavaScript(String str) {
return unescapeJava(str);
}
/**
* Unescapes any JavaScript literals found in the String
to a
* Writer
.
*
* For example, it will turn a sequence of '\'
and 'n'
* into a newline character, unless the '\'
is preceded by another
* '\'
.
*
* A null
string input has no effect.
*
* @see #unescapeJava(Writer,String)
* @param out the Writer
used to output unescaped characters
* @param str the String
to unescape, may be null
* @throws IllegalArgumentException if the Writer is null
* @throws IOException if error occurs on underlying Writer
*/
public static void unescapeJavaScript(Writer out, String str) throws IOException {
unescapeJava(out, str);
}
// HTML and XML
//--------------------------------------------------------------------------
/**
* Escapes the characters in a String
using HTML entities.
*
*
* For example:
*
* "bread" & "butter"
* becomes:
*
* "bread" & "butter"
.
*
*
* Supports all known HTML 4.0 entities, including funky accents.
* Note that the commonly used apostrophe escape character (')
* is not a legal entity and so is not supported).
*
* @param str the String
to escape, may be null
* @return a new escaped String
, null
if null string input
*
* @see #unescapeHtml(String)
* @see ISO Entities
* @see HTML 3.2 Character Entities for ISO Latin-1
* @see HTML 4.0 Character entity references
* @see HTML 4.01 Character References
* @see HTML 4.01 Code positions
*/
public static String escapeHtml(String str) {
if (str == null) {
return null;
}
try {
StringWriter writer = new StringWriter ((int)(str.length() * 1.5));
escapeHtml(writer, str);
return writer.toString();
} catch (IOException ioe) {
//should be impossible
throw new UnhandledException(ioe);
}
}
/**
* Escapes the characters in a String
using HTML entities and writes
* them to a Writer
.
*
*
* For example:
*
* "bread" & "butter"
* becomes:
* "bread" & "butter"
.
*
* Supports all known HTML 4.0 entities, including funky accents.
* Note that the commonly used apostrophe escape character (')
* is not a legal entity and so is not supported).
*
* @param writer the writer receiving the escaped string, not null
* @param string the String
to escape, may be null
* @throws IllegalArgumentException if the writer is null
* @throws IOException when Writer
passed throws the exception from
* calls to the {@link Writer#write(int)} methods.
*
* @see #escapeHtml(String)
* @see #unescapeHtml(String)
* @see ISO Entities
* @see HTML 3.2 Character Entities for ISO Latin-1
* @see HTML 4.0 Character entity references
* @see HTML 4.01 Character References
* @see HTML 4.01 Code positions
*/
public static void escapeHtml(Writer writer, String string) throws IOException {
if (writer == null ) {
throw new IllegalArgumentException ("The Writer must not be null.");
}
if (string == null) {
return;
}
Entities.HTML40.escape(writer, string);
}
//-----------------------------------------------------------------------
/**
* Unescapes a string containing entity escapes to a string
* containing the actual Unicode characters corresponding to the
* escapes. Supports HTML 4.0 entities.
*
* For example, the string "<Français>"
* will become "<Français>"
*
* If an entity is unrecognized, it is left alone, and inserted
* verbatim into the result string. e.g. ">&zzzz;x" will
* become ">&zzzz;x".
*
* @param str the String
to unescape, may be null
* @return a new unescaped String
, null
if null string input
* @see #escapeHtml(Writer, String)
*/
public static String unescapeHtml(String str) {
if (str == null) {
return null;
}
try {
StringWriter writer = new StringWriter ((int)(str.length() * 1.5));
unescapeHtml(writer, str);
return writer.toString();
} catch (IOException ioe) {
//should be impossible
throw new UnhandledException(ioe);
}
}
/**
* Unescapes a string containing entity escapes to a string
* containing the actual Unicode characters corresponding to the
* escapes. Supports HTML 4.0 entities.
*
* For example, the string "<Français>"
* will become "<Français>"
*
* If an entity is unrecognized, it is left alone, and inserted
* verbatim into the result string. e.g. ">&zzzz;x" will
* become ">&zzzz;x".
*
* @param writer the writer receiving the unescaped string, not null
* @param string the String
to unescape, may be null
* @throws IllegalArgumentException if the writer is null
* @throws IOException if an IOException occurs
* @see #escapeHtml(String)
*/
public static void unescapeHtml(Writer writer, String string) throws IOException {
if (writer == null ) {
throw new IllegalArgumentException ("The Writer must not be null.");
}
if (string == null) {
return;
}
Entities.HTML40.unescape(writer, string);
}
//-----------------------------------------------------------------------
/**
* Escapes the characters in a String
using XML entities.
*
* For example: "bread" & "butter" =>
* "bread" & "butter".
*
*
* Supports only the five basic XML entities (gt, lt, quot, amp, apos).
* Does not support DTDs or external entities.
*
* Note that unicode characters greater than 0x7f are currently escaped to
* their numerical \\u equivalent. This may change in future releases.
*
* @param writer the writer receiving the unescaped string, not null
* @param str the String
to escape, may be null
* @throws IllegalArgumentException if the writer is null
* @throws IOException if there is a problem writing
* @see #unescapeXml(java.lang.String)
*/
public static void escapeXml(Writer writer, String str) throws IOException {
if (writer == null ) {
throw new IllegalArgumentException ("The Writer must not be null.");
}
if (str == null) {
return;
}
Entities.XML.escape(writer, str);
}
/**
* Escapes the characters in a String
using XML entities.
*
* For example: "bread" & "butter" =>
* "bread" & "butter".
*
*
* Supports only the five basic XML entities (gt, lt, quot, amp, apos).
* Does not support DTDs or external entities.
*
* Note that unicode characters greater than 0x7f are currently escaped to
* their numerical \\u equivalent. This may change in future releases.
*
* @param str the String
to escape, may be null
* @return a new escaped String
, null
if null string input
* @see #unescapeXml(java.lang.String)
*/
public static String escapeXml(String str) {
if (str == null) {
return null;
}
return Entities.XML.escape(str);
}
//-----------------------------------------------------------------------
/**
* Unescapes a string containing XML entity escapes to a string
* containing the actual Unicode characters corresponding to the
* escapes.
*
* Supports only the five basic XML entities (gt, lt, quot, amp, apos).
* Does not support DTDs or external entities.
*
* Note that numerical \\u unicode codes are unescaped to their respective
* unicode characters. This may change in future releases.
*
* @param writer the writer receiving the unescaped string, not null
* @param str the String
to unescape, may be null
* @throws IllegalArgumentException if the writer is null
* @throws IOException if there is a problem writing
* @see #escapeXml(String)
*/
public static void unescapeXml(Writer writer, String str) throws IOException {
if (writer == null ) {
throw new IllegalArgumentException ("The Writer must not be null.");
}
if (str == null) {
return;
}
Entities.XML.unescape(writer, str);
}
/**
* Unescapes a string containing XML entity escapes to a string
* containing the actual Unicode characters corresponding to the
* escapes.
*
* Supports only the five basic XML entities (gt, lt, quot, amp, apos).
* Does not support DTDs or external entities.
*
* Note that numerical \\u unicode codes are unescaped to their respective
* unicode characters. This may change in future releases.
*
* @param str the String
to unescape, may be null
* @return a new unescaped String
, null
if null string input
* @see #escapeXml(String)
*/
public static String unescapeXml(String str) {
if (str == null) {
return null;
}
return Entities.XML.unescape(str);
}
//-----------------------------------------------------------------------
/**
* Escapes the characters in a String
to be suitable to pass to
* an SQL query.
*
* For example,
*
statement.executeQuery("SELECT * FROM MOVIES WHERE TITLE='" +
* StringEscapeUtils.escapeSql("McHale's Navy") +
* "'");
*
*
* At present, this method only turns single-quotes into doubled single-quotes
* ("McHale's Navy"
=> "McHale''s Navy"
). It does not
* handle the cases of percent (%) or underscore (_) for use in LIKE clauses.
*
* see http://www.jguru.com/faq/view.jsp?EID=8881
* @param str the string to escape, may be null
* @return a new String, escaped for SQL, null
if null string input
*/
public static String escapeSql(String str) {
if (str == null) {
return null;
}
return StringUtils.replace(str, "'", "''");
}
//-----------------------------------------------------------------------
/**
* Returns a String
value for a CSV column enclosed in double quotes,
* if required.
*
* If the value contains a comma, newline or double quote, then the
* String value is returned enclosed in double quotes.
*
*
* Any double quote characters in the value are escaped with another double quote.
*
* If the value does not contain a comma, newline or double quote, then the
* String value is returned unchanged.
*
*
* see Wikipedia and
* RFC 4180.
*
* @param str the input CSV column String, may be null
* @return the input String, enclosed in double quotes if the value contains a comma,
* newline or double quote, null
if null string input
* @since 2.4
*/
public static String escapeCsv(String str) {
if (StringUtils.containsNone(str, CSV_SEARCH_CHARS)) {
return str;
}
try {
StringWriter writer = new StringWriter();
escapeCsv(writer, str);
return writer.toString();
} catch (IOException ioe) {
// this should never ever happen while writing to a StringWriter
throw new UnhandledException(ioe);
}
}
/**
* Writes a String
value for a CSV column enclosed in double quotes,
* if required.
*
* If the value contains a comma, newline or double quote, then the
* String value is written enclosed in double quotes.
*
*
* Any double quote characters in the value are escaped with another double quote.
*
* If the value does not contain a comma, newline or double quote, then the
* String value is written unchanged (null values are ignored).
*
*
* see Wikipedia and
* RFC 4180.
*
* @param str the input CSV column String, may be null
* @param out Writer to write input string to, enclosed in double quotes if it contains
* a comma, newline or double quote
* @throws IOException if error occurs on underlying Writer
* @since 2.4
*/
public static void escapeCsv(Writer out, String str) throws IOException {
if (StringUtils.containsNone(str, CSV_SEARCH_CHARS)) {
if (str != null) {
out.write(str);
}
return;
}
out.write(CSV_QUOTE);
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c == CSV_QUOTE) {
out.write(CSV_QUOTE); // escape double quote
}
out.write(c);
}
out.write(CSV_QUOTE);
}
/**
* Returns a String
value for an unescaped CSV column.
*
* If the value is enclosed in double quotes, and contains a comma, newline
* or double quote, then quotes are removed.
*
*
* Any double quote escaped characters (a pair of double quotes) are unescaped
* to just one double quote.
*
* If the value is not enclosed in double quotes, or is and does not contain a
* comma, newline or double quote, then the String value is returned unchanged.
*
*
* see Wikipedia and
* RFC 4180.
*
* @param str the input CSV column String, may be null
* @return the input String, with enclosing double quotes removed and embedded double
* quotes unescaped, null
if null string input
* @since 2.4
*/
public static String unescapeCsv(String str) {
if (str == null) {
return null;
}
try {
StringWriter writer = new StringWriter();
unescapeCsv(writer, str);
return writer.toString();
} catch (IOException ioe) {
// this should never ever happen while writing to a StringWriter
throw new UnhandledException(ioe);
}
}
/**
* Returns a String
value for an unescaped CSV column.
*
* If the value is enclosed in double quotes, and contains a comma, newline
* or double quote, then quotes are removed.
*
*
* Any double quote escaped characters (a pair of double quotes) are unescaped
* to just one double quote.
*
* If the value is not enclosed in double quotes, or is and does not contain a
* comma, newline or double quote, then the String value is returned unchanged.
*
*
* see Wikipedia and
* RFC 4180.
*
* @param str the input CSV column String, may be null
* @param out Writer to write the input String to, with enclosing double quotes
* removed and embedded double quotes unescaped, null
if null string input
* @throws IOException if error occurs on underlying Writer
* @since 2.4
*/
public static void unescapeCsv(Writer out, String str) throws IOException {
if (str == null) {
return;
}
if (str.length() < 2) {
out.write(str);
return;
}
if ( str.charAt(0) != CSV_QUOTE || str.charAt(str.length() - 1) != CSV_QUOTE ) {
out.write(str);
return;
}
// strip quotes
String quoteless = str.substring(1, str.length() - 1);
if ( StringUtils.containsAny(quoteless, CSV_SEARCH_CHARS) ) {
// deal with escaped quotes; ie) ""
str = StringUtils.replace(quoteless, CSV_QUOTE_STR + CSV_QUOTE_STR, CSV_QUOTE_STR);
}
out.write(str);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/StringUtils.java 100644 0 0 1014637 11513702445 24157 0 ustar 0 0 /*
* 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.lang;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import org.apache.commons.lang.text.StrBuilder;
/**
* Operations on {@link java.lang.String} that are
* null
safe.
*
*
* - IsEmpty/IsBlank
* - checks if a String contains text
* - Trim/Strip
* - removes leading and trailing whitespace
* - Equals
* - compares two strings null-safe
* - startsWith
* - check if a String starts with a prefix null-safe
* - endsWith
* - check if a String ends with a suffix null-safe
* - IndexOf/LastIndexOf/Contains
* - null-safe index-of checks
*
- IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut
* - index-of any of a set of Strings
* - ContainsOnly/ContainsNone/ContainsAny
* - does String contains only/none/any of these characters
* - Substring/Left/Right/Mid
* - null-safe substring extractions
* - SubstringBefore/SubstringAfter/SubstringBetween
* - substring extraction relative to other strings
* - Split/Join
* - splits a String into an array of substrings and vice versa
* - Remove/Delete
* - removes part of a String
* - Replace/Overlay
* - Searches a String and replaces one String with another
* - Chomp/Chop
* - removes the last part of a String
* - LeftPad/RightPad/Center/Repeat
* - pads a String
* - UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize
* - changes the case of a String
* - CountMatches
* - counts the number of occurrences of one String in another
* - IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable
* - checks the characters in a String
* - DefaultString
* - protects against a null input String
* - Reverse/ReverseDelimited
* - reverses a String
* - Abbreviate
* - abbreviates a string using ellipsis
* - Difference
* - compares Strings and reports on their differences
* - LevensteinDistance
* - the number of changes needed to change one String into another
*
*
* The StringUtils
class defines certain words related to
* String handling.
*
*
* - null -
null
* - empty - a zero-length string (
""
)
* - space - the space character (
' '
, char 32)
* - whitespace - the characters defined by {@link Character#isWhitespace(char)}
* - trim - the characters <= 32 as in {@link String#trim()}
*
*
* StringUtils
handles null
input Strings quietly.
* That is to say that a null
input will return null
.
* Where a boolean
or int
is being returned
* details vary by method.
*
* A side effect of the null
handling is that a
* NullPointerException
should be considered a bug in
* StringUtils
(except for deprecated methods).
*
* Methods in this class give sample code to explain their operation.
* The symbol *
is used to indicate any input including null
.
*
* #ThreadSafe#
* @see java.lang.String
* @author Apache Software Foundation
* @author Apache Jakarta Turbine
* @author Jon S. Stevens
* @author Daniel L. Rall
* @author Greg Coladonato
* @author Ed Korthof
* @author Rand McNeely
* @author Fredrik Westermarck
* @author Holger Krauth
* @author Alexander Day Chaffee
* @author Henning P. Schmiedehausen
* @author Arun Mammen Thomas
* @author Gary Gregory
* @author Phil Steitz
* @author Al Chou
* @author Michael Davey
* @author Reuben Sivan
* @author Chris Hyzer
* @author Scott Johnson
* @since 1.0
* @version $Id: StringUtils.java 1058365 2011-01-13 00:04:49Z niallp $
*/
//@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 ""
.
* @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;
/**
* StringUtils
instances should NOT be constructed in
* standard programming. Instead, the class should be used as
* 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 String 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 String.
* That functionality is available in isBlank().
*
* @param str the String to check, may be null
* @return true
if the String is empty or null
*/
public static boolean isEmpty(String str) {
return str == null || str.length() == 0;
}
/**
* Checks if a String 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 str the String to check, may be null
* @return true
if the String is not empty and not null
*/
public static boolean isNotEmpty(String str) {
return !StringUtils.isEmpty(str);
}
/**
* Checks if a String is whitespace, empty ("") or null.
*
*
* StringUtils.isBlank(null) = true
* StringUtils.isBlank("") = true
* StringUtils.isBlank(" ") = true
* StringUtils.isBlank("bob") = false
* StringUtils.isBlank(" bob ") = false
*
*
* @param str the String to check, may be null
* @return true
if the String is null, empty or whitespace
* @since 2.0
*/
public static boolean isBlank(String str) {
int strLen;
if (str == null || (strLen = str.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if ((Character.isWhitespace(str.charAt(i)) == false)) {
return false;
}
}
return true;
}
/**
* Checks if a String 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 str the String to check, may be null
* @return true
if the String is
* not empty and not null and not whitespace
* @since 2.0
*/
public static boolean isNotBlank(String str) {
return !StringUtils.isBlank(str);
}
// Trim
//-----------------------------------------------------------------------
/**
* Removes control characters (char <= 32) from both
* ends of this String, handling null
by returning
* an empty String ("").
*
*
* StringUtils.clean(null) = ""
* StringUtils.clean("") = ""
* StringUtils.clean("abc") = "abc"
* StringUtils.clean(" abc ") = "abc"
* StringUtils.clean(" ") = ""
*
*
* @see java.lang.String#trim()
* @param str the String to clean, may be null
* @return the trimmed text, never null
* @deprecated Use the clearer named {@link #trimToEmpty(String)}.
* Method will be removed in Commons Lang 3.0.
*/
public static String clean(String str) {
return str == null ? EMPTY : str.trim();
}
/**
* Removes control characters (char <= 32) from both
* ends of this String, handling null
by returning
* 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, 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 null
if the String is
* empty ("") after the trim or if it is 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,
* 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 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 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 null
input String returns 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, 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
* 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,
* 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 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 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 null
input String returns null
.
* An empty string ("") input returns the empty string.
*
* If the stripChars String is 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, 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 null
input String returns null
.
* An empty string ("") input returns the empty string.
*
* If the stripChars String is 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, 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 null
input String returns null
.
* An empty string ("") input returns the empty string.
*
* If the stripChars String is 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, 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 null
array will return null
.
* An empty array will return itself.
* A 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, 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 null
array will return null
.
* An empty array will return itself.
* A null
array entry will be ignored.
* A 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, 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;
}
// Equals
//-----------------------------------------------------------------------
/**
* Compares two Strings, returning true
if they are equal.
*
* null
s are handled without exceptions. Two 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 str1 the first String, may be null
* @param str2 the second String, may be null
* @return true
if the Strings are equal, case sensitive, or
* both null
*/
public static boolean equals(String str1, String str2) {
return str1 == null ? str2 == null : str1.equals(str2);
}
/**
* Compares two Strings, returning true
if they are equal ignoring
* the case.
*
* null
s are handled without exceptions. Two 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
*
*
* @see java.lang.String#equalsIgnoreCase(String)
* @param str1 the first String, may be null
* @param str2 the second String, may be null
* @return true
if the Strings are equal, case insensitive, or
* both null
*/
public static boolean equalsIgnoreCase(String str1, String str2) {
return str1 == null ? str2 == null : str1.equalsIgnoreCase(str2);
}
// IndexOf
//-----------------------------------------------------------------------
/**
* Finds the first index within a String, handling null
.
* This method uses {@link String#indexOf(int)}.
*
* A null
or empty ("") String will return INDEX_NOT_FOUND (-1)
.
*
*
* StringUtils.indexOf(null, *) = -1
* StringUtils.indexOf("", *) = -1
* StringUtils.indexOf("aabaabaa", 'a') = 0
* StringUtils.indexOf("aabaabaa", 'b') = 2
*
*
* @param str the String to check, may be null
* @param searchChar the character to find
* @return the first index of the search character,
* -1 if no match or null
string input
* @since 2.0
*/
public static int indexOf(String str, char searchChar) {
if (isEmpty(str)) {
return INDEX_NOT_FOUND;
}
return str.indexOf(searchChar);
}
/**
* Finds the first index within a String from a start position,
* handling null
.
* This method uses {@link String#indexOf(int, int)}.
*
* A null
or empty ("") String will return (INDEX_NOT_FOUND) -1
.
* A negative start position is treated as zero.
* A start position greater than the string length returns -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 str the String 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 null
string input
* @since 2.0
*/
public static int indexOf(String str, char searchChar, int startPos) {
if (isEmpty(str)) {
return INDEX_NOT_FOUND;
}
return str.indexOf(searchChar, startPos);
}
/**
* Finds the first index within a String, handling null
.
* This method uses {@link String#indexOf(String)}.
*
* A null
String will return -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 str the String to check, may be null
* @param searchStr the String to find, may be null
* @return the first index of the search String,
* -1 if no match or null
string input
* @since 2.0
*/
public static int indexOf(String str, String searchStr) {
if (str == null || searchStr == null) {
return INDEX_NOT_FOUND;
}
return str.indexOf(searchStr);
}
/**
* Finds the n-th index within a String, handling null
.
* This method uses {@link String#indexOf(String)}.
*
* A null
String will return -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(String str, int n)' may be implemented as:
*
*
* str.substring(0, lastOrdinalIndexOf(str, "\n", n))
*
*
* @param str the String to check, may be null
* @param searchStr the String to find, may be null
* @param ordinal the n-th searchStr
to find
* @return the n-th index of the search String,
* -1
(INDEX_NOT_FOUND
) if no match or null
string input
* @since 2.1
*/
public static int ordinalIndexOf(String str, String searchStr, int ordinal) {
return ordinalIndexOf(str, searchStr, ordinal, false);
}
/**
* Finds the n-th index within a String, handling null
.
* This method uses {@link String#indexOf(String)}.
*
* A null
String will return -1
.
*
* @param str the String to check, may be null
* @param searchStr the String to find, may be null
* @param ordinal the n-th searchStr
to find
* @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
* @return the n-th index of the search String,
* -1
(INDEX_NOT_FOUND
) if no match or null
string input
*/
// Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int)
private static int ordinalIndexOf(String str, String 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 = str.lastIndexOf(searchStr, index - 1);
} else {
index = str.indexOf(searchStr, index + 1);
}
if (index < 0) {
return index;
}
found++;
} while (found < ordinal);
return index;
}
/**
* Finds the first index within a String, handling null
.
* This method uses {@link String#indexOf(String, int)}.
*
* A null
String will return -1
.
* A negative start position is treated as zero.
* An empty ("") search String always matches.
* A start position greater than the string length only matches
* an empty search String.
*
*
* 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 str the String to check, may be null
* @param searchStr the String to find, may be null
* @param startPos the start position, negative treated as zero
* @return the first index of the search String,
* -1 if no match or null
string input
* @since 2.0
*/
public static int indexOf(String str, String searchStr, int startPos) {
if (str == null || searchStr == null) {
return INDEX_NOT_FOUND;
}
// JDK1.2/JDK1.3 have a bug, when startPos > str.length for "", hence
if (searchStr.length() == 0 && startPos >= str.length()) {
return str.length();
}
return str.indexOf(searchStr, startPos);
}
/**
* Case in-sensitive find of the first index within a String.
*
* A null
String will return -1
.
* A negative start position is treated as zero.
* An empty ("") search String always matches.
* A start position greater than the string length only matches
* an empty search String.
*
*
* 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 String to check, may be null
* @param searchStr the String to find, may be null
* @return the first index of the search String,
* -1 if no match or null
string input
* @since 2.5
*/
public static int indexOfIgnoreCase(String str, String searchStr) {
return indexOfIgnoreCase(str, searchStr, 0);
}
/**
* Case in-sensitive find of the first index within a String
* from the specified position.
*
* A null
String will return -1
.
* A negative start position is treated as zero.
* An empty ("") search String always matches.
* A start position greater than the string length only matches
* an empty search String.
*
*
* 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 String to check, may be null
* @param searchStr the String to find, may be null
* @param startPos the start position, negative treated as zero
* @return the first index of the search String,
* -1 if no match or null
string input
* @since 2.5
*/
public static int indexOfIgnoreCase(String str, String 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 (str.regionMatches(true, i, searchStr, 0, searchStr.length())) {
return i;
}
}
return INDEX_NOT_FOUND;
}
// LastIndexOf
//-----------------------------------------------------------------------
/**
* Finds the last index within a String, handling null
.
* This method uses {@link String#lastIndexOf(int)}.
*
* A null
or empty ("") String will return -1
.
*
*
* StringUtils.lastIndexOf(null, *) = -1
* StringUtils.lastIndexOf("", *) = -1
* StringUtils.lastIndexOf("aabaabaa", 'a') = 7
* StringUtils.lastIndexOf("aabaabaa", 'b') = 5
*
*
* @param str the String to check, may be null
* @param searchChar the character to find
* @return the last index of the search character,
* -1 if no match or null
string input
* @since 2.0
*/
public static int lastIndexOf(String str, char searchChar) {
if (isEmpty(str)) {
return INDEX_NOT_FOUND;
}
return str.lastIndexOf(searchChar);
}
/**
* Finds the last index within a String from a start position,
* handling null
.
* This method uses {@link String#lastIndexOf(int, int)}.
*
* A null
or empty ("") String will return -1
.
* A negative start position returns -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 str the String 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 null
string input
* @since 2.0
*/
public static int lastIndexOf(String str, char searchChar, int startPos) {
if (isEmpty(str)) {
return INDEX_NOT_FOUND;
}
return str.lastIndexOf(searchChar, startPos);
}
/**
* Finds the last index within a String, handling null
.
* This method uses {@link String#lastIndexOf(String)}.
*
* A null
String will return -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 str the String to check, may be null
* @param searchStr the String to find, may be null
* @return the last index of the search String,
* -1 if no match or null
string input
* @since 2.0
*/
public static int lastIndexOf(String str, String searchStr) {
if (str == null || searchStr == null) {
return INDEX_NOT_FOUND;
}
return str.lastIndexOf(searchStr);
}
/**
* Finds the n-th last index within a String, handling null
.
* This method uses {@link String#lastIndexOf(String)}.
*
* A null
String will return -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(String str, int n)' may be implemented as:
*
*
* str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
*
*
* @param str the String to check, may be null
* @param searchStr the String to find, may be null
* @param ordinal the n-th last searchStr
to find
* @return the n-th last index of the search String,
* -1
(INDEX_NOT_FOUND
) if no match or null
string input
* @since 2.5
*/
public static int lastOrdinalIndexOf(String str, String searchStr, int ordinal) {
return ordinalIndexOf(str, searchStr, ordinal, true);
}
/**
* Finds the first index within a String, handling null
.
* This method uses {@link String#lastIndexOf(String, int)}.
*
* A null
String will return -1
.
* A negative start position returns -1
.
* An empty ("") search String 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 str the String to check, may be null
* @param searchStr the String to find, may be null
* @param startPos the start position, negative treated as zero
* @return the first index of the search String,
* -1 if no match or null
string input
* @since 2.0
*/
public static int lastIndexOf(String str, String searchStr, int startPos) {
if (str == null || searchStr == null) {
return INDEX_NOT_FOUND;
}
return str.lastIndexOf(searchStr, startPos);
}
/**
* Case in-sensitive find of the last index within a String.
*
* A null
String will return -1
.
* A negative start position returns -1
.
* An empty ("") search String 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 String to check, may be null
* @param searchStr the String to find, may be null
* @return the first index of the search String,
* -1 if no match or null
string input
* @since 2.5
*/
public static int lastIndexOfIgnoreCase(String str, String 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 String
* from the specified position.
*
* A null
String will return -1
.
* A negative start position returns -1
.
* An empty ("") search String 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 String to check, may be null
* @param searchStr the String to find, may be null
* @param startPos the start position
* @return the first index of the search String,
* -1 if no match or null
string input
* @since 2.5
*/
public static int lastIndexOfIgnoreCase(String str, String 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 (str.regionMatches(true, i, searchStr, 0, searchStr.length())) {
return i;
}
}
return INDEX_NOT_FOUND;
}
// Contains
//-----------------------------------------------------------------------
/**
* Checks if String contains a search character, handling null
.
* This method uses {@link String#indexOf(int)}.
*
* A null
or empty ("") String will return false
.
*
*
* StringUtils.contains(null, *) = false
* StringUtils.contains("", *) = false
* StringUtils.contains("abc", 'a') = true
* StringUtils.contains("abc", 'z') = false
*
*
* @param str the String to check, may be null
* @param searchChar the character to find
* @return true if the String contains the search character,
* false if not or null
string input
* @since 2.0
*/
public static boolean contains(String str, char searchChar) {
if (isEmpty(str)) {
return false;
}
return str.indexOf(searchChar) >= 0;
}
/**
* Checks if String contains a search String, handling null
.
* This method uses {@link String#indexOf(String)}.
*
* A null
String will return 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 str the String to check, may be null
* @param searchStr the String to find, may be null
* @return true if the String contains the search String,
* false if not or null
string input
* @since 2.0
*/
public static boolean contains(String str, String searchStr) {
if (str == null || searchStr == null) {
return false;
}
return str.indexOf(searchStr) >= 0;
}
/**
* Checks if String contains a search String irrespective of case,
* handling null
. Case-insensitivity is defined as by
* {@link String#equalsIgnoreCase(String)}.
*
*
A null
String will return 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 String to check, may be null
* @param searchStr the String to find, may be null
* @return true if the String contains the search String irrespective of
* case or false if not or null
string input
*/
public static boolean containsIgnoreCase(String str, String 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 (str.regionMatches(true, i, searchStr, 0, len)) {
return true;
}
}
return false;
}
// IndexOfAny chars
//-----------------------------------------------------------------------
/**
* Search a String to find the first index of any
* character in the given set of characters.
*
* A null
String will return -1
.
* A null
or zero length search array will return -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 str the String 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
*/
public static int indexOfAny(String str, char[] searchChars) {
if (isEmpty(str) || ArrayUtils.isEmpty(searchChars)) {
return INDEX_NOT_FOUND;
}
int csLen = str.length();
int csLast = csLen - 1;
int searchLen = searchChars.length;
int searchLast = searchLen - 1;
for (int i = 0; i < csLen; i++) {
char ch = str.charAt(i);
for (int j = 0; j < searchLen; j++) {
if (searchChars[j] == ch) {
if (i < csLast && j < searchLast && CharUtils.isHighSurrogate(ch)) {
// ch is a supplementary character
if (searchChars[j + 1] == str.charAt(i + 1)) {
return i;
}
} else {
return i;
}
}
}
}
return INDEX_NOT_FOUND;
}
/**
* Search a String to find the first index of any
* character in the given set of characters.
*
* A null
String will return -1
.
* A null
search string will return -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 str the String 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
*/
public static int indexOfAny(String str, String searchChars) {
if (isEmpty(str) || isEmpty(searchChars)) {
return INDEX_NOT_FOUND;
}
return indexOfAny(str, searchChars.toCharArray());
}
// ContainsAny
//-----------------------------------------------------------------------
/**
* Checks if the String contains any character in the given
* set of characters.
*
* A null
String will return false
.
* A null
or zero length search array will return 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 str the String to check, may be null
* @param searchChars the chars to search for, may be null
* @return the true
if any of the chars are found,
* false
if no match or null input
* @since 2.4
*/
public static boolean containsAny(String str, char[] searchChars) {
if (isEmpty(str) || ArrayUtils.isEmpty(searchChars)) {
return false;
}
int csLength = str.length();
int searchLength = searchChars.length;
int csLast = csLength - 1;
int searchLast = searchLength - 1;
for (int i = 0; i < csLength; i++) {
char ch = str.charAt(i);
for (int j = 0; j < searchLength; j++) {
if (searchChars[j] == ch) {
if (CharUtils.isHighSurrogate(ch)) {
if (j == searchLast) {
// missing low surrogate, fine, like String.indexOf(String)
return true;
}
if (i < csLast && searchChars[j + 1] == str.charAt(i + 1)) {
return true;
}
} else {
// ch is in the Basic Multilingual Plane
return true;
}
}
}
}
return false;
}
/**
*
* Checks if the String contains any character in the given set of characters.
*
*
*
* A null
String will return false
. A null
search string will return
* 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 str
* the String to check, may be null
* @param searchChars
* the chars to search for, may be null
* @return the true
if any of the chars are found, false
if no match or null input
* @since 2.4
*/
public static boolean containsAny(String str, String searchChars) {
if (searchChars == null) {
return false;
}
return containsAny(str, searchChars.toCharArray());
}
// IndexOfAnyBut chars
//-----------------------------------------------------------------------
/**
* Search a String to find the first index of any
* character not in the given set of characters.
*
* A null
String will return -1
.
* A null
or zero length search array will return -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 str the String 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
*/
public static int indexOfAnyBut(String str, char[] searchChars) {
if (isEmpty(str) || ArrayUtils.isEmpty(searchChars)) {
return INDEX_NOT_FOUND;
}
int csLen = str.length();
int csLast = csLen - 1;
int searchLen = searchChars.length;
int searchLast = searchLen - 1;
outer:
for (int i = 0; i < csLen; i++) {
char ch = str.charAt(i);
for (int j = 0; j < searchLen; j++) {
if (searchChars[j] == ch) {
if (i < csLast && j < searchLast && CharUtils.isHighSurrogate(ch)) {
if (searchChars[j + 1] == str.charAt(i + 1)) {
continue outer;
}
} else {
continue outer;
}
}
}
return i;
}
return INDEX_NOT_FOUND;
}
/**
* Search a String to find the first index of any
* character not in the given set of characters.
*
* A null
String will return -1
.
* A null
or empty search string will return -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 str the String 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
*/
public static int indexOfAnyBut(String str, String searchChars) {
if (isEmpty(str) || isEmpty(searchChars)) {
return INDEX_NOT_FOUND;
}
int strLen = str.length();
for (int i = 0; i < strLen; i++) {
char ch = str.charAt(i);
boolean chFound = searchChars.indexOf(ch) >= 0;
if (i + 1 < strLen && CharUtils.isHighSurrogate(ch)) {
char ch2 = str.charAt(i + 1);
if (chFound && searchChars.indexOf(ch2) < 0) {
return i;
}
} else {
if (!chFound) {
return i;
}
}
}
return INDEX_NOT_FOUND;
}
// ContainsOnly
//-----------------------------------------------------------------------
/**
* Checks if the String contains only certain characters.
*
* A null
String will return false
.
* A null
valid character array will return false
.
* An empty String (length()=0) always returns 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 str 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
*/
public static boolean containsOnly(String str, char[] valid) {
// All these pre-checks are to maintain API with an older version
if ((valid == null) || (str == null)) {
return false;
}
if (str.length() == 0) {
return true;
}
if (valid.length == 0) {
return false;
}
return indexOfAnyBut(str, valid) == INDEX_NOT_FOUND;
}
/**
* Checks if the String contains only certain characters.
*
* A null
String will return false
.
* A null
valid character String will return false
.
* An empty String (length()=0) always returns 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 str the String 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
*/
public static boolean containsOnly(String str, String validChars) {
if (str == null || validChars == null) {
return false;
}
return containsOnly(str, validChars.toCharArray());
}
// ContainsNone
//-----------------------------------------------------------------------
/**
* Checks that the String does not contain certain characters.
*
* A null
String will return true
.
* A null
invalid character array will return true
.
* An empty String (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 str the String 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
*/
public static boolean containsNone(String str, char[] searchChars) {
if (str == null || searchChars == null) {
return true;
}
int csLen = str.length();
int csLast = csLen - 1;
int searchLen = searchChars.length;
int searchLast = searchLen - 1;
for (int i = 0; i < csLen; i++) {
char ch = str.charAt(i);
for (int j = 0; j < searchLen; j++) {
if (searchChars[j] == ch) {
if (CharUtils.isHighSurrogate(ch)) {
if (j == searchLast) {
// missing low surrogate, fine, like String.indexOf(String)
return false;
}
if (i < csLast && searchChars[j + 1] == str.charAt(i + 1)) {
return false;
}
} else {
// ch is in the Basic Multilingual Plane
return false;
}
}
}
}
return true;
}
/**
* Checks that the String does not contain certain characters.
*
* A null
String will return true
.
* A null
invalid character array will return 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 str the String 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
*/
public static boolean containsNone(String str, String invalidChars) {
if (str == null || invalidChars == null) {
return true;
}
return containsNone(str, invalidChars.toCharArray());
}
// IndexOfAny strings
//-----------------------------------------------------------------------
/**
* Find the first index of any of a set of potential substrings.
*
* A null
String will return -1
.
* A null
or zero length search array will return -1
.
* A null
search array entry will be ignored, but a search
* array containing "" will return 0
if str
is not
* null. This method uses {@link String#indexOf(String)}.
*
*
* 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 String to check, may be null
* @param searchStrs the Strings to search for, may be null
* @return the first index of any of the searchStrs in str, -1 if no match
*/
public static int indexOfAny(String str, String[] 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++) {
String search = searchStrs[i];
if (search == null) {
continue;
}
tmp = str.indexOf(search);
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 null
String will return -1
.
* A null
search array will return -1
.
* A null
or zero length search array entry will be ignored,
* but a search array containing "" will return the length of str
* if str
is not null. This method uses {@link String#indexOf(String)}
*
*
* 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 String to check, may be null
* @param searchStrs the Strings to search for, may be null
* @return the last index of any of the Strings, -1 if no match
*/
public static int lastIndexOfAny(String str, String[] 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++) {
String search = searchStrs[i];
if (search == null) {
continue;
}
tmp = str.lastIndexOf(search);
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 n
* characters from the end of the String.
*
* A null
String will return 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, 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 n
* characters from the end of the String.
*
* The returned substring starts with the character in the start
* position and ends before the end
position. All position counting is
* zero-based -- i.e., to start at the beginning of the string use
* start = 0
. Negative start and end positions can be used to
* specify offsets relative to the end of the String.
*
* If start
is not strictly to the left of 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 positon,
* 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 len
characters of a String.
*
* If len
characters are not available, or the
* String is 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, 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 len
characters of a String.
*
* If len
characters are not available, or the String
* is 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, 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 len
characters from the middle of a String.
*
* If len
characters are not available, the remainder
* of the String will be returned without an exception. If the
* String is null
, null
will be returned.
* An empty String is returned if len is negative or exceeds the
* length of 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, 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 null
string input will return null
.
* An empty ("") string input will return the empty string.
* A 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,
* 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 null
string input will return null
.
* An empty ("") string input will return the empty string.
* A null
separator will return the empty string if the
* input string is not 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,
* 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 null
string input will return null
.
* An empty ("") string input will return the empty string.
* An empty or 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,
* 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 null
string input will return null
.
* An empty ("") string input will return the empty string.
* An empty or null
separator will return the empty string if
* the input string is not 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,
* 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 null
input String returns null
.
* A null
tag returns 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, 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 null
input String returns null
.
* A null
open/close returns 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, 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 null
input String returns null
.
* A null
open/close returns null
(no match).
* An empty ("") open/close returns 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 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();
List list = new ArrayList();
int pos = 0;
while (pos < (strLen - closeLen)) {
int start = str.indexOf(open, pos);
if (start < 0) {
break;
}
start += openLen;
int end = str.indexOf(close, start);
if (end < 0) {
break;
}
list.add(str.substring(start, end));
pos = end + closeLen;
}
if (list.isEmpty()) {
return null;
}
return (String[]) list.toArray(new String [list.size()]);
}
// Nested extraction
//-----------------------------------------------------------------------
/**
* Gets the String that is nested in between two instances of the
* same String.
*
* A null
input String returns null
.
* A null
tag returns null
.
*
*
* StringUtils.getNestedString(null, *) = null
* StringUtils.getNestedString("", "") = ""
* StringUtils.getNestedString("", "tag") = null
* StringUtils.getNestedString("tagabctag", null) = null
* StringUtils.getNestedString("tagabctag", "") = ""
* StringUtils.getNestedString("tagabctag", "tag") = "abc"
*
*
* @param str the String containing nested-string, may be null
* @param tag the String before and after nested-string, may be null
* @return the nested String, null
if no match
* @deprecated Use the better named {@link #substringBetween(String, String)}.
* Method will be removed in Commons Lang 3.0.
*/
public static String getNestedString(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 null
input String returns null
.
* A null
open/close returns null
(no match).
* An empty ("") open/close returns an empty string.
*
*
* StringUtils.getNestedString(null, *, *) = null
* StringUtils.getNestedString("", "", "") = ""
* StringUtils.getNestedString("", "", "tag") = null
* StringUtils.getNestedString("", "tag", "tag") = null
* StringUtils.getNestedString("yabcz", null, null) = null
* StringUtils.getNestedString("yabcz", "", "") = ""
* StringUtils.getNestedString("yabcz", "y", "z") = "abc"
* StringUtils.getNestedString("yabczyabcz", "y", "z") = "abc"
*
*
* @param str the String containing nested-string, may be null
* @param open the String before nested-string, may be null
* @param close the String after nested-string, may be null
* @return the nested String, null
if no match
* @deprecated Use the better named {@link #substringBetween(String, String, String)}.
* Method will be removed in Commons Lang 3.0.
*/
public static String getNestedString(String str, String open, String close) {
return substringBetween(str, open, close);
}
// Splitting
//-----------------------------------------------------------------------
/**
* Splits 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 null
input String returns 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, 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 null
input String returns 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, 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 null
input String returns null
.
* A 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,
* null
splits on whitespace
* @return an array of parsed Strings, 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 null
input String returns null
.
* A null
separatorChars splits on whitespace.
*
* If more than max
delimited substrings are found, the last
* returned string includes all characters after the first 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,
* 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, 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 null
input String returns null
.
* A 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,
* null
splits on whitespace
* @return an array of parsed Strings, 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 max
substrings.
*
* The separator(s) will not be included in the returned String array.
* Adjacent separators are treated as one separator.
*
* A null
input String returns null
.
* A 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,
* 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, 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 null
input String returns null
.
* A 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,
* null
splits on whitespace
* @return an array of parsed Strings, 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 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 null
input String returns null
.
* A 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,
* 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, 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 splitByWholeSeparatorPreserveAllTokens
methods.
*
* @param str the String to parse, may be null
* @param separator String containing the String to be used as a delimiter,
* 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 true
, adjacent separators are
* treated as empty token separators; if false
, adjacent
* separators are treated as one separator.
* @return an array of parsed Strings, 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();
ArrayList substrings = new ArrayList();
int numberOfSubstrings = 0;
int beg = 0;
int end = 0;
while (end < len) {
end = str.indexOf(separator, beg);
if (end > -1) {
if (end > beg) {
numberOfSubstrings += 1;
if (numberOfSubstrings == max) {
end = len;
substrings.add(str.substring(beg));
} else {
// The following is OK, because String.substring( beg, end ) excludes
// the character at the position 'end'.
substrings.add(str.substring(beg, end));
// Set the starting point for the next search.
// The following is equivalent to beg = end + (separatorLength - 1) + 1,
// which is the right calculation:
beg = end + separatorLength;
}
} else {
// We found a consecutive occurrence of the separator, so skip it.
if (preserveAllTokens) {
numberOfSubstrings += 1;
if (numberOfSubstrings == max) {
end = len;
substrings.add(str.substring(beg));
} else {
substrings.add(EMPTY);
}
}
beg = end + separatorLength;
}
} else {
// String.substring( beg ) goes from 'beg' to the end of the String.
substrings.add(str.substring(beg));
end = len;
}
}
return (String[]) substrings.toArray(new String[substrings.size()]);
}
// -----------------------------------------------------------------------
/**
* Splits 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 null
input String returns 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 null
* @return an array of parsed Strings, 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 null
input String returns 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 null
* @param separatorChar the character used as the delimiter,
* null
splits on whitespace
* @return an array of parsed Strings, 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 split
and
* splitPreserveAllTokens
methods that do not return a
* maximum array length.
*
* @param str the String to parse, may be null
* @param separatorChar the separate character
* @param preserveAllTokens if true
, adjacent separators are
* treated as empty token separators; if false
, adjacent
* separators are treated as one separator.
* @return an array of parsed Strings, 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;
}
List list = new ArrayList();
int i = 0, start = 0;
boolean match = false;
boolean lastMatch = false;
while (i < len) {
if (str.charAt(i) == separatorChar) {
if (match || preserveAllTokens) {
list.add(str.substring(start, i));
match = false;
lastMatch = true;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
if (match || (preserveAllTokens && lastMatch)) {
list.add(str.substring(start, i));
}
return (String[]) list.toArray(new String[list.size()]);
}
/**
* Splits 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 null
input String returns null
.
* A 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 null
* @param separatorChars the characters used as the delimiters,
* null
splits on whitespace
* @return an array of parsed Strings, 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 null
input String returns null
.
* A null
separatorChars splits on whitespace.
*
* If more than max
delimited substrings are found, the last
* returned string includes all characters after the first 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 null
* @param separatorChars the characters used as the delimiters,
* 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, 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 split
and
* splitPreserveAllTokens
methods that return a maximum array
* length.
*
* @param str the String to parse, may be 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 true
, adjacent separators are
* treated as empty token separators; if false
, adjacent
* separators are treated as one separator.
* @return an array of parsed Strings, 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;
}
List list = new ArrayList();
int sizePlus1 = 1;
int i = 0, start = 0;
boolean match = false;
boolean lastMatch = false;
if (separatorChars == null) {
// Null separator means use whitespace
while (i < len) {
if (Character.isWhitespace(str.charAt(i))) {
if (match || preserveAllTokens) {
lastMatch = true;
if (sizePlus1++ == max) {
i = len;
lastMatch = false;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
} else if (separatorChars.length() == 1) {
// Optimise 1 character case
char sep = separatorChars.charAt(0);
while (i < len) {
if (str.charAt(i) == sep) {
if (match || preserveAllTokens) {
lastMatch = true;
if (sizePlus1++ == max) {
i = len;
lastMatch = false;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
} else {
// standard case
while (i < len) {
if (separatorChars.indexOf(str.charAt(i)) >= 0) {
if (match || preserveAllTokens) {
lastMatch = true;
if (sizePlus1++ == max) {
i = len;
lastMatch = false;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
}
if (match || (preserveAllTokens && lastMatch)) {
list.add(str.substring(start, i));
}
return (String[]) list.toArray(new String[list.size()]);
}
/**
* Splits a String by Character type as returned by
* 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 null
* @return an array of parsed Strings, 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
* 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
* Character.UPPERCASE_LETTER
, if any, immediately
* preceding a token of type Character.LOWERCASE_LETTER
* will belong to the following token rather than to the preceding, if any,
* 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 null
* @return an array of parsed Strings, 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
* java.lang.Character.getType(char)
. Groups of contiguous
* characters of the same type are returned as complete tokens, with the
* following exception: if camelCase
is true
,
* the character of type Character.UPPERCASE_LETTER
, if any,
* immediately preceding a token of type Character.LOWERCASE_LETTER
* will belong to the following token rather than to the preceding, if any,
* Character.UPPERCASE_LETTER
token.
* @param str the String to split, may be null
* @param camelCase whether to use so-called "camel-case" for letter types
* @return an array of parsed Strings, 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 list = new ArrayList();
int tokenStart = 0;
int currentType = Character.getType(c[tokenStart]);
for (int pos = tokenStart + 1; pos < c.length; pos++) {
int type = Character.getType(c[pos]);
if (type == currentType) {
continue;
}
if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
int newTokenStart = pos - 1;
if (newTokenStart != tokenStart) {
list.add(new String(c, tokenStart, newTokenStart - tokenStart));
tokenStart = newTokenStart;
}
} else {
list.add(new String(c, tokenStart, pos - tokenStart));
tokenStart = pos;
}
currentType = type;
}
list.add(new String(c, tokenStart, c.length - tokenStart));
return (String[]) list.toArray(new String[list.size()]);
}
// Joining
//-----------------------------------------------------------------------
/**
*
Joins the provided elements into a single String.
*
* No separator is added to the joined String.
* Null objects or empty string elements are represented by
* empty strings.
*
*
* StringUtils.concatenate(null) = null
* StringUtils.concatenate([]) = ""
* StringUtils.concatenate([null]) = ""
* StringUtils.concatenate(["a", "b", "c"]) = "abc"
* StringUtils.concatenate([null, "", "a"]) = "a"
*
*
* @param array the array of values to concatenate, may be null
* @return the concatenated String, null
if null array input
* @deprecated Use the better named {@link #join(Object[])} instead.
* Method will be removed in Commons Lang 3.0.
*/
public static String concatenate(Object[] array) {
return join(array, null);
}
/**
* 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.
*
*
* StringUtils.join(null) = null
* StringUtils.join([]) = ""
* StringUtils.join([null]) = ""
* StringUtils.join(["a", "b", "c"]) = "abc"
* StringUtils.join([null, "", "a"]) = "a"
*
*
* @param array the array of values to join together, may be null
* @return the joined String, null
if null array input
* @since 2.0
*/
public static String join(Object[] array) {
return join(array, null);
}
/**
* 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.
*
*
* 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, 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);
}
/**
* 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.
*
*
* 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, 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 bufSize = (endIndex - startIndex);
if (bufSize <= 0) {
return EMPTY;
}
bufSize *= ((array[startIndex] == null ? 16 : array[startIndex].toString().length()) + 1);
StrBuilder buf = new StrBuilder(bufSize);
for (int i = startIndex; i < endIndex; i++) {
if (i > startIndex) {
buf.append(separator);
}
if (array[i] != null) {
buf.append(array[i]);
}
}
return buf.toString();
}
/**
* 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 null
separator is the same as an empty String ("").
* Null objects or empty strings within the array are represented by
* empty strings.
*
*
* 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, 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);
}
/**
* 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 null
separator is the same as an empty String ("").
* Null objects or empty strings within the array are represented by
* empty strings.
*
*
* 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, 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 bufSize = (endIndex - startIndex);
if (bufSize <= 0) {
return EMPTY;
}
bufSize *= ((array[startIndex] == null ? 16 : array[startIndex].toString().length())
+ separator.length());
StrBuilder buf = new StrBuilder(bufSize);
for (int i = startIndex; i < endIndex; i++) {
if (i > startIndex) {
buf.append(separator);
}
if (array[i] != null) {
buf.append(array[i]);
}
}
return buf.toString();
}
/**
* Joins the elements of the provided 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)}.
*
* @param iterator the Iterator
of values to join together, may be null
* @param separator the separator character to use
* @return the joined String, null
if null iterator input
* @since 2.0
*/
public static String join(Iterator iterator, char separator) {
// handle null, zero and one elements before building a buffer
if (iterator == null) {
return null;
}
if (!iterator.hasNext()) {
return EMPTY;
}
Object first = iterator.next();
if (!iterator.hasNext()) {
return ObjectUtils.toString(first);
}
// two or more elements
StrBuilder buf = new StrBuilder(256); // Java default is 16, probably too small
if (first != null) {
buf.append(first);
}
while (iterator.hasNext()) {
buf.append(separator);
Object obj = iterator.next();
if (obj != null) {
buf.append(obj);
}
}
return buf.toString();
}
/**
* Joins the elements of the provided Iterator
into
* a single String containing the provided elements.
*
* No delimiter is added before or after the list.
* A null
separator is the same as an empty String ("").
*
* See the examples here: {@link #join(Object[],String)}.
*
* @param iterator the Iterator
of values to join together, may be null
* @param separator the separator character to use, null treated as ""
* @return the joined String, null
if null iterator input
*/
public static String join(Iterator iterator, String separator) {
// handle null, zero and one elements before building a buffer
if (iterator == null) {
return null;
}
if (!iterator.hasNext()) {
return EMPTY;
}
Object first = iterator.next();
if (!iterator.hasNext()) {
return ObjectUtils.toString(first);
}
// two or more elements
StrBuilder buf = new StrBuilder(256); // Java default is 16, probably too small
if (first != null) {
buf.append(first);
}
while (iterator.hasNext()) {
if (separator != null) {
buf.append(separator);
}
Object obj = iterator.next();
if (obj != null) {
buf.append(obj);
}
}
return buf.toString();
}
/**
* Joins the elements of the provided Collection
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)}.
*
* @param collection the Collection
of values to join together, may be null
* @param separator the separator character to use
* @return the joined String, null
if null iterator input
* @since 2.3
*/
public static String join(Collection collection, char separator) {
if (collection == null) {
return null;
}
return join(collection.iterator(), separator);
}
/**
* Joins the elements of the provided Collection
into
* a single String containing the provided elements.
*
* No delimiter is added before or after the list.
* A null
separator is the same as an empty String ("").
*
* See the examples here: {@link #join(Object[],String)}.
*
* @param collection the Collection
of values to join together, may be null
* @param separator the separator character to use, null treated as ""
* @return the joined String, null
if null iterator input
* @since 2.3
*/
public static String join(Collection collection, String separator) {
if (collection == null) {
return null;
}
return join(collection.iterator(), separator);
}
// Delete
//-----------------------------------------------------------------------
/**
* Deletes all 'space' characters from a String as defined by
* {@link Character#isSpace(char)}.
*
* This is the only StringUtils method that uses the
* isSpace
definition. You are advised to use
* {@link #deleteWhitespace(String)} instead as whitespace is much
* better localized.
*
*
* StringUtils.deleteSpaces(null) = null
* StringUtils.deleteSpaces("") = ""
* StringUtils.deleteSpaces("abc") = "abc"
* StringUtils.deleteSpaces(" \t abc \n ") = "abc"
* StringUtils.deleteSpaces("ab c") = "abc"
* StringUtils.deleteSpaces("a\nb\tc ") = "abc"
*
*
* Spaces are defined as {' ', '\t', '\r', '\n', '\b'}
* in line with the deprecated isSpace
method.
*
* @param str the String to delete spaces from, may be null
* @return the String without 'spaces', null
if null String input
* @deprecated Use the better localized {@link #deleteWhitespace(String)}.
* Method will be removed in Commons Lang 3.0.
*/
public static String deleteSpaces(String str) {
if (str == null) {
return null;
}
return CharSetUtils.delete(str, " \t\r\n\b");
}
/**
* Deletes all whitespaces from a String as defined by
* {@link Character#isWhitespace(char)}.
*
*
* 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, 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
//-----------------------------------------------------------------------
/**
* Removes a substring only if it is at the begining of a source string,
* otherwise returns the source string.
*
* A null
source string will return null
.
* An empty ("") source string will return the empty string.
* A null
search string will return the source string.
*
*
* 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,
* 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;
}
/**
* Case insensitive removal of a substring if it is at the begining of a source string,
* otherwise returns the source string.
*
* A null
source string will return null
.
* An empty ("") source string will return the empty string.
* A null
search string will return the source string.
*
*
* 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,
* 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;
}
/**
* Removes a substring only if it is at the end of a source string,
* otherwise returns the source string.
*
* A null
source string will return null
.
* An empty ("") source string will return the empty string.
* A null
search string will return the source string.
*
*
* 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,
* 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;
}
/**
* Case insensitive removal of a substring if it is at the end of a source string,
* otherwise returns the source string.
*
* A null
source string will return null
.
* An empty ("") source string will return the empty string.
* A null
search string will return the source string.
*
*
* 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,
* 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;
}
/**
* Removes all occurrences of a substring from within the source string.
*
* A null
source string will return null
.
* An empty ("") source string will return the empty string.
* A null
remove string will return the source string.
* An empty ("") remove string will return the source string.
*
*
* 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,
* 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);
}
/**
* Removes all occurrences of a character from within the source string.
*
* A null
source string will return null
.
* An empty ("") source string will return the empty string.
*
*
* 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,
* 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
//-----------------------------------------------------------------------
/**
* Replaces a String with another String inside a larger String, once.
*
* A null
reference passed to this method is a no-op.
*
*
* 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,
* null
if null String input
*/
public static String replaceOnce(String text, String searchString, String replacement) {
return replace(text, searchString, replacement, 1);
}
/**
* Replaces all occurrences of a String within another String.
*
* A null
reference passed to this method is a no-op.
*
*
* 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,
* null
if null String input
*/
public static String replace(String text, String searchString, String replacement) {
return replace(text, searchString, replacement, -1);
}
/**
* Replaces a String with another String inside a larger String,
* for the first max
values of the search String.
*
* A null
reference passed to this method is a no-op.
*
*
* 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 -1
if no maximum
* @return the text with any replacements processed,
* 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));
StrBuilder buf = new StrBuilder(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();
}
/**
*
* Replaces all occurrences of Strings within another String.
*
*
*
* A 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.
*
*
*
* 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, null
if
* null String input
* @throws IndexOutOfBoundsException
* 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);
}
/**
*
* Replaces all occurrences of Strings within another String.
*
*
*
* A 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.
*
*
*
* 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) = IllegalArgumentException
* 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, null
if
* null String input
* @throws IllegalArgumentException
* if the search is repeating and there is an endless loop due
* to outputs of one being inputs to another
* @throws IndexOutOfBoundsException
* 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);
}
/**
*
* Replaces all occurrences of Strings within another String.
*
*
*
* A 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.
*
*
*
* 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"}, *) = IllegalArgumentException
*
*
* @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, null
if
* null String input
* @throws IllegalArgumentException
* if the search is repeating and there is an endless loop due
* to outputs of one being inputs to another
* @throws IndexOutOfBoundsException
* 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 shouldnt be less than 0
if (timeToLive < 0) {
throw new IllegalStateException("TimeToLive of " + timeToLive + " is less than 0: " + text);
}
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 doesnt 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);
StrBuilder buf = new StrBuilder(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
//-----------------------------------------------------------------------
/**
* Replaces all occurrences of a character in a String with another.
* This is a null-safe version of {@link String#replace(char, char)}.
*
* A null
string input returns null
.
* An empty ("") string input returns an empty string.
*
*
* 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, 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);
}
/**
* Replaces multiple characters in a String in one go.
* This method can also be used to delete characters.
*
* For example:
* replaceChars("hello", "ho", "jy") = jelly
.
*
* A null
string input returns 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.
*
*
* 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, 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();
StrBuilder buf = new StrBuilder(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
//-----------------------------------------------------------------------
/**
* Overlays part of a String with another String.
*
*
* StringUtils.overlayString(null, *, *, *) = NullPointerException
* StringUtils.overlayString(*, null, *, *) = NullPointerException
* StringUtils.overlayString("", "abc", 0, 0) = "abc"
* StringUtils.overlayString("abcdef", null, 2, 4) = "abef"
* StringUtils.overlayString("abcdef", "", 2, 4) = "abef"
* StringUtils.overlayString("abcdef", "zzzz", 2, 4) = "abzzzzef"
* StringUtils.overlayString("abcdef", "zzzz", 4, 2) = "abcdzzzzcdef"
* StringUtils.overlayString("abcdef", "zzzz", -1, 4) = IndexOutOfBoundsException
* StringUtils.overlayString("abcdef", "zzzz", 2, 8) = IndexOutOfBoundsException
*
*
* @param text 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, must be valid
* @param end the position to stop overlaying before, must be valid
* @return overlayed String, null
if null String input
* @throws NullPointerException if text or overlay is null
* @throws IndexOutOfBoundsException if either position is invalid
* @deprecated Use better named {@link #overlay(String, String, int, int)} instead.
* Method will be removed in Commons Lang 3.0.
*/
public static String overlayString(String text, String overlay, int start, int end) {
return new StrBuilder(start + overlay.length() + text.length() - end + 1)
.append(text.substring(0, start))
.append(overlay)
.append(text.substring(end))
.toString();
}
/**
* Overlays part of a String with another String.
*
* A null
string input returns 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.
*
*
* 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, 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 StrBuilder(len + start - end + overlay.length() + 1)
.append(str.substring(0, start))
.append(overlay)
.append(str.substring(end))
.toString();
}
// Chomping
//-----------------------------------------------------------------------
/**
* Removes one newline from end of a String if it's there,
* otherwise leave it alone. A newline is "\n
",
* "\r
", or "\r\n
".
*
* NOTE: This method changed in 2.0.
* It now more closely matches Perl chomp.
*
*
* 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, 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);
}
/**
* Removes separator
from the end of
* str
if it's there, otherwise leave it alone.
*
* NOTE: This method changed in version 2.0.
* It now more closely matches Perl chomp.
* For the previous behavior, use {@link #substringBeforeLast(String, String)}.
* This method uses {@link String#endsWith(String)}.
*
*
* StringUtils.chomp(null, *) = null
* StringUtils.chomp("", *) = ""
* StringUtils.chomp("foobar", "bar") = "foo"
* StringUtils.chomp("foobar", "baz") = "foobar"
* StringUtils.chomp("foo", "foo") = ""
* StringUtils.chomp("foo ", "foo") = "foo "
* StringUtils.chomp(" foo", "foo") = " "
* StringUtils.chomp("foo", "foooo") = "foo"
* StringUtils.chomp("foo", "") = "foo"
* StringUtils.chomp("foo", null) = "foo"
*
*
* @param str the String to chomp from, may be null
* @param separator separator String, may be null
* @return String without trailing separator, null
if null String input
*/
public static String chomp(String str, String separator) {
if (isEmpty(str) || separator == null) {
return str;
}
if (str.endsWith(separator)) {
return str.substring(0, str.length() - separator.length());
}
return str;
}
/**
* Remove any "\n" if and only if it is at the end
* of the supplied String.
*
* @param str the String to chomp from, must not be null
* @return String without chomped ending
* @throws NullPointerException if str is null
* @deprecated Use {@link #chomp(String)} instead.
* Method will be removed in Commons Lang 3.0.
*/
public static String chompLast(String str) {
return chompLast(str, "\n");
}
/**
* Remove a value if and only if the String ends with that value.
*
* @param str the String to chomp from, must not be null
* @param sep the String to chomp, must not be null
* @return String without chomped ending
* @throws NullPointerException if str or sep is null
* @deprecated Use {@link #chomp(String,String)} instead.
* Method will be removed in Commons Lang 3.0.
*/
public static String chompLast(String str, String sep) {
if (str.length() == 0) {
return str;
}
String sub = str.substring(str.length() - sep.length());
if (sep.equals(sub)) {
return str.substring(0, str.length() - sep.length());
}
return str;
}
/**
* Remove everything and return the last value of a supplied String, and
* everything after it from a String.
*
* @param str the String to chomp from, must not be null
* @param sep the String to chomp, must not be null
* @return String chomped
* @throws NullPointerException if str or sep is null
* @deprecated Use {@link #substringAfterLast(String, String)} instead
* (although this doesn't include the separator)
* Method will be removed in Commons Lang 3.0.
*/
public static String getChomp(String str, String sep) {
int idx = str.lastIndexOf(sep);
if (idx == str.length() - sep.length()) {
return sep;
} else if (idx != -1) {
return str.substring(idx);
} else {
return EMPTY;
}
}
/**
* Remove the first value of a supplied String, and everything before it
* from a String.
*
* @param str the String to chomp from, must not be null
* @param sep the String to chomp, must not be null
* @return String without chomped beginning
* @throws NullPointerException if str or sep is null
* @deprecated Use {@link #substringAfter(String,String)} instead.
* Method will be removed in Commons Lang 3.0.
*/
public static String prechomp(String str, String sep) {
int idx = str.indexOf(sep);
if (idx == -1) {
return str;
}
return str.substring(idx + sep.length());
}
/**
* Remove and return everything before the first value of a
* supplied String from another String.
*
* @param str the String to chomp from, must not be null
* @param sep the String to chomp, must not be null
* @return String prechomped
* @throws NullPointerException if str or sep is null
* @deprecated Use {@link #substringBefore(String,String)} instead
* (although this doesn't include the separator).
* Method will be removed in Commons Lang 3.0.
*/
public static String getPrechomp(String str, String sep) {
int idx = str.indexOf(sep);
if (idx == -1) {
return EMPTY;
}
return str.substring(0, idx + sep.length());
}
// Chopping
//-----------------------------------------------------------------------
/**
* Remove the last character from a String.
*
* If the String ends in \r\n
, then remove both
* of them.
*
*
* 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, 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) {
if (ret.charAt(lastIdx - 1) == CharUtils.CR) {
return ret.substring(0, lastIdx - 1);
}
}
return ret;
}
/**
* Removes \n
from end of a String if it's there.
* If a \r
precedes it, then remove that too.
*
* @param str the String to chop a newline from, must not be null
* @return String without newline
* @throws NullPointerException if str is null
* @deprecated Use {@link #chomp(String)} instead.
* Method will be removed in Commons Lang 3.0.
*/
public static String chopNewline(String str) {
int lastIdx = str.length() - 1;
if (lastIdx <= 0) {
return EMPTY;
}
char last = str.charAt(lastIdx);
if (last == CharUtils.LF) {
if (str.charAt(lastIdx - 1) == CharUtils.CR) {
lastIdx--;
}
} else {
lastIdx++;
}
return str.substring(0, lastIdx);
}
// Conversion
//-----------------------------------------------------------------------
/**
* Escapes any values it finds into their String form.
*
* So a tab becomes the characters '\\'
and
* 't'
.
*
* As of Lang 2.0, this calls {@link StringEscapeUtils#escapeJava(String)}
* behind the scenes.
*
* @see StringEscapeUtils#escapeJava(java.lang.String)
* @param str String to escape values in
* @return String with escaped values
* @throws NullPointerException if str is null
* @deprecated Use {@link StringEscapeUtils#escapeJava(String)}
* This method will be removed in Commons Lang 3.0
*/
public static String escape(String str) {
return StringEscapeUtils.escapeJava(str);
}
// Padding
//-----------------------------------------------------------------------
/**
* Repeat a String repeat
times to form a
* new String.
*
*
* 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,
* 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 padding(repeat, str.charAt(0));
}
int outputLength = inputLength * repeat;
switch (inputLength) {
case 1 :
char ch = str.charAt(0);
char[] output1 = new char[outputLength];
for (int i = repeat - 1; i >= 0; i--) {
output1[i] = ch;
}
return new String(output1);
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 :
StrBuilder buf = new StrBuilder(outputLength);
for (int i = 0; i < repeat; i++) {
buf.append(str);
}
return buf.toString();
}
}
/**
* Repeat a String repeat
times to form a
* new String, with a String separator injected each time.
*
*
* 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,
* 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);
}
}
/**
* Returns padding using the specified delimiter repeated
* to a given length.
*
*
* StringUtils.padding(0, 'e') = ""
* StringUtils.padding(3, 'e') = "eee"
* StringUtils.padding(-2, 'e') = IndexOutOfBoundsException
*
*
* Note: this method doesn't not support padding with
* Unicode Supplementary Characters
* as they require a pair of char
s to be represented.
* If you are needing to support full I18N of your applications
* consider using {@link #repeat(String, int)} instead.
*
*
* @param repeat number of times to repeat delim
* @param padChar character to repeat
* @return String with repeated character
* @throws IndexOutOfBoundsException if repeat < 0
* @see #repeat(String, int)
*/
private static String padding(int repeat, char padChar) throws IndexOutOfBoundsException {
if (repeat < 0) {
throw new IndexOutOfBoundsException("Cannot pad a negative amount: " + repeat);
}
final char[] buf = new char[repeat];
for (int i = 0; i < buf.length; i++) {
buf[i] = padChar;
}
return new String(buf);
}
/**
* Right pad a String with spaces (' ').
*
* The String is padded to the size of size
.
*
*
* 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,
* null
if null String input
*/
public static String rightPad(String str, int size) {
return rightPad(str, size, ' ');
}
/**
* Right pad a String with a specified character.
*
* The String is padded to the size of 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,
* 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(padding(pads, padChar));
}
/**
* Right pad a String with a specified String.
*
* The String is padded to the size of size
.
*
*
* 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,
* 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));
}
}
/**
* Left pad a String with spaces (' ').
*
* The String is padded to the size of size
.
*
*
* 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,
* null
if null String input
*/
public static String leftPad(String str, int size) {
return leftPad(str, size, ' ');
}
/**
* Left pad a String with a specified character.
*
* Pad to a size of 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,
* 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 padding(pads, padChar).concat(str);
}
/**
* Left pad a String with a specified String.
*
* Pad to a size of size
.
*
*
* 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,
* 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 String's length or 0
if the String is null
.
*
* @param str
* a String or null
* @return String length or 0
if the String is null
.
* @since 2.4
*/
public static int length(String str) {
return str == null ? 0 : str.length();
}
// Centering
//-----------------------------------------------------------------------
/**
* Centers a String in a larger String of size size
* using the space character (' ').
*
*
If the size is less than the String length, the String is returned.
* A null
String returns null
.
* A negative size is treated as zero.
*
* Equivalent to 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 "
*
*
* @param str the String to center, may be null
* @param size the int size of new String, negative treated as zero
* @return centered String, null
if null String input
*/
public static String center(String str, int size) {
return center(str, size, ' ');
}
/**
* Centers a String in a larger String of size 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 null
String returns null
.
* A negative size is treated as zero.
*
*
* 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, 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;
}
/**
* Centers a String in a larger String of size 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 null
String returns null
.
* A negative size is treated as zero.
*
*
* 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, null
if null String input
* @throws IllegalArgumentException if padStr is 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
//-----------------------------------------------------------------------
/**
* Converts a String to upper case as per {@link String#toUpperCase()}.
*
* A null
input String returns null
.
*
*
* StringUtils.upperCase(null) = null
* StringUtils.upperCase("") = ""
* StringUtils.upperCase("aBc") = "ABC"
*
*
* 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}).
*
* @param str the String to upper case, may be null
* @return the upper cased String, null
if null String input
*/
public static String upperCase(String str) {
if (str == null) {
return null;
}
return str.toUpperCase();
}
/**
* Converts a String to upper case as per {@link String#toUpperCase(Locale)}.
*
* A null
input String returns null
.
*
*
* 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, 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);
}
/**
* Converts a String to lower case as per {@link String#toLowerCase()}.
*
* A null
input String returns null
.
*
*
* StringUtils.lowerCase(null) = null
* StringUtils.lowerCase("") = ""
* StringUtils.lowerCase("aBc") = "abc"
*
*
* 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}).
*
* @param str the String to lower case, may be null
* @return the lower cased String, null
if null String input
*/
public static String lowerCase(String str) {
if (str == null) {
return null;
}
return str.toLowerCase();
}
/**
* Converts a String to lower case as per {@link String#toLowerCase(Locale)}.
*
* A null
input String returns null
.
*
*
* 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, 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);
}
/**
* 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 WordUtils#capitalize(String)}.
* A null
input String returns null
.
*
*
* 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, null
if null String input
* @see 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 StrBuilder(strLen)
.append(Character.toTitleCase(str.charAt(0)))
.append(str.substring(1))
.toString();
}
/**
* Capitalizes a String changing the first letter to title case as
* per {@link Character#toTitleCase(char)}. No other letters are changed.
*
* @param str the String to capitalize, may be null
* @return the capitalized String, null
if null String input
* @deprecated Use the standardly named {@link #capitalize(String)}.
* Method will be removed in Commons Lang 3.0.
*/
public static String capitalise(String str) {
return capitalize(str);
}
/**
* 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 WordUtils#uncapitalize(String)}.
* A null
input String returns null
.
*
*
* 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, null
if null String input
* @see 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 StrBuilder(strLen)
.append(Character.toLowerCase(str.charAt(0)))
.append(str.substring(1))
.toString();
}
/**
* Uncapitalizes a String changing the first letter to title case as
* per {@link Character#toLowerCase(char)}. No other letters are changed.
*
* @param str the String to uncapitalize, may be null
* @return the uncapitalized String, null
if null String input
* @deprecated Use the standardly named {@link #uncapitalize(String)}.
* Method will be removed in Commons Lang 3.0.
*/
public static String uncapitalise(String str) {
return uncapitalize(str);
}
/**
* Swaps the case of a String changing upper and title case to
* lower case, and lower case to upper case.
*
*
* - Upper case character converts to Lower case
* - Title case character converts to Lower case
* - Lower case character converts to Upper case
*
*
* For a word based algorithm, see {@link WordUtils#swapCase(String)}.
* A null
input String returns null
.
*
*
* StringUtils.swapCase(null) = null
* StringUtils.swapCase("") = ""
* StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
*
*
* 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 WordUtils.
*
* @param str the String to swap case, may be null
* @return the changed String, null
if null String input
*/
public static String swapCase(String str) {
int strLen;
if (str == null || (strLen = str.length()) == 0) {
return str;
}
StrBuilder buffer = new StrBuilder(strLen);
char ch = 0;
for (int i = 0; i < strLen; i++) {
ch = str.charAt(i);
if (Character.isUpperCase(ch)) {
ch = Character.toLowerCase(ch);
} else if (Character.isTitleCase(ch)) {
ch = Character.toLowerCase(ch);
} else if (Character.isLowerCase(ch)) {
ch = Character.toUpperCase(ch);
}
buffer.append(ch);
}
return buffer.toString();
}
/**
* Capitalizes all the whitespace separated words in a String.
* Only the first letter of each word is changed.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
* A null
input String returns null
.
*
* @param str the String to capitalize, may be null
* @return capitalized String, null
if null String input
* @deprecated Use the relocated {@link WordUtils#capitalize(String)}.
* Method will be removed in Commons Lang 3.0.
*/
public static String capitaliseAllWords(String str) {
return WordUtils.capitalize(str);
}
// Count matches
//-----------------------------------------------------------------------
/**
* Counts how many times the substring appears in the larger String.
*
* A null
or empty ("") String input returns 0
.
*
*
* 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 String to check, may be null
* @param sub the substring to count, may be null
* @return the number of occurrences, 0 if either String is null
*/
public static int countMatches(String str, String sub) {
if (isEmpty(str) || isEmpty(sub)) {
return 0;
}
int count = 0;
int idx = 0;
while ((idx = str.indexOf(sub, idx)) != INDEX_NOT_FOUND) {
count++;
idx += sub.length();
}
return count;
}
// Character Tests
//-----------------------------------------------------------------------
/**
* Checks if the String contains only unicode letters.
*
* null
will return false
.
* An empty String (length()=0) will return true
.
*
*
* StringUtils.isAlpha(null) = false
* StringUtils.isAlpha("") = true
* StringUtils.isAlpha(" ") = false
* StringUtils.isAlpha("abc") = true
* StringUtils.isAlpha("ab2c") = false
* StringUtils.isAlpha("ab-c") = false
*
*
* @param str the String to check, may be null
* @return true
if only contains letters, and is non-null
*/
public static boolean isAlpha(String str) {
if (str == null) {
return false;
}
int sz = str.length();
for (int i = 0; i < sz; i++) {
if (Character.isLetter(str.charAt(i)) == false) {
return false;
}
}
return true;
}
/**
* Checks if the String contains only unicode letters and
* space (' ').
*
* null
will return false
* An empty String (length()=0) will 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 str the String to check, may be null
* @return true
if only contains letters and space,
* and is non-null
*/
public static boolean isAlphaSpace(String str) {
if (str == null) {
return false;
}
int sz = str.length();
for (int i = 0; i < sz; i++) {
if ((Character.isLetter(str.charAt(i)) == false) && (str.charAt(i) != ' ')) {
return false;
}
}
return true;
}
/**
* Checks if the String contains only unicode letters or digits.
*
* null
will return false
.
* An empty String (length()=0) will return true
.
*
*
* StringUtils.isAlphanumeric(null) = false
* StringUtils.isAlphanumeric("") = true
* StringUtils.isAlphanumeric(" ") = false
* StringUtils.isAlphanumeric("abc") = true
* StringUtils.isAlphanumeric("ab c") = false
* StringUtils.isAlphanumeric("ab2c") = true
* StringUtils.isAlphanumeric("ab-c") = false
*
*
* @param str the String to check, may be null
* @return true
if only contains letters or digits,
* and is non-null
*/
public static boolean isAlphanumeric(String str) {
if (str == null) {
return false;
}
int sz = str.length();
for (int i = 0; i < sz; i++) {
if (Character.isLetterOrDigit(str.charAt(i)) == false) {
return false;
}
}
return true;
}
/**
* Checks if the String contains only unicode letters, digits
* or space (' '
).
*
* null
will return false
.
* An empty String (length()=0) will return true
.
*
*
* StringUtils.isAlphanumeric(null) = false
* StringUtils.isAlphanumeric("") = true
* StringUtils.isAlphanumeric(" ") = true
* StringUtils.isAlphanumeric("abc") = true
* StringUtils.isAlphanumeric("ab c") = true
* StringUtils.isAlphanumeric("ab2c") = true
* StringUtils.isAlphanumeric("ab-c") = false
*
*
* @param str the String to check, may be null
* @return true
if only contains letters, digits or space,
* and is non-null
*/
public static boolean isAlphanumericSpace(String str) {
if (str == null) {
return false;
}
int sz = str.length();
for (int i = 0; i < sz; i++) {
if ((Character.isLetterOrDigit(str.charAt(i)) == false) && (str.charAt(i) != ' ')) {
return false;
}
}
return true;
}
/**
* Checks if the string contains only ASCII printable characters.
*
* null
will return false
.
* An empty String (length()=0) will 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 str the string to check, may be null
* @return true
if every character is in the range
* 32 thru 126
* @since 2.1
*/
public static boolean isAsciiPrintable(String str) {
if (str == null) {
return false;
}
int sz = str.length();
for (int i = 0; i < sz; i++) {
if (CharUtils.isAsciiPrintable(str.charAt(i)) == false) {
return false;
}
}
return true;
}
/**
* Checks if the String contains only unicode digits.
* A decimal point is not a unicode digit and returns false.
*
* null
will return false
.
* An empty String (length()=0) will return true
.
*
*
* StringUtils.isNumeric(null) = false
* StringUtils.isNumeric("") = true
* 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 str the String to check, may be null
* @return true
if only contains digits, and is non-null
*/
public static boolean isNumeric(String str) {
if (str == null) {
return false;
}
int sz = str.length();
for (int i = 0; i < sz; i++) {
if (Character.isDigit(str.charAt(i)) == false) {
return false;
}
}
return true;
}
/**
* Checks if the String contains only unicode digits or space
* (' '
).
* A decimal point is not a unicode digit and returns false.
*
* null
will return false
.
* An empty String (length()=0) will return true
.
*
*
* StringUtils.isNumeric(null) = false
* StringUtils.isNumeric("") = true
* StringUtils.isNumeric(" ") = true
* StringUtils.isNumeric("123") = true
* StringUtils.isNumeric("12 3") = true
* StringUtils.isNumeric("ab2c") = false
* StringUtils.isNumeric("12-3") = false
* StringUtils.isNumeric("12.3") = false
*
*
* @param str the String to check, may be null
* @return true
if only contains digits or space,
* and is non-null
*/
public static boolean isNumericSpace(String str) {
if (str == null) {
return false;
}
int sz = str.length();
for (int i = 0; i < sz; i++) {
if ((Character.isDigit(str.charAt(i)) == false) && (str.charAt(i) != ' ')) {
return false;
}
}
return true;
}
/**
* Checks if the String contains only whitespace.
*
* null
will return false
.
* An empty String (length()=0) will 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 str the String to check, may be null
* @return true
if only contains whitespace, and is non-null
* @since 2.0
*/
public static boolean isWhitespace(String str) {
if (str == null) {
return false;
}
int sz = str.length();
for (int i = 0; i < sz; i++) {
if ((Character.isWhitespace(str.charAt(i)) == false)) {
return false;
}
}
return true;
}
/**
* Checks if the String contains only lowercase characters.
*
* null
will return false
.
* An empty String (length()=0) will return false
.
*
*
* StringUtils.isAllLowerCase(null) = false
* StringUtils.isAllLowerCase("") = false
* StringUtils.isAllLowerCase(" ") = false
* StringUtils.isAllLowerCase("abc") = true
* StringUtils.isAllLowerCase("abC") = false
*
*
* @param str the String to check, may be null
* @return true
if only contains lowercase characters, and is non-null
* @since 2.5
*/
public static boolean isAllLowerCase(String str) {
if (str == null || isEmpty(str)) {
return false;
}
int sz = str.length();
for (int i = 0; i < sz; i++) {
if (Character.isLowerCase(str.charAt(i)) == false) {
return false;
}
}
return true;
}
/**
* Checks if the String contains only uppercase characters.
*
* null
will return false
.
* An empty String (length()=0) will return false
.
*
*
* StringUtils.isAllUpperCase(null) = false
* StringUtils.isAllUpperCase("") = false
* StringUtils.isAllUpperCase(" ") = false
* StringUtils.isAllUpperCase("ABC") = true
* StringUtils.isAllUpperCase("aBC") = false
*
*
* @param str the String to check, may be null
* @return true
if only contains uppercase characters, and is non-null
* @since 2.5
*/
public static boolean isAllUpperCase(String str) {
if (str == null || isEmpty(str)) {
return false;
}
int sz = str.length();
for (int i = 0; i < sz; i++) {
if (Character.isUpperCase(str.charAt(i)) == false) {
return false;
}
}
return true;
}
// Defaults
//-----------------------------------------------------------------------
/**
* Returns either the passed in String,
* or if the String is null
, an empty String ("").
*
*
* 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 null
*/
public static String defaultString(String str) {
return str == null ? EMPTY : str;
}
/**
* Returns either the passed in String, or if the String is
* null
, the value of defaultStr
.
*
*
* 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 null
, may be null
* @return the passed in String, or the default if it was null
*/
public static String defaultString(String str, String defaultStr) {
return str == null ? defaultStr : str;
}
/**
* Returns either the passed in String, or if the String is
* whitespace, empty ("") or null
, the value of defaultStr
.
*
*
* StringUtils.defaultIfBlank(null, "NULL") = "NULL"
* StringUtils.defaultIfBlank("", "NULL") = "NULL"
* StringUtils.defaultIfBlank(" ", "NULL") = "NULL"
* StringUtils.defaultIfBlank("bat", "NULL") = "bat"
* StringUtils.defaultIfBlank("", null) = null
*
* @param str the String to check, may be null
* @param defaultStr the default String to return
* if the input is whitespace, empty ("") or null
, may be null
* @return the passed in String, or the default
* @see StringUtils#defaultString(String, String)
* @since 2.6
*/
public static String defaultIfBlank(String str, String defaultStr) {
return StringUtils.isBlank(str) ? defaultStr : str;
}
/**
* Returns either the passed in String, or if the String is
* empty or null
, the value of defaultStr
.
*
*
* StringUtils.defaultIfEmpty(null, "NULL") = "NULL"
* StringUtils.defaultIfEmpty("", "NULL") = "NULL"
* StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
* StringUtils.defaultIfEmpty("", null) = null
*
*
* @param str the String to check, may be null
* @param defaultStr the default String to return
* if the input is empty ("") or null
, may be null
* @return the passed in String, or the default
* @see StringUtils#defaultString(String, String)
*/
public static String defaultIfEmpty(String str, String defaultStr) {
return StringUtils.isEmpty(str) ? defaultStr : str;
}
// Reversing
//-----------------------------------------------------------------------
/**
* Reverses a String as per {@link StrBuilder#reverse()}.
*
* A null
String returns null
.
*
*
* StringUtils.reverse(null) = null
* StringUtils.reverse("") = ""
* StringUtils.reverse("bat") = "tab"
*
*
* @param str the String to reverse, may be null
* @return the reversed String, null
if null String input
*/
public static String reverse(String str) {
if (str == null) {
return null;
}
return new StrBuilder(str).reverse().toString();
}
/**
* 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 '.'
).
*
*
* 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, 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);
}
/**
* 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 "."
).
*
*
* StringUtils.reverseDelimitedString(null, *) = null
* StringUtils.reverseDelimitedString("",*) = ""
* StringUtils.reverseDelimitedString("a.b.c", null) = "a.b.c"
* StringUtils.reverseDelimitedString("a.b.c", ".") = "c.b.a"
*
*
* @param str the String to reverse, may be null
* @param separatorChars the separator characters to use, null treated as whitespace
* @return the reversed String, null
if null String input
* @deprecated Use {@link #reverseDelimited(String, char)} instead.
* This method is broken as the join doesn't know which char to use.
* Method will be removed in Commons Lang 3.0.
*
*/
public static String reverseDelimitedString(String str, String separatorChars) {
if (str == null) {
return null;
}
// could implement manually, but simple way is to reuse other,
// probably slower, methods.
String[] strs = split(str, separatorChars);
ArrayUtils.reverse(strs);
if (separatorChars == null) {
return join(strs, ' ');
}
return join(strs, separatorChars);
}
// Abbreviating
//-----------------------------------------------------------------------
/**
* Abbreviates a String using ellipses. This will turn
* "Now is the time for all good men" into "Now is the time for..."
*
* Specifically:
*
* - If
str
is less than maxWidth
characters
* long, return it.
* - Else abbreviate it to
(substring(str, 0, max-3) + "...")
.
* - If
maxWidth
is less than 4
, throw an
* IllegalArgumentException
.
* - In no case will it return a String of length greater than
*
maxWidth
.
*
*
*
*
* 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, 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 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
* 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, 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);
}
if (offset <= 4) {
return str.substring(0, maxWidth - 3) + "...";
}
if (maxWidth < 7) {
throw new IllegalArgumentException("Minimum abbreviation width with offset is 7");
}
if ((offset + (maxWidth - 3)) < str.length()) {
return "..." + abbreviate(str.substring(offset), maxWidth - 3);
}
return "..." + 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:
*
* - Neither the String for abbreviation nor the replacement String are null or empty
* - The length to truncate to is less than the length of the supplied String
* - The length to truncate to is greater than 0
* - The abbreviated String will have enough room for the length supplied replacement String
* and the first and last characters of the supplied String for abbreviation
*
* Otherwise, the returned String will be the same as the supplied String for abbreviation.
*
*
*
* 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 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;
StrBuilder builder = new StrBuilder(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,
* 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 Strings, and returns the index at which the
* Strings begin to differ.
*
* For example,
* 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 str1 the first String, may be null
* @param str2 the second String, may be null
* @return the index where str2 and str1 begin to differ; -1 if they are equal
* @since 2.0
*/
public static int indexOfDifference(String str1, String str2) {
if (str1 == str2) {
return INDEX_NOT_FOUND;
}
if (str1 == null || str2 == null) {
return 0;
}
int i;
for (i = 0; i < str1.length() && i < str2.length(); ++i) {
if (str1.charAt(i) != str2.charAt(i)) {
break;
}
}
if (i < str2.length() || i < str1.length()) {
return i;
}
return INDEX_NOT_FOUND;
}
/**
* Compares all Strings in an array and returns the index at which the
* Strings 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 strs array of strings, entries may be null
* @return the index where the strings begin to differ; -1 if they are all equal
* @since 2.4
*/
public static int indexOfDifference(String[] strs) {
if (strs == null || strs.length <= 1) {
return INDEX_NOT_FOUND;
}
boolean anyStringNull = false;
boolean allStringsNull = true;
int arrayLen = strs.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 (strs[i] == null) {
anyStringNull = true;
shortestStrLen = 0;
} else {
allStringsNull = false;
shortestStrLen = Math.min(strs[i].length(), shortestStrLen);
longestStrLen = Math.max(strs[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 = strs[0].charAt(stringPos);
for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
if (strs[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 null
*/
public static int getLevenshteinDistance(String s, String 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
String 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];
}
// startsWith
//-----------------------------------------------------------------------
/**
* Check if a String starts with a specified prefix.
*
* null
s are handled without exceptions. Two 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 String to check, may be null
* @param prefix the prefix to find, may be null
* @return true
if the String starts with the prefix, case sensitive, or
* both null
* @since 2.4
*/
public static boolean startsWith(String str, String prefix) {
return startsWith(str, prefix, false);
}
/**
* Case insensitive check if a String starts with a specified prefix.
*
* null
s are handled without exceptions. Two 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 String to check, may be null
* @param prefix the prefix to find, may be null
* @return true
if the String starts with the prefix, case insensitive, or
* both null
* @since 2.4
*/
public static boolean startsWithIgnoreCase(String str, String prefix) {
return startsWith(str, prefix, true);
}
/**
* Check if a String starts with a specified prefix (optionally case insensitive).
*
* @see java.lang.String#startsWith(String)
* @param str the String to check, may be null
* @param prefix the prefix to find, may be null
* @param ignoreCase inidicates whether the compare should ignore case
* (case insensitive) or not.
* @return true
if the String starts with the prefix or
* both null
*/
private static boolean startsWith(String str, String prefix, boolean ignoreCase) {
if (str == null || prefix == null) {
return (str == null && prefix == null);
}
if (prefix.length() > str.length()) {
return false;
}
return str.regionMatches(ignoreCase, 0, prefix, 0, prefix.length());
}
/**
* Check if a String 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
*
*
* @see #startsWith(String, String)
* @param string the String to check, may be null
* @param searchStrings the Strings to find, may be null or empty
* @return true
if the String starts with any of the the prefixes, case insensitive, or
* both null
* @since 2.5
*/
public static boolean startsWithAny(String string, String[] searchStrings) {
if (isEmpty(string) || ArrayUtils.isEmpty(searchStrings)) {
return false;
}
for (int i = 0; i < searchStrings.length; i++) {
String searchString = searchStrings[i];
if (StringUtils.startsWith(string, searchString)) {
return true;
}
}
return false;
}
// endsWith
//-----------------------------------------------------------------------
/**
* Check if a String ends with a specified suffix.
*
* null
s are handled without exceptions. Two 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 String to check, may be null
* @param suffix the suffix to find, may be null
* @return true
if the String ends with the suffix, case sensitive, or
* both null
* @since 2.4
*/
public static boolean endsWith(String str, String suffix) {
return endsWith(str, suffix, false);
}
/**
* Case insensitive check if a String ends with a specified suffix.
*
* null
s are handled without exceptions. Two 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 String to check, may be null
* @param suffix the suffix to find, may be null
* @return true
if the String ends with the suffix, case insensitive, or
* both null
* @since 2.4
*/
public static boolean endsWithIgnoreCase(String str, String suffix) {
return endsWith(str, suffix, true);
}
/**
* Check if a String ends with a specified suffix (optionally case insensitive).
*
* @see java.lang.String#endsWith(String)
* @param str the String to check, may be null
* @param suffix the suffix to find, may be null
* @param ignoreCase inidicates whether the compare should ignore case
* (case insensitive) or not.
* @return true
if the String starts with the prefix or
* both null
*/
private static boolean endsWith(String str, String 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 str.regionMatches(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.
*
* In XML Whitespace characters are the same as those allowed by the S production, which is S ::= (#x20 | #x9 | #xD | #xA)+
*
* See Java's {@link Character#isWhitespace(char)} for which characters are considered whitespace.
*
* The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
* normalize. Additonally {@link #trim(String)}
removes control characters (char <= 32) from both
* ends of this String.
*
*
* @see Character#isWhitespace(char)
* @see #trim(String)
* @see
* http://www.w3.org/TR/xpath/#function-normalize-space
* @param str the source String to normalize whitespaces from, may be null
* @return the modified string with whitespace normalized, null
if null String input
*
* @since 2.6
*/
public static String normalizeSpace(String str) {
str = strip(str);
if(str == null || str.length() <= 2) {
return str;
}
StrBuilder b = new StrBuilder(str.length());
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (Character.isWhitespace(c)) {
if (i > 0 && !Character.isWhitespace(str.charAt(i - 1))) {
b.append(' ');
}
} else {
b.append(c);
}
}
return b.toString();
}
/**
* Check if a String 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 String to check, may be null
* @param searchStrings the Strings to find, may be null or empty
* @return true
if the String ends with any of the the prefixes, case insensitive, or
* both null
* @since 2.6
*/
public static boolean endsWithAny(String string, String[] searchStrings) {
if (isEmpty(string) || ArrayUtils.isEmpty(searchStrings)) {
return false;
}
for (int i = 0; i < searchStrings.length; i++) {
String searchString = searchStrings[i];
if (StringUtils.endsWith(string, searchString)) {
return true;
}
}
return false;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/SystemUtils.java 100644 0 0 173574 11513702446 24163 0 ustar 0 0 /*
* 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.lang;
import java.io.File;
/**
*
* Helpers for java.lang.System
.
*
*
*
* If a system property cannot be read due to security restrictions,
* the corresponding field in this class will be set to null
* and a message will be written to System.err
.
*
*
*
* #ThreadSafe#
*
*
* @author Apache Software Foundation
* @author Based on code from Avalon Excalibur
* @author Based on code from Lucene
* @author Steve Downey
* @author Gary Gregory
* @author Michael Becke
* @author Tetsuya Kaneuchi
* @author Rafal Krupinski
* @author Jason Gritman
* @since 1.0
* @version $Id: SystemUtils.java 1056988 2011-01-09 17:58:53Z niallp $
*/
public class SystemUtils {
private static final int JAVA_VERSION_TRIM_SIZE = 3;
/**
* 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 awt.toolkit
System Property.
*
*
* Holds a class name, on Windows XP this is sun.awt.windows.WToolkit
.
*
*
* On platforms without a GUI, this value is null
.
*
*
*
* Defaults to 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 file.encoding
System Property.
*
*
* File encoding, such as Cp1252
.
*
*
*
* Defaults to 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 file.separator
System Property. File separator ("/"
on UNIX).
*
*
*
* Defaults to 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 java.awt.fonts
System Property.
*
*
*
* Defaults to 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 java.awt.graphicsenv
System Property.
*
*
*
* Defaults to 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 java.awt.headless
System Property.
* The value of this property is the String "true"
or "false"
.
*
*
*
* Defaults to 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 java.awt.printerjob
System Property.
*
*
*
* Defaults to 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 java.class.path
System Property. Java class path.
*
*
*
* Defaults to 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 java.class.version
System Property. Java class format version number.
*
*
*
* Defaults to 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 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 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 java.endorsed.dirs
System Property. Path of endorsed directory or directories.
*
*
*
* Defaults to 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 java.ext.dirs
System Property. Path of extension directory or directories.
*
*
*
* Defaults to 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 java.home
System Property. Java installation directory.
*
*
*
* Defaults to 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 java.io.tmpdir
System Property. Default temp file path.
*
*
*
* Defaults to 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 java.library.path
System Property. List of paths to search when loading libraries.
*
*
*
* Defaults to 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 java.runtime.name
System Property. Java Runtime Environment name.
*
*
*
* Defaults to 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 java.runtime.version
System Property. Java Runtime Environment version.
*
*
*
* Defaults to 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 java.specification.name
System Property. Java Runtime Environment specification name.
*
*
*
* Defaults to 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 java.specification.vendor
System Property. Java Runtime Environment specification vendor.
*
*
*
* Defaults to 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 java.specification.version
System Property. Java Runtime Environment specification version.
*
*
*
* Defaults to 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");
/**
*
* The java.util.prefs.PreferencesFactory
System Property. A class name.
*
*
*
* Defaults to 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 java.vendor
System Property. Java vendor-specific string.
*
*
*
* Defaults to 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 java.vendor.url
System Property. Java vendor URL.
*
*
*
* Defaults to 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 java.version
System Property. Java version number.
*
*
*
* Defaults to 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 java.vm.info
System Property. Java Virtual Machine implementation info.
*
*
*
* Defaults to 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 java.vm.name
System Property. Java Virtual Machine implementation name.
*
*
*
* Defaults to 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 java.vm.specification.name
System Property. Java Virtual Machine specification name.
*
*
*
* Defaults to 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 java.vm.specification.vendor
System Property. Java Virtual Machine specification vendor.
*
*
*
* Defaults to 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 java.vm.specification.version
System Property. Java Virtual Machine specification version.
*
*
*
* Defaults to 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 java.vm.vendor
System Property. Java Virtual Machine implementation vendor.
*
*
*
* Defaults to 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 java.vm.version
System Property. Java Virtual Machine implementation version.
*
*
*
* Defaults to 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 line.separator
System Property. Line separator ("\n"
on UNIX).
*
*
*
* Defaults to 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 os.arch
System Property. Operating system architecture.
*
*
*
* Defaults to 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 os.name
System Property. Operating system name.
*
*
*
* Defaults to 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 os.version
System Property. Operating system version.
*
*
*
* Defaults to 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 path.separator
System Property. Path separator (":"
on UNIX).
*
*
*
* Defaults to 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 user.country
or user.region
System Property.
* User's country code, such as GB
. First in
* Java version 1.2 as user.region
. Renamed to user.country
in 1.4
*
*
*
* Defaults to 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 user.dir
System Property. User's current working directory.
*
*
*
* Defaults to 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 user.home
System Property. User's home directory.
*
*
*
* Defaults to 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 user.language
System Property. User's language code, such as "en"
.
*
*
*
* Defaults to 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 user.name
System Property. User's account name.
*
*
*
* Defaults to 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 user.timezone
System Property. For example: "America/Los_Angeles"
.
*
*
*
* Defaults to 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
// -----------------------------------------------------------------------
// This MUST be declared after those above as it depends on the
// values being set up
/**
*
* Gets the Java version as a String
trimming leading letters.
*
*
*
* The field will return null
if {@link #JAVA_VERSION} is null
.
*
*
* @since 2.1
*/
public static final String JAVA_VERSION_TRIMMED = getJavaVersionTrimmed();
// Java version values
// -----------------------------------------------------------------------
// These MUST be declared after the trim above as they depend on the
// value being set up
/**
*
* Gets the Java version as a float
.
*
*
*
* Example return values:
*
*
* 1.2f
for Java 1.2
* 1.31f
for Java 1.3.1
*
*
*
* The field will return zero if {@link #JAVA_VERSION} is null
.
*
*
* @since 2.0
*/
public static final float JAVA_VERSION_FLOAT = getJavaVersionAsFloat();
/**
*
* Gets the Java version as an int
.
*
*
*
* Example return values:
*
*
* 120
for Java 1.2
* 131
for Java 1.3.1
*
*
*
* The field will return zero if {@link #JAVA_VERSION} is null
.
*
*
* @since 2.0
*/
public static final int JAVA_VERSION_INT = getJavaVersionAsInt();
// Java version checks
// -----------------------------------------------------------------------
// These MUST be declared after those above as they depend on the
// values being set up
/**
*
* Is true
if this is Java version 1.1 (also 1.1.x versions).
*
*
*
* The field will return false
if {@link #JAVA_VERSION} is null
.
*
*/
public static final boolean IS_JAVA_1_1 = getJavaVersionMatches("1.1");
/**
*
* Is true
if this is Java version 1.2 (also 1.2.x versions).
*
*
*
* The field will return false
if {@link #JAVA_VERSION} is null
.
*
*/
public static final boolean IS_JAVA_1_2 = getJavaVersionMatches("1.2");
/**
*
* Is true
if this is Java version 1.3 (also 1.3.x versions).
*
*
*
* The field will return false
if {@link #JAVA_VERSION} is null
.
*
*/
public static final boolean IS_JAVA_1_3 = getJavaVersionMatches("1.3");
/**
*
* Is true
if this is Java version 1.4 (also 1.4.x versions).
*
*
*
* The field will return false
if {@link #JAVA_VERSION} is null
.
*
*/
public static final boolean IS_JAVA_1_4 = getJavaVersionMatches("1.4");
/**
*
* Is true
if this is Java version 1.5 (also 1.5.x versions).
*
*
*
* The field will return false
if {@link #JAVA_VERSION} is null
.
*
*/
public static final boolean IS_JAVA_1_5 = getJavaVersionMatches("1.5");
/**
*
* Is true
if this is Java version 1.6 (also 1.6.x versions).
*
*
*
* The field will return false
if {@link #JAVA_VERSION} is null
.
*
*/
public static final boolean IS_JAVA_1_6 = getJavaVersionMatches("1.6");
/**
*
* Is true
if this is Java version 1.7 (also 1.7.x versions).
*
*
*
* The field will return false
if {@link #JAVA_VERSION} is null
.
*
*
* @since 2.5
*/
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 true
if this is AIX.
*
*
*
* The field will return false
if OS_NAME
is null
.
*
*
* @since 2.0
*/
public static final boolean IS_OS_AIX = getOSMatchesName("AIX");
/**
*
* Is true
if this is HP-UX.
*
*
*
* The field will return false
if OS_NAME
is null
.
*
*
* @since 2.0
*/
public static final boolean IS_OS_HP_UX = getOSMatchesName("HP-UX");
/**
*
* Is true
if this is Irix.
*
*
*
* The field will return false
if OS_NAME
is null
.
*
*
* @since 2.0
*/
public static final boolean IS_OS_IRIX = getOSMatchesName("Irix");
/**
*
* Is true
if this is Linux.
*
*
*
* The field will return false
if OS_NAME
is null
.
*
*
* @since 2.0
*/
public static final boolean IS_OS_LINUX = getOSMatchesName("Linux") || getOSMatchesName("LINUX");
/**
*
* Is true
if this is Mac.
*
*
*
* The field will return false
if OS_NAME
is null
.
*
*
* @since 2.0
*/
public static final boolean IS_OS_MAC = getOSMatchesName("Mac");
/**
*
* Is true
if this is Mac.
*
*
*
* The field will return false
if OS_NAME
is null
.
*
*
* @since 2.0
*/
public static final boolean IS_OS_MAC_OSX = getOSMatchesName("Mac OS X");
/**
*
* Is true
if this is OS/2.
*
*
*
* The field will return false
if OS_NAME
is null
.
*
*
* @since 2.0
*/
public static final boolean IS_OS_OS2 = getOSMatchesName("OS/2");
/**
*
* Is true
if this is Solaris.
*
*
*
* The field will return false
if OS_NAME
is null
.
*
*
* @since 2.0
*/
public static final boolean IS_OS_SOLARIS = getOSMatchesName("Solaris");
/**
*
* Is true
if this is SunOS.
*
*
*
* The field will return false
if OS_NAME
is null
.
*
*
* @since 2.0
*/
public static final boolean IS_OS_SUN_OS = getOSMatchesName("SunOS");
/**
*
* Is 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 false
if OS_NAME
is 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 true
if this is Windows.
*
*
*
* The field will return false
if OS_NAME
is null
.
*
*
* @since 2.0
*/
public static final boolean IS_OS_WINDOWS = getOSMatchesName(OS_NAME_WINDOWS_PREFIX);
/**
*
* Is true
if this is Windows 2000.
*
*
*
* The field will return false
if OS_NAME
is null
.
*
*
* @since 2.0
*/
public static final boolean IS_OS_WINDOWS_2000 = getOSMatches(OS_NAME_WINDOWS_PREFIX, "5.0");
/**
*
* Is true
if this is Windows 95.
*
*
*
* The field will return false
if OS_NAME
is 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 true
if this is Windows 98.
*
*
*
* The field will return false
if OS_NAME
is 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 true
if this is Windows ME.
*
*
*
* The field will return false
if OS_NAME
is 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 true
if this is Windows NT.
*
*
*
* The field will return false
if OS_NAME
is 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 true
if this is Windows XP.
*
*
*
* The field will return false
if OS_NAME
is null
.
*
*
* @since 2.0
*/
public static final boolean IS_OS_WINDOWS_XP = getOSMatches(OS_NAME_WINDOWS_PREFIX, "5.1");
// -----------------------------------------------------------------------
/**
*
* Is true
if this is Windows Vista.
*
*
*
* The field will return false
if OS_NAME
is null
.
*
*
* @since 2.4
*/
public static final boolean IS_OS_WINDOWS_VISTA = getOSMatches(OS_NAME_WINDOWS_PREFIX, "6.0");
/**
*
* Is true
if this is Windows 7.
*
*
*
* The field will return false
if OS_NAME
is null
.
*
*
* @since 2.5
*/
public static final boolean IS_OS_WINDOWS_7 = getOSMatches(OS_NAME_WINDOWS_PREFIX, "6.1");
/**
*
* Gets the Java home directory as a File
.
*
*
* @return a directory
* @throws SecurityException if a security manager exists and its
* 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 File
.
*
*
* @return a directory
* @throws SecurityException if a security manager exists and its
* 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));
}
/**
* Gets the Java version number as a float
.
*
* Example return values:
*
* 1.2f
for JDK 1.2
* 1.31f
for JDK 1.3.1
*
*
* @return the version, for example 1.31f for JDK 1.3.1
* @deprecated Use {@link #JAVA_VERSION_FLOAT} instead.
* Method will be removed in Commons Lang 3.0.
*/
public static float getJavaVersion() {
return JAVA_VERSION_FLOAT;
}
/**
*
* Gets the Java version number as a float
.
*
*
*
* Example return values:
*
*
* 1.2f
for Java 1.2
* 1.31f
for Java 1.3.1
* 1.6f
for Java 1.6.0_20
*
*
*
* Patch releases are not reported.
*
*
* @return the version, for example 1.31f for Java 1.3.1
*/
private static float getJavaVersionAsFloat() {
return toVersionFloat(toJavaVersionIntArray(SystemUtils.JAVA_VERSION, JAVA_VERSION_TRIM_SIZE));
}
/**
*
* Gets the Java version number as an int
.
*
*
*
* Example return values:
*
*
* 120
for Java 1.2
* 131
for Java 1.3.1
* 160
for Java 1.6.0_20
*
*
*
* Patch releases are not reported.
*
*
* @return the version, for example 131 for Java 1.3.1
*/
private static int getJavaVersionAsInt() {
return toVersionInt(toJavaVersionIntArray(SystemUtils.JAVA_VERSION, JAVA_VERSION_TRIM_SIZE));
}
/**
*
* 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_VERSION_TRIMMED, versionPrefix);
}
/**
* Trims the text of the java version to start with numbers.
*
* @return the trimmed java version
*/
private static String getJavaVersionTrimmed() {
if (JAVA_VERSION != null) {
for (int i = 0; i < JAVA_VERSION.length(); i++) {
char ch = JAVA_VERSION.charAt(i);
if (ch >= '0' && ch <= '9') {
return JAVA_VERSION.substring(i);
}
}
}
return null;
}
/**
* 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 null
if the property cannot be read.
*
*
*
* If a SecurityException
is caught, the return value is null
and a message is written to
* System.err
.
*
*
* @param property
* the system property name
* @return the system property value or 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 File
.
*
*
* @return a directory
* @throws SecurityException if a security manager exists and its
* 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 File
.
*
*
* @return a directory
* @throws SecurityException if a security manager exists and its
* 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 true
.
*
* @return true
if JAVA_AWT_HEADLESS
is "true"
, 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:
*
*
* 1.2f
to test for Java 1.2
* 1.31f
to test for Java 1.3.1
*
*
* @param requiredVersion
* the required version, for example 1.31f
* @return true
if the actual version is equal or greater than the required version
*/
public static boolean isJavaVersionAtLeast(float requiredVersion) {
return JAVA_VERSION_FLOAT >= requiredVersion;
}
/**
*
* Is the Java version at least the requested version.
*
*
*
* Example input:
*
*
* 120
to test for Java 1.2 or greater
* 131
to test for Java 1.3.1 or greater
*
*
* @param requiredVersion
* the required version, for example 131
* @return true
if the actual version is equal or greater than the required version
* @since 2.0
*/
public static boolean isJavaVersionAtLeast(int requiredVersion) {
return JAVA_VERSION_INT >= requiredVersion;
}
/**
*
* 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);
}
/**
*
* Converts the given Java version string to a float
.
*
*
*
* Example return values:
*
*
* 1.2f
for Java 1.2
* 1.31f
for Java 1.3.1
* 1.6f
for Java 1.6.0_20
*
*
*
* Patch releases are not reported.
*
*
* This method is package private instead of private to support unit test invocation.
*
*
* @param version The string version
* @return the version, for example 1.31f for Java 1.3.1
*/
static float toJavaVersionFloat(String version) {
return toVersionFloat(toJavaVersionIntArray(version, JAVA_VERSION_TRIM_SIZE));
}
/**
*
* Converts the given Java version string to an int
.
*
*
*
* Example return values:
*
*
* 120
for Java 1.2
* 131
for Java 1.3.1
* 160
for Java 1.6.0_20
*
*
*
* Patch releases are not reported.
*
*
* This method is package private instead of private to support unit test invocation.
*
*
* @param version The string version
* @return the version, for example 131 for Java 1.3.1
*/
static int toJavaVersionInt(String version) {
return toVersionInt(toJavaVersionIntArray(version, JAVA_VERSION_TRIM_SIZE));
}
/**
*
* Converts the given Java version string to an int[]
of maximum size 3
.
*
*
*
* Example return values:
*
*
* [1, 2, 0]
for Java 1.2
* [1, 3, 1]
for Java 1.3.1
* [1, 5, 0]
for Java 1.5.0_21
*
*
* This method is package private instead of private to support unit test invocation.
*
*
* @param version The string version
* @return the version, for example [1, 5, 0] for Java 1.5.0_21
*/
static int[] toJavaVersionIntArray(String version) {
return toJavaVersionIntArray(version, Integer.MAX_VALUE);
}
/**
*
* Converts the given Java version string to an int[]
of maximum size limit
.
*
*
*
* Example return values:
*
*
* [1, 2, 0]
for Java 1.2
* [1, 3, 1]
for Java 1.3.1
* [1, 5, 0, 21]
for Java 1.5.0_21
*
*
* @param version The string version
* @param limit version limit
* @return the version, for example [1, 5, 0, 21] for Java 1.5.0_21
*/
private static int[] toJavaVersionIntArray(String version, int limit) {
if (version == null) {
return ArrayUtils.EMPTY_INT_ARRAY;
}
String[] strings = StringUtils.split(version, "._- ");
int[] ints = new int[Math.min(limit, strings.length)];
int j = 0;
for (int i = 0; i < strings.length && j < limit; i++) {
String s = strings[i];
if (s.length() > 0) {
try {
ints[j] = Integer.parseInt(s);
j++;
} catch (Exception e) {
}
}
}
if (ints.length > j) {
int[] newInts = new int[j];
System.arraycopy(ints, 0, newInts, 0, j);
ints = newInts;
}
return ints;
}
/**
*
* Converts given the Java version array to a float
.
*
*
*
* Example return values:
*
*
* 1.2f
for Java 1.2
* 1.31f
for Java 1.3.1
* 1.6f
for Java 1.6.0_20
*
*
*
* Patch releases are not reported.
*
*
* @param javaVersions The version numbers
* @return the version, for example 1.31f for Java 1.3.1
*/
private static float toVersionFloat(int[] javaVersions) {
if (javaVersions == null || javaVersions.length == 0) {
return 0f;
}
if (javaVersions.length == 1) {
return javaVersions[0];
}
StringBuffer builder = new StringBuffer();
builder.append(javaVersions[0]);
builder.append('.');
for (int i = 1; i < javaVersions.length; i++) {
builder.append(javaVersions[i]);
}
try {
return Float.parseFloat(builder.toString());
} catch (Exception ex) {
return 0f;
}
}
/**
*
* Converts given the Java version array to an int
.
*
*
*
* Example return values:
*
*
* 120
for Java 1.2
* 131
for Java 1.3.1
* 160
for Java 1.6.0_20
*
*
*
* Patch releases are not reported.
*
*
* @param javaVersions The version numbers
* @return the version, for example 1.31f for Java 1.3.1
*/
private static int toVersionInt(int[] javaVersions) {
if (javaVersions == null) {
return 0;
}
int intVersion = 0;
int len = javaVersions.length;
if (len >= 1) {
intVersion = javaVersions[0] * 100;
}
if (len >= 2) {
intVersion += javaVersions[1] * 10;
}
if (len >= 3) {
intVersion += javaVersions[2];
}
return intVersion;
}
// -----------------------------------------------------------------------
/**
*
* SystemUtils instances should NOT be constructed in standard programming. Instead, the class should be used as
* SystemUtils.FILE_SEPARATOR
.
*
*
*
* This constructor is public to permit tools that require a JavaBean instance to operate.
*
*/
public SystemUtils() {
super();
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/text/CompositeFormat.java 100644 0 0 7432 11513702441 25675 0 ustar 0 0 /*
* 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.lang.text;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParseException;
import java.text.ParsePosition;
/**
* Formats using one formatter and parses using a different formatter. An
* example of use for this would be a webapp where data is taken in one way and
* stored in a database another way.
*
* @author Apache Software Foundation
* @author Archimedes Trajano
* @version $Id: CompositeFormat.java 905636 2010-02-02 14:03:32Z niallp $
*/
public class CompositeFormat extends Format {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = -4329119827877627683L;
/** The parser to use. */
private final Format parser;
/** The formatter to use. */
private final Format formatter;
/**
* Create a format that points its parseObject method to one implementation
* and its format method to another.
*
* @param parser implementation
* @param formatter implementation
*/
public CompositeFormat(Format parser, Format formatter) {
this.parser = parser;
this.formatter = formatter;
}
/**
* Uses the formatter Format instance.
*
* @param obj the object to format
* @param toAppendTo the {@link StringBuffer} to append to
* @param pos the FieldPosition to use (or ignore).
* @return toAppendTo
* @see Format#format(Object, StringBuffer, FieldPosition)
*/
public StringBuffer format(Object obj, StringBuffer toAppendTo,
FieldPosition pos) {
return formatter.format(obj, toAppendTo, pos);
}
/**
* Uses the parser Format instance.
*
* @param source the String source
* @param pos the ParsePosition containing the position to parse from, will
* be updated according to parsing success (index) or failure
* (error index)
* @return the parsed Object
* @see Format#parseObject(String, ParsePosition)
*/
public Object parseObject(String source, ParsePosition pos) {
return parser.parseObject(source, pos);
}
/**
* Provides access to the parser Format implementation.
*
* @return parser Format implementation
*/
public Format getParser() {
return this.parser;
}
/**
* Provides access to the parser Format implementation.
*
* @return formatter Format implementation
*/
public Format getFormatter() {
return this.formatter;
}
/**
* Utility method to parse and then reformat a String.
*
* @param input String to reformat
* @return A reformatted String
* @throws ParseException thrown by parseObject(String) call
*/
public String reformat(String input) throws ParseException {
return format(parseObject(input));
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/text/ExtendedMessageFormat.java 100644 0 0 46156 11513702441 27026 0 ustar 0 0 /*
* 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.lang.text;
import java.text.Format;
import java.text.MessageFormat;
import java.text.ParsePosition;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.Validate;
/**
* Extends java.text.MessageFormat
to allow pluggable/additional formatting
* options for embedded format elements. Client code should specify a registry
* of FormatFactory
instances associated with String
* format names. This registry will be consulted when the format elements are
* parsed from the message pattern. In this way custom patterns can be specified,
* and the formats supported by java.text.MessageFormat
can be overridden
* at the format and/or format style level (see MessageFormat). A "format element"
* embedded in the message pattern is specified (()? signifies optionality):
* {
argument-number(,
format-name(,
format-style)?)?}
*
*
* format-name and format-style values are trimmed of surrounding whitespace
* in the manner of java.text.MessageFormat
. If format-name denotes
* FormatFactory formatFactoryInstance
in registry
, a Format
* matching format-name and format-style is requested from
* formatFactoryInstance
. If this is successful, the Format
* found is used for this format element.
*
*
* NOTICE:: The various subformat mutator methods are considered unnecessary; they exist on the parent
* class to allow the type of customization which it is the job of this class to provide in
* a configurable fashion. These methods have thus been disabled and will throw
* UnsupportedOperationException
if called.
*
*
* Limitations inherited from java.text.MessageFormat
:
*
* - When using "choice" subformats, support for nested formatting instructions is limited
* to that provided by the base class.
* - Thread-safety of
Format
s, including MessageFormat
and thus
* ExtendedMessageFormat
, is not guaranteed.
*
*
*
* @author Apache Software Foundation
* @author Matt Benson
* @since 2.4
* @version $Id: ExtendedMessageFormat.java 1057427 2011-01-11 00:28:01Z niallp $
*/
public class ExtendedMessageFormat extends MessageFormat {
private static final long serialVersionUID = -2362048321261811743L;
private static final int HASH_SEED = 31;
private static final String DUMMY_PATTERN = "";
private static final String ESCAPED_QUOTE = "''";
private static final char START_FMT = ',';
private static final char END_FE = '}';
private static final char START_FE = '{';
private static final char QUOTE = '\'';
private String toPattern;
private final Map registry;
/**
* Create a new ExtendedMessageFormat for the default locale.
*
* @param pattern the pattern to use, not null
* @throws IllegalArgumentException in case of a bad pattern.
*/
public ExtendedMessageFormat(String pattern) {
this(pattern, Locale.getDefault());
}
/**
* Create a new ExtendedMessageFormat.
*
* @param pattern the pattern to use, not null
* @param locale the locale to use, not null
* @throws IllegalArgumentException in case of a bad pattern.
*/
public ExtendedMessageFormat(String pattern, Locale locale) {
this(pattern, locale, null);
}
/**
* Create a new ExtendedMessageFormat for the default locale.
*
* @param pattern the pattern to use, not null
* @param registry the registry of format factories, may be null
* @throws IllegalArgumentException in case of a bad pattern.
*/
public ExtendedMessageFormat(String pattern, Map registry) {
this(pattern, Locale.getDefault(), registry);
}
/**
* Create a new ExtendedMessageFormat.
*
* @param pattern the pattern to use, not null
* @param locale the locale to use, not null
* @param registry the registry of format factories, may be null
* @throws IllegalArgumentException in case of a bad pattern.
*/
public ExtendedMessageFormat(String pattern, Locale locale, Map registry) {
super(DUMMY_PATTERN);
setLocale(locale);
this.registry = registry;
applyPattern(pattern);
}
/**
* {@inheritDoc}
*/
public String toPattern() {
return toPattern;
}
/**
* Apply the specified pattern.
*
* @param pattern String
*/
public final void applyPattern(String pattern) {
if (registry == null) {
super.applyPattern(pattern);
toPattern = super.toPattern();
return;
}
ArrayList foundFormats = new ArrayList();
ArrayList foundDescriptions = new ArrayList();
StrBuilder stripCustom = new StrBuilder(pattern.length());
ParsePosition pos = new ParsePosition(0);
char[] c = pattern.toCharArray();
int fmtCount = 0;
while (pos.getIndex() < pattern.length()) {
switch (c[pos.getIndex()]) {
case QUOTE:
appendQuotedString(pattern, pos, stripCustom, true);
break;
case START_FE:
fmtCount++;
seekNonWs(pattern, pos);
int start = pos.getIndex();
int index = readArgumentIndex(pattern, next(pos));
stripCustom.append(START_FE).append(index);
seekNonWs(pattern, pos);
Format format = null;
String formatDescription = null;
if (c[pos.getIndex()] == START_FMT) {
formatDescription = parseFormatDescription(pattern,
next(pos));
format = getFormat(formatDescription);
if (format == null) {
stripCustom.append(START_FMT).append(formatDescription);
}
}
foundFormats.add(format);
foundDescriptions.add(format == null ? null : formatDescription);
Validate.isTrue(foundFormats.size() == fmtCount);
Validate.isTrue(foundDescriptions.size() == fmtCount);
if (c[pos.getIndex()] != END_FE) {
throw new IllegalArgumentException(
"Unreadable format element at position " + start);
}
//$FALL-THROUGH$
default:
stripCustom.append(c[pos.getIndex()]);
next(pos);
}
}
super.applyPattern(stripCustom.toString());
toPattern = insertFormats(super.toPattern(), foundDescriptions);
if (containsElements(foundFormats)) {
Format[] origFormats = getFormats();
// only loop over what we know we have, as MessageFormat on Java 1.3
// seems to provide an extra format element:
int i = 0;
for (Iterator it = foundFormats.iterator(); it.hasNext(); i++) {
Format f = (Format) it.next();
if (f != null) {
origFormats[i] = f;
}
}
super.setFormats(origFormats);
}
}
/**
* Throws UnsupportedOperationException - see class Javadoc for details.
*
* @param formatElementIndex format element index
* @param newFormat the new format
* @throws UnsupportedOperationException
*/
public void setFormat(int formatElementIndex, Format newFormat) {
throw new UnsupportedOperationException();
}
/**
* Throws UnsupportedOperationException - see class Javadoc for details.
*
* @param argumentIndex argument index
* @param newFormat the new format
* @throws UnsupportedOperationException
*/
public void setFormatByArgumentIndex(int argumentIndex, Format newFormat) {
throw new UnsupportedOperationException();
}
/**
* Throws UnsupportedOperationException - see class Javadoc for details.
*
* @param newFormats new formats
* @throws UnsupportedOperationException
*/
public void setFormats(Format[] newFormats) {
throw new UnsupportedOperationException();
}
/**
* Throws UnsupportedOperationException - see class Javadoc for details.
*
* @param newFormats new formats
* @throws UnsupportedOperationException
*/
public void setFormatsByArgumentIndex(Format[] newFormats) {
throw new UnsupportedOperationException();
}
/**
* Check if this extended message format is equal to another object.
*
* @param obj the object to compare to
* @return true if this object equals the other, otherwise false
* @since 2.6
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null) {
return false;
}
if (!super.equals(obj)) {
return false;
}
if (ObjectUtils.notEqual(getClass(), obj.getClass())) {
return false;
}
ExtendedMessageFormat rhs = (ExtendedMessageFormat)obj;
if (ObjectUtils.notEqual(toPattern, rhs.toPattern)) {
return false;
}
if (ObjectUtils.notEqual(registry, rhs.registry)) {
return false;
}
return true;
}
/**
* Return the hashcode.
*
* @return the hashcode
* @since 2.6
*/
public int hashCode() {
int result = super.hashCode();
result = HASH_SEED * result + ObjectUtils.hashCode(registry);
result = HASH_SEED * result + ObjectUtils.hashCode(toPattern);
return result;
}
/**
* Get a custom format from a format description.
*
* @param desc String
* @return Format
*/
private Format getFormat(String desc) {
if (registry != null) {
String name = desc;
String args = null;
int i = desc.indexOf(START_FMT);
if (i > 0) {
name = desc.substring(0, i).trim();
args = desc.substring(i + 1).trim();
}
FormatFactory factory = (FormatFactory) registry.get(name);
if (factory != null) {
return factory.getFormat(name, args, getLocale());
}
}
return null;
}
/**
* Read the argument index from the current format element
*
* @param pattern pattern to parse
* @param pos current parse position
* @return argument index
*/
private int readArgumentIndex(String pattern, ParsePosition pos) {
int start = pos.getIndex();
seekNonWs(pattern, pos);
StrBuilder result = new StrBuilder();
boolean error = false;
for (; !error && pos.getIndex() < pattern.length(); next(pos)) {
char c = pattern.charAt(pos.getIndex());
if (Character.isWhitespace(c)) {
seekNonWs(pattern, pos);
c = pattern.charAt(pos.getIndex());
if (c != START_FMT && c != END_FE) {
error = true;
continue;
}
}
if ((c == START_FMT || c == END_FE) && result.length() > 0) {
try {
return Integer.parseInt(result.toString());
} catch (NumberFormatException e) {
// we've already ensured only digits, so unless something
// outlandishly large was specified we should be okay.
}
}
error = !Character.isDigit(c);
result.append(c);
}
if (error) {
throw new IllegalArgumentException(
"Invalid format argument index at position " + start + ": "
+ pattern.substring(start, pos.getIndex()));
}
throw new IllegalArgumentException(
"Unterminated format element at position " + start);
}
/**
* Parse the format component of a format element.
*
* @param pattern string to parse
* @param pos current parse position
* @return Format description String
*/
private String parseFormatDescription(String pattern, ParsePosition pos) {
int start = pos.getIndex();
seekNonWs(pattern, pos);
int text = pos.getIndex();
int depth = 1;
for (; pos.getIndex() < pattern.length(); next(pos)) {
switch (pattern.charAt(pos.getIndex())) {
case START_FE:
depth++;
break;
case END_FE:
depth--;
if (depth == 0) {
return pattern.substring(text, pos.getIndex());
}
break;
case QUOTE:
getQuotedString(pattern, pos, false);
break;
}
}
throw new IllegalArgumentException(
"Unterminated format element at position " + start);
}
/**
* Insert formats back into the pattern for toPattern() support.
*
* @param pattern source
* @param customPatterns The custom patterns to re-insert, if any
* @return full pattern
*/
private String insertFormats(String pattern, ArrayList customPatterns) {
if (!containsElements(customPatterns)) {
return pattern;
}
StrBuilder sb = new StrBuilder(pattern.length() * 2);
ParsePosition pos = new ParsePosition(0);
int fe = -1;
int depth = 0;
while (pos.getIndex() < pattern.length()) {
char c = pattern.charAt(pos.getIndex());
switch (c) {
case QUOTE:
appendQuotedString(pattern, pos, sb, false);
break;
case START_FE:
depth++;
if (depth == 1) {
fe++;
sb.append(START_FE).append(
readArgumentIndex(pattern, next(pos)));
String customPattern = (String) customPatterns.get(fe);
if (customPattern != null) {
sb.append(START_FMT).append(customPattern);
}
}
break;
case END_FE:
depth--;
//$FALL-THROUGH$
default:
sb.append(c);
next(pos);
}
}
return sb.toString();
}
/**
* Consume whitespace from the current parse position.
*
* @param pattern String to read
* @param pos current position
*/
private void seekNonWs(String pattern, ParsePosition pos) {
int len = 0;
char[] buffer = pattern.toCharArray();
do {
len = StrMatcher.splitMatcher().isMatch(buffer, pos.getIndex());
pos.setIndex(pos.getIndex() + len);
} while (len > 0 && pos.getIndex() < pattern.length());
}
/**
* Convenience method to advance parse position by 1
*
* @param pos ParsePosition
* @return pos
*/
private ParsePosition next(ParsePosition pos) {
pos.setIndex(pos.getIndex() + 1);
return pos;
}
/**
* Consume a quoted string, adding it to appendTo
if
* specified.
*
* @param pattern pattern to parse
* @param pos current parse position
* @param appendTo optional StringBuffer to append
* @param escapingOn whether to process escaped quotes
* @return appendTo
*/
private StrBuilder appendQuotedString(String pattern, ParsePosition pos,
StrBuilder appendTo, boolean escapingOn) {
int start = pos.getIndex();
char[] c = pattern.toCharArray();
if (escapingOn && c[start] == QUOTE) {
next(pos);
return appendTo == null ? null : appendTo.append(QUOTE);
}
int lastHold = start;
for (int i = pos.getIndex(); i < pattern.length(); i++) {
if (escapingOn && pattern.substring(i).startsWith(ESCAPED_QUOTE)) {
appendTo.append(c, lastHold, pos.getIndex() - lastHold).append(
QUOTE);
pos.setIndex(i + ESCAPED_QUOTE.length());
lastHold = pos.getIndex();
continue;
}
switch (c[pos.getIndex()]) {
case QUOTE:
next(pos);
return appendTo == null ? null : appendTo.append(c, lastHold,
pos.getIndex() - lastHold);
default:
next(pos);
}
}
throw new IllegalArgumentException(
"Unterminated quoted string at position " + start);
}
/**
* Consume quoted string only
*
* @param pattern pattern to parse
* @param pos current parse position
* @param escapingOn whether to process escaped quotes
*/
private void getQuotedString(String pattern, ParsePosition pos,
boolean escapingOn) {
appendQuotedString(pattern, pos, null, escapingOn);
}
/**
* Learn whether the specified Collection contains non-null elements.
* @param coll to check
* @return true
if some Object was found, false
otherwise.
*/
private boolean containsElements(Collection coll) {
if (coll == null || coll.size() == 0) {
return false;
}
for (Iterator iter = coll.iterator(); iter.hasNext();) {
if (iter.next() != null) {
return true;
}
}
return false;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/text/FormatFactory.java 100644 0 0 3137 11513702441 25340 0 ustar 0 0 /*
* 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.lang.text;
import java.text.Format;
import java.util.Locale;
/**
* Format factory.
*
* @author Apache Software Foundation
* @since 2.4
* @version $Id: FormatFactory.java 905636 2010-02-02 14:03:32Z niallp $
*/
public interface FormatFactory {
/**
* Create or retrieve a format instance.
*
* @param name The format type name
* @param arguments Arguments used to create the format instance. This allows the
* FormatFactory
to implement the "format style"
* concept from java.text.MessageFormat
.
* @param locale The locale, may be null
* @return The format instance
*/
Format getFormat(String name, String arguments, Locale locale);
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/text/package.html 100644 0 0 2073 11513702441 24174 0 ustar 0 0
Provides classes for handling and manipulating text, partly as an extension to {@link java.text}.
The classes in this package are, for the most part, intended to be instantiated.
(ie. they are not utility classes with lots of static methods)
@since 2.1
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/text/StrBuilder.java 100644 0 0 276700 11513702441 24707 0 ustar 0 0 /*
* 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.lang.text;
import java.io.Reader;
import java.io.Writer;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.SystemUtils;
/**
* Builds a string from constituent parts providing a more flexible and powerful API
* than StringBuffer.
*
* The main differences from StringBuffer/StringBuilder are:
*
* - Not synchronized
* - Not final
* - Subclasses have direct access to character array
* - Additional methods
*
* - appendWithSeparators - adds an array of values, with a separator
* - appendPadding - adds a length padding characters
* - appendFixedLength - adds a fixed width field to the builder
* - toCharArray/getChars - simpler ways to get a range of the character array
* - delete - delete char or string
* - replace - search and replace for a char or string
* - leftString/rightString/midString - substring without exceptions
* - contains - whether the builder contains a char or string
* - size/clear/isEmpty - collections style API methods
*
*
*
* Views
*
* - asTokenizer - uses the internal buffer as the source of a StrTokenizer
* - asReader - uses the internal buffer as the source of a Reader
* - asWriter - allows a Writer to write directly to the internal buffer
*
*
*
*
* The aim has been to provide an API that mimics very closely what StringBuffer
* provides, but with additional methods. It should be noted that some edge cases,
* with invalid indices or null input, have been altered - see individual methods.
* The biggest of these changes is that by default, null will not output the text
* 'null'. This can be controlled by a property, {@link #setNullText(String)}.
*
* Prior to 3.0, this class implemented Cloneable but did not implement the
* clone method so could not be used. From 3.0 onwards it no longer implements
* the interface.
*
* @author Apache Software Foundation
* @since 2.2
* @version $Id: StrBuilder.java 1057349 2011-01-10 20:40:49Z niallp $
*/
public class StrBuilder implements Cloneable {
/**
* The extra capacity for new builders.
*/
static final int CAPACITY = 32;
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 7628716375283629643L;
/** Internal data storage. */
protected char[] buffer; // TODO make private?
/** Current size of the buffer. */
protected int size; // TODO make private?
/** The new line. */
private String newLine;
/** The null text. */
private String nullText;
//-----------------------------------------------------------------------
/**
* Constructor that creates an empty builder initial capacity 32 characters.
*/
public StrBuilder() {
this(CAPACITY);
}
/**
* Constructor that creates an empty builder the specified initial capacity.
*
* @param initialCapacity the initial capacity, zero or less will be converted to 32
*/
public StrBuilder(int initialCapacity) {
super();
if (initialCapacity <= 0) {
initialCapacity = CAPACITY;
}
buffer = new char[initialCapacity];
}
/**
* Constructor that creates a builder from the string, allocating
* 32 extra characters for growth.
*
* @param str the string to copy, null treated as blank string
*/
public StrBuilder(String str) {
super();
if (str == null) {
buffer = new char[CAPACITY];
} else {
buffer = new char[str.length() + CAPACITY];
append(str);
}
}
//-----------------------------------------------------------------------
/**
* Gets the text to be appended when a new line is added.
*
* @return the new line text, null means use system default
*/
public String getNewLineText() {
return newLine;
}
/**
* Sets the text to be appended when a new line is added.
*
* @param newLine the new line text, null means use system default
* @return this, to enable chaining
*/
public StrBuilder setNewLineText(String newLine) {
this.newLine = newLine;
return this;
}
//-----------------------------------------------------------------------
/**
* Gets the text to be appended when null is added.
*
* @return the null text, null means no append
*/
public String getNullText() {
return nullText;
}
/**
* Sets the text to be appended when null is added.
*
* @param nullText the null text, null means no append
* @return this, to enable chaining
*/
public StrBuilder setNullText(String nullText) {
if (nullText != null && nullText.length() == 0) {
nullText = null;
}
this.nullText = nullText;
return this;
}
//-----------------------------------------------------------------------
/**
* Gets the length of the string builder.
*
* @return the length
*/
public int length() {
return size;
}
/**
* Updates the length of the builder by either dropping the last characters
* or adding filler of unicode zero.
*
* @param length the length to set to, must be zero or positive
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if the length is negative
*/
public StrBuilder setLength(int length) {
if (length < 0) {
throw new StringIndexOutOfBoundsException(length);
}
if (length < size) {
size = length;
} else if (length > size) {
ensureCapacity(length);
int oldEnd = size;
int newEnd = length;
size = length;
for (int i = oldEnd; i < newEnd; i++) {
buffer[i] = '\0';
}
}
return this;
}
//-----------------------------------------------------------------------
/**
* Gets the current size of the internal character array buffer.
*
* @return the capacity
*/
public int capacity() {
return buffer.length;
}
/**
* Checks the capacity and ensures that it is at least the size specified.
*
* @param capacity the capacity to ensure
* @return this, to enable chaining
*/
public StrBuilder ensureCapacity(int capacity) {
if (capacity > buffer.length) {
char[] old = buffer;
buffer = new char[capacity * 2];
System.arraycopy(old, 0, buffer, 0, size);
}
return this;
}
/**
* Minimizes the capacity to the actual length of the string.
*
* @return this, to enable chaining
*/
public StrBuilder minimizeCapacity() {
if (buffer.length > length()) {
char[] old = buffer;
buffer = new char[length()];
System.arraycopy(old, 0, buffer, 0, size);
}
return this;
}
//-----------------------------------------------------------------------
/**
* Gets the length of the string builder.
*
* This method is the same as {@link #length()} and is provided to match the
* API of Collections.
*
* @return the length
*/
public int size() {
return size;
}
/**
* Checks is the string builder is empty (convenience Collections API style method).
*
* This method is the same as checking {@link #length()} and is provided to match the
* API of Collections.
*
* @return true
if the size is 0
.
*/
public boolean isEmpty() {
return size == 0;
}
/**
* Clears the string builder (convenience Collections API style method).
*
* This method does not reduce the size of the internal character buffer.
* To do that, call clear()
followed by {@link #minimizeCapacity()}.
*
* This method is the same as {@link #setLength(int)} called with zero
* and is provided to match the API of Collections.
*
* @return this, to enable chaining
*/
public StrBuilder clear() {
size = 0;
return this;
}
//-----------------------------------------------------------------------
/**
* Gets the character at the specified index.
*
* @see #setCharAt(int, char)
* @see #deleteCharAt(int)
* @param index the index to retrieve, must be valid
* @return the character at the index
* @throws IndexOutOfBoundsException if the index is invalid
*/
public char charAt(int index) {
if (index < 0 || index >= length()) {
throw new StringIndexOutOfBoundsException(index);
}
return buffer[index];
}
/**
* Sets the character at the specified index.
*
* @see #charAt(int)
* @see #deleteCharAt(int)
* @param index the index to set
* @param ch the new character
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if the index is invalid
*/
public StrBuilder setCharAt(int index, char ch) {
if (index < 0 || index >= length()) {
throw new StringIndexOutOfBoundsException(index);
}
buffer[index] = ch;
return this;
}
/**
* Deletes the character at the specified index.
*
* @see #charAt(int)
* @see #setCharAt(int, char)
* @param index the index to delete
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if the index is invalid
*/
public StrBuilder deleteCharAt(int index) {
if (index < 0 || index >= size) {
throw new StringIndexOutOfBoundsException(index);
}
deleteImpl(index, index + 1, 1);
return this;
}
//-----------------------------------------------------------------------
/**
* Copies the builder's character array into a new character array.
*
* @return a new array that represents the contents of the builder
*/
public char[] toCharArray() {
if (size == 0) {
return ArrayUtils.EMPTY_CHAR_ARRAY;
}
char chars[] = new char[size];
System.arraycopy(buffer, 0, chars, 0, size);
return chars;
}
/**
* Copies part of the builder's character array into a new character array.
*
* @param startIndex the start index, inclusive, must be valid
* @param endIndex the end index, exclusive, must be valid except that
* if too large it is treated as end of string
* @return a new array that holds part of the contents of the builder
* @throws IndexOutOfBoundsException if startIndex is invalid,
* or if endIndex is invalid (but endIndex greater than size is valid)
*/
public char[] toCharArray(int startIndex, int endIndex) {
endIndex = validateRange(startIndex, endIndex);
int len = endIndex - startIndex;
if (len == 0) {
return ArrayUtils.EMPTY_CHAR_ARRAY;
}
char chars[] = new char[len];
System.arraycopy(buffer, startIndex, chars, 0, len);
return chars;
}
/**
* Copies the character array into the specified array.
*
* @param destination the destination array, null will cause an array to be created
* @return the input array, unless that was null or too small
*/
public char[] getChars(char[] destination) {
int len = length();
if (destination == null || destination.length < len) {
destination = new char[len];
}
System.arraycopy(buffer, 0, destination, 0, len);
return destination;
}
/**
* Copies the character array into the specified array.
*
* @param startIndex first index to copy, inclusive, must be valid
* @param endIndex last index, exclusive, must be valid
* @param destination the destination array, must not be null or too small
* @param destinationIndex the index to start copying in destination
* @throws NullPointerException if the array is null
* @throws IndexOutOfBoundsException if any index is invalid
*/
public void getChars(int startIndex, int endIndex, char destination[], int destinationIndex) {
if (startIndex < 0) {
throw new StringIndexOutOfBoundsException(startIndex);
}
if (endIndex < 0 || endIndex > length()) {
throw new StringIndexOutOfBoundsException(endIndex);
}
if (startIndex > endIndex) {
throw new StringIndexOutOfBoundsException("end < start");
}
System.arraycopy(buffer, startIndex, destination, destinationIndex, endIndex - startIndex);
}
//-----------------------------------------------------------------------
/**
* Appends the new line string to this string builder.
*
* The new line string can be altered using {@link #setNewLineText(String)}.
* This might be used to force the output to always use Unix line endings
* even when on Windows.
*
* @return this, to enable chaining
*/
public StrBuilder appendNewLine() {
if (newLine == null) {
append(SystemUtils.LINE_SEPARATOR);
return this;
}
return append(newLine);
}
/**
* Appends the text representing null
to this string builder.
*
* @return this, to enable chaining
*/
public StrBuilder appendNull() {
if (nullText == null) {
return this;
}
return append(nullText);
}
/**
* Appends an object to this string builder.
* Appending null will call {@link #appendNull()}.
*
* @param obj the object to append
* @return this, to enable chaining
*/
public StrBuilder append(Object obj) {
if (obj == null) {
return appendNull();
}
return append(obj.toString());
}
/**
* Appends a string to this string builder.
* Appending null will call {@link #appendNull()}.
*
* @param str the string to append
* @return this, to enable chaining
*/
public StrBuilder append(String str) {
if (str == null) {
return appendNull();
}
int strLen = str.length();
if (strLen > 0) {
int len = length();
ensureCapacity(len + strLen);
str.getChars(0, strLen, buffer, len);
size += strLen;
}
return this;
}
/**
* Appends part of a string to this string builder.
* Appending null will call {@link #appendNull()}.
*
* @param str the string to append
* @param startIndex the start index, inclusive, must be valid
* @param length the length to append, must be valid
* @return this, to enable chaining
*/
public StrBuilder append(String str, int startIndex, int length) {
if (str == null) {
return appendNull();
}
if (startIndex < 0 || startIndex > str.length()) {
throw new StringIndexOutOfBoundsException("startIndex must be valid");
}
if (length < 0 || (startIndex + length) > str.length()) {
throw new StringIndexOutOfBoundsException("length must be valid");
}
if (length > 0) {
int len = length();
ensureCapacity(len + length);
str.getChars(startIndex, startIndex + length, buffer, len);
size += length;
}
return this;
}
/**
* Appends a string buffer to this string builder.
* Appending null will call {@link #appendNull()}.
*
* @param str the string buffer to append
* @return this, to enable chaining
*/
public StrBuilder append(StringBuffer str) {
if (str == null) {
return appendNull();
}
int strLen = str.length();
if (strLen > 0) {
int len = length();
ensureCapacity(len + strLen);
str.getChars(0, strLen, buffer, len);
size += strLen;
}
return this;
}
/**
* Appends part of a string buffer to this string builder.
* Appending null will call {@link #appendNull()}.
*
* @param str the string to append
* @param startIndex the start index, inclusive, must be valid
* @param length the length to append, must be valid
* @return this, to enable chaining
*/
public StrBuilder append(StringBuffer str, int startIndex, int length) {
if (str == null) {
return appendNull();
}
if (startIndex < 0 || startIndex > str.length()) {
throw new StringIndexOutOfBoundsException("startIndex must be valid");
}
if (length < 0 || (startIndex + length) > str.length()) {
throw new StringIndexOutOfBoundsException("length must be valid");
}
if (length > 0) {
int len = length();
ensureCapacity(len + length);
str.getChars(startIndex, startIndex + length, buffer, len);
size += length;
}
return this;
}
/**
* Appends another string builder to this string builder.
* Appending null will call {@link #appendNull()}.
*
* @param str the string builder to append
* @return this, to enable chaining
*/
public StrBuilder append(StrBuilder str) {
if (str == null) {
return appendNull();
}
int strLen = str.length();
if (strLen > 0) {
int len = length();
ensureCapacity(len + strLen);
System.arraycopy(str.buffer, 0, buffer, len, strLen);
size += strLen;
}
return this;
}
/**
* Appends part of a string builder to this string builder.
* Appending null will call {@link #appendNull()}.
*
* @param str the string to append
* @param startIndex the start index, inclusive, must be valid
* @param length the length to append, must be valid
* @return this, to enable chaining
*/
public StrBuilder append(StrBuilder str, int startIndex, int length) {
if (str == null) {
return appendNull();
}
if (startIndex < 0 || startIndex > str.length()) {
throw new StringIndexOutOfBoundsException("startIndex must be valid");
}
if (length < 0 || (startIndex + length) > str.length()) {
throw new StringIndexOutOfBoundsException("length must be valid");
}
if (length > 0) {
int len = length();
ensureCapacity(len + length);
str.getChars(startIndex, startIndex + length, buffer, len);
size += length;
}
return this;
}
/**
* Appends a char array to the string builder.
* Appending null will call {@link #appendNull()}.
*
* @param chars the char array to append
* @return this, to enable chaining
*/
public StrBuilder append(char[] chars) {
if (chars == null) {
return appendNull();
}
int strLen = chars.length;
if (strLen > 0) {
int len = length();
ensureCapacity(len + strLen);
System.arraycopy(chars, 0, buffer, len, strLen);
size += strLen;
}
return this;
}
/**
* Appends a char array to the string builder.
* Appending null will call {@link #appendNull()}.
*
* @param chars the char array to append
* @param startIndex the start index, inclusive, must be valid
* @param length the length to append, must be valid
* @return this, to enable chaining
*/
public StrBuilder append(char[] chars, int startIndex, int length) {
if (chars == null) {
return appendNull();
}
if (startIndex < 0 || startIndex > chars.length) {
throw new StringIndexOutOfBoundsException("Invalid startIndex: " + length);
}
if (length < 0 || (startIndex + length) > chars.length) {
throw new StringIndexOutOfBoundsException("Invalid length: " + length);
}
if (length > 0) {
int len = length();
ensureCapacity(len + length);
System.arraycopy(chars, startIndex, buffer, len, length);
size += length;
}
return this;
}
/**
* Appends a boolean value to the string builder.
*
* @param value the value to append
* @return this, to enable chaining
*/
public StrBuilder append(boolean value) {
if (value) {
ensureCapacity(size + 4);
buffer[size++] = 't';
buffer[size++] = 'r';
buffer[size++] = 'u';
buffer[size++] = 'e';
} else {
ensureCapacity(size + 5);
buffer[size++] = 'f';
buffer[size++] = 'a';
buffer[size++] = 'l';
buffer[size++] = 's';
buffer[size++] = 'e';
}
return this;
}
/**
* Appends a char value to the string builder.
*
* @param ch the value to append
* @return this, to enable chaining
*/
public StrBuilder append(char ch) {
int len = length();
ensureCapacity(len + 1);
buffer[size++] = ch;
return this;
}
/**
* Appends an int value to the string builder using String.valueOf
.
*
* @param value the value to append
* @return this, to enable chaining
*/
public StrBuilder append(int value) {
return append(String.valueOf(value));
}
/**
* Appends a long value to the string builder using String.valueOf
.
*
* @param value the value to append
* @return this, to enable chaining
*/
public StrBuilder append(long value) {
return append(String.valueOf(value));
}
/**
* Appends a float value to the string builder using String.valueOf
.
*
* @param value the value to append
* @return this, to enable chaining
*/
public StrBuilder append(float value) {
return append(String.valueOf(value));
}
/**
* Appends a double value to the string builder using String.valueOf
.
*
* @param value the value to append
* @return this, to enable chaining
*/
public StrBuilder append(double value) {
return append(String.valueOf(value));
}
//-----------------------------------------------------------------------
/**
* Appends an object followed by a new line to this string builder.
* Appending null will call {@link #appendNull()}.
*
* @param obj the object to append
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendln(Object obj) {
return append(obj).appendNewLine();
}
/**
* Appends a string followed by a new line to this string builder.
* Appending null will call {@link #appendNull()}.
*
* @param str the string to append
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendln(String str) {
return append(str).appendNewLine();
}
/**
* Appends part of a string followed by a new line to this string builder.
* Appending null will call {@link #appendNull()}.
*
* @param str the string to append
* @param startIndex the start index, inclusive, must be valid
* @param length the length to append, must be valid
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendln(String str, int startIndex, int length) {
return append(str, startIndex, length).appendNewLine();
}
/**
* Appends a string buffer followed by a new line to this string builder.
* Appending null will call {@link #appendNull()}.
*
* @param str the string buffer to append
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendln(StringBuffer str) {
return append(str).appendNewLine();
}
/**
* Appends part of a string buffer followed by a new line to this string builder.
* Appending null will call {@link #appendNull()}.
*
* @param str the string to append
* @param startIndex the start index, inclusive, must be valid
* @param length the length to append, must be valid
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendln(StringBuffer str, int startIndex, int length) {
return append(str, startIndex, length).appendNewLine();
}
/**
* Appends another string builder followed by a new line to this string builder.
* Appending null will call {@link #appendNull()}.
*
* @param str the string builder to append
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendln(StrBuilder str) {
return append(str).appendNewLine();
}
/**
* Appends part of a string builder followed by a new line to this string builder.
* Appending null will call {@link #appendNull()}.
*
* @param str the string to append
* @param startIndex the start index, inclusive, must be valid
* @param length the length to append, must be valid
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendln(StrBuilder str, int startIndex, int length) {
return append(str, startIndex, length).appendNewLine();
}
/**
* Appends a char array followed by a new line to the string builder.
* Appending null will call {@link #appendNull()}.
*
* @param chars the char array to append
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendln(char[] chars) {
return append(chars).appendNewLine();
}
/**
* Appends a char array followed by a new line to the string builder.
* Appending null will call {@link #appendNull()}.
*
* @param chars the char array to append
* @param startIndex the start index, inclusive, must be valid
* @param length the length to append, must be valid
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendln(char[] chars, int startIndex, int length) {
return append(chars, startIndex, length).appendNewLine();
}
/**
* Appends a boolean value followed by a new line to the string builder.
*
* @param value the value to append
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendln(boolean value) {
return append(value).appendNewLine();
}
/**
* Appends a char value followed by a new line to the string builder.
*
* @param ch the value to append
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendln(char ch) {
return append(ch).appendNewLine();
}
/**
* Appends an int value followed by a new line to the string builder using String.valueOf
.
*
* @param value the value to append
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendln(int value) {
return append(value).appendNewLine();
}
/**
* Appends a long value followed by a new line to the string builder using String.valueOf
.
*
* @param value the value to append
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendln(long value) {
return append(value).appendNewLine();
}
/**
* Appends a float value followed by a new line to the string builder using String.valueOf
.
*
* @param value the value to append
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendln(float value) {
return append(value).appendNewLine();
}
/**
* Appends a double value followed by a new line to the string builder using String.valueOf
.
*
* @param value the value to append
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendln(double value) {
return append(value).appendNewLine();
}
//-----------------------------------------------------------------------
/**
* Appends each item in an array to the builder without any separators.
* Appending a null array will have no effect.
* Each object is appended using {@link #append(Object)}.
*
* @param array the array to append
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendAll(Object[] array) {
if (array != null && array.length > 0) {
for (int i = 0; i < array.length; i++) {
append(array[i]);
}
}
return this;
}
/**
* Appends each item in a collection to the builder without any separators.
* Appending a null collection will have no effect.
* Each object is appended using {@link #append(Object)}.
*
* @param coll the collection to append
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendAll(Collection coll) {
if (coll != null && coll.size() > 0) {
Iterator it = coll.iterator();
while (it.hasNext()) {
append(it.next());
}
}
return this;
}
/**
* Appends each item in an iterator to the builder without any separators.
* Appending a null iterator will have no effect.
* Each object is appended using {@link #append(Object)}.
*
* @param it the iterator to append
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendAll(Iterator it) {
if (it != null) {
while (it.hasNext()) {
append(it.next());
}
}
return this;
}
//-----------------------------------------------------------------------
/**
* Appends an array placing separators between each value, but
* not before the first or after the last.
* Appending a null array will have no effect.
* Each object is appended using {@link #append(Object)}.
*
* @param array the array to append
* @param separator the separator to use, null means no separator
* @return this, to enable chaining
*/
public StrBuilder appendWithSeparators(Object[] array, String separator) {
if (array != null && array.length > 0) {
separator = (separator == null ? "" : separator);
append(array[0]);
for (int i = 1; i < array.length; i++) {
append(separator);
append(array[i]);
}
}
return this;
}
/**
* Appends a collection placing separators between each value, but
* not before the first or after the last.
* Appending a null collection will have no effect.
* Each object is appended using {@link #append(Object)}.
*
* @param coll the collection to append
* @param separator the separator to use, null means no separator
* @return this, to enable chaining
*/
public StrBuilder appendWithSeparators(Collection coll, String separator) {
if (coll != null && coll.size() > 0) {
separator = (separator == null ? "" : separator);
Iterator it = coll.iterator();
while (it.hasNext()) {
append(it.next());
if (it.hasNext()) {
append(separator);
}
}
}
return this;
}
/**
* Appends an iterator placing separators between each value, but
* not before the first or after the last.
* Appending a null iterator will have no effect.
* Each object is appended using {@link #append(Object)}.
*
* @param it the iterator to append
* @param separator the separator to use, null means no separator
* @return this, to enable chaining
*/
public StrBuilder appendWithSeparators(Iterator it, String separator) {
if (it != null) {
separator = (separator == null ? "" : separator);
while (it.hasNext()) {
append(it.next());
if (it.hasNext()) {
append(separator);
}
}
}
return this;
}
//-----------------------------------------------------------------------
/**
* Appends a separator if the builder is currently non-empty.
* Appending a null separator will have no effect.
* The separator is appended using {@link #append(String)}.
*
* This method is useful for adding a separator each time around the
* loop except the first.
*
* for (Iterator it = list.iterator(); it.hasNext(); ) {
* appendSeparator(",");
* append(it.next());
* }
*
* Note that for this simple example, you should use
* {@link #appendWithSeparators(Collection, String)}.
*
* @param separator the separator to use, null means no separator
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendSeparator(String separator) {
return appendSeparator(separator, null);
}
/**
* Appends one of both separators to the StrBuilder.
* If the builder is currently empty it will append the defaultIfEmpty-separator
* Otherwise it will append the standard-separator
*
* Appending a null separator will have no effect.
* The separator is appended using {@link #append(String)}.
*
* This method is for example useful for constructing queries
*
* StrBuilder whereClause = new StrBuilder();
* if(searchCommand.getPriority() != null) {
* whereClause.appendSeparator(" and", " where");
* whereClause.append(" priority = ?")
* }
* if(searchCommand.getComponent() != null) {
* whereClause.appendSeparator(" and", " where");
* whereClause.append(" component = ?")
* }
* selectClause.append(whereClause)
*
*
* @param standard the separator if builder is not empty, null means no separator
* @param defaultIfEmpty the separator if builder is empty, null means no separator
* @return this, to enable chaining
* @since 2.5
*/
public StrBuilder appendSeparator(String standard, String defaultIfEmpty) {
String str = isEmpty() ? defaultIfEmpty : standard;
if (str != null) {
append(str);
}
return this;
}
/**
* Appends a separator if the builder is currently non-empty.
* The separator is appended using {@link #append(char)}.
*
* This method is useful for adding a separator each time around the
* loop except the first.
*
* for (Iterator it = list.iterator(); it.hasNext(); ) {
* appendSeparator(',');
* append(it.next());
* }
*
* Note that for this simple example, you should use
* {@link #appendWithSeparators(Collection, String)}.
*
* @param separator the separator to use
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendSeparator(char separator) {
if (size() > 0) {
append(separator);
}
return this;
}
/**
* Append one of both separators to the builder
* If the builder is currently empty it will append the defaultIfEmpty-separator
* Otherwise it will append the standard-separator
*
* The separator is appended using {@link #append(char)}.
* @param standard the separator if builder is not empty
* @param defaultIfEmpty the separator if builder is empty
* @return this, to enable chaining
* @since 2.5
*/
public StrBuilder appendSeparator(char standard, char defaultIfEmpty) {
if (size() > 0) {
append(standard);
}
else {
append(defaultIfEmpty);
}
return this;
}
/**
* Appends a separator to the builder if the loop index is greater than zero.
* Appending a null separator will have no effect.
* The separator is appended using {@link #append(String)}.
*
* This method is useful for adding a separator each time around the
* loop except the first.
*
* for (int i = 0; i < list.size(); i++) {
* appendSeparator(",", i);
* append(list.get(i));
* }
*
* Note that for this simple example, you should use
* {@link #appendWithSeparators(Collection, String)}.
*
* @param separator the separator to use, null means no separator
* @param loopIndex the loop index
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendSeparator(String separator, int loopIndex) {
if (separator != null && loopIndex > 0) {
append(separator);
}
return this;
}
/**
* Appends a separator to the builder if the loop index is greater than zero.
* The separator is appended using {@link #append(char)}.
*
* This method is useful for adding a separator each time around the
* loop except the first.
*
* for (int i = 0; i < list.size(); i++) {
* appendSeparator(",", i);
* append(list.get(i));
* }
*
* Note that for this simple example, you should use
* {@link #appendWithSeparators(Collection, String)}.
*
* @param separator the separator to use
* @param loopIndex the loop index
* @return this, to enable chaining
* @since 2.3
*/
public StrBuilder appendSeparator(char separator, int loopIndex) {
if (loopIndex > 0) {
append(separator);
}
return this;
}
//-----------------------------------------------------------------------
/**
* Appends the pad character to the builder the specified number of times.
*
* @param length the length to append, negative means no append
* @param padChar the character to append
* @return this, to enable chaining
*/
public StrBuilder appendPadding(int length, char padChar) {
if (length >= 0) {
ensureCapacity(size + length);
for (int i = 0; i < length; i++) {
buffer[size++] = padChar;
}
}
return this;
}
//-----------------------------------------------------------------------
/**
* Appends an object to the builder padding on the left to a fixed width.
* The toString
of the object is used.
* If the object is larger than the length, the left hand side is lost.
* If the object is null, the null text value is used.
*
* @param obj the object to append, null uses null text
* @param width the fixed field width, zero or negative has no effect
* @param padChar the pad character to use
* @return this, to enable chaining
*/
public StrBuilder appendFixedWidthPadLeft(Object obj, int width, char padChar) {
if (width > 0) {
ensureCapacity(size + width);
String str = (obj == null ? getNullText() : obj.toString());
if (str == null) {
str = "";
}
int strLen = str.length();
if (strLen >= width) {
str.getChars(strLen - width, strLen, buffer, size);
} else {
int padLen = width - strLen;
for (int i = 0; i < padLen; i++) {
buffer[size + i] = padChar;
}
str.getChars(0, strLen, buffer, size + padLen);
}
size += width;
}
return this;
}
/**
* Appends an object to the builder padding on the left to a fixed width.
* The String.valueOf
of the int
value is used.
* If the formatted value is larger than the length, the left hand side is lost.
*
* @param value the value to append
* @param width the fixed field width, zero or negative has no effect
* @param padChar the pad character to use
* @return this, to enable chaining
*/
public StrBuilder appendFixedWidthPadLeft(int value, int width, char padChar) {
return appendFixedWidthPadLeft(String.valueOf(value), width, padChar);
}
/**
* Appends an object to the builder padding on the right to a fixed length.
* The toString
of the object is used.
* If the object is larger than the length, the right hand side is lost.
* If the object is null, null text value is used.
*
* @param obj the object to append, null uses null text
* @param width the fixed field width, zero or negative has no effect
* @param padChar the pad character to use
* @return this, to enable chaining
*/
public StrBuilder appendFixedWidthPadRight(Object obj, int width, char padChar) {
if (width > 0) {
ensureCapacity(size + width);
String str = (obj == null ? getNullText() : obj.toString());
if (str == null) {
str = "";
}
int strLen = str.length();
if (strLen >= width) {
str.getChars(0, width, buffer, size);
} else {
int padLen = width - strLen;
str.getChars(0, strLen, buffer, size);
for (int i = 0; i < padLen; i++) {
buffer[size + strLen + i] = padChar;
}
}
size += width;
}
return this;
}
/**
* Appends an object to the builder padding on the right to a fixed length.
* The String.valueOf
of the int
value is used.
* If the object is larger than the length, the right hand side is lost.
*
* @param value the value to append
* @param width the fixed field width, zero or negative has no effect
* @param padChar the pad character to use
* @return this, to enable chaining
*/
public StrBuilder appendFixedWidthPadRight(int value, int width, char padChar) {
return appendFixedWidthPadRight(String.valueOf(value), width, padChar);
}
//-----------------------------------------------------------------------
/**
* Inserts the string representation of an object into this builder.
* Inserting null will use the stored null text value.
*
* @param index the index to add at, must be valid
* @param obj the object to insert
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if the index is invalid
*/
public StrBuilder insert(int index, Object obj) {
if (obj == null) {
return insert(index, nullText);
}
return insert(index, obj.toString());
}
/**
* Inserts the string into this builder.
* Inserting null will use the stored null text value.
*
* @param index the index to add at, must be valid
* @param str the string to insert
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if the index is invalid
*/
public StrBuilder insert(int index, String str) {
validateIndex(index);
if (str == null) {
str = nullText;
}
int strLen = (str == null ? 0 : str.length());
if (strLen > 0) {
int newSize = size + strLen;
ensureCapacity(newSize);
System.arraycopy(buffer, index, buffer, index + strLen, size - index);
size = newSize;
str.getChars(0, strLen, buffer, index); // str cannot be null here
}
return this;
}
/**
* Inserts the character array into this builder.
* Inserting null will use the stored null text value.
*
* @param index the index to add at, must be valid
* @param chars the char array to insert
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if the index is invalid
*/
public StrBuilder insert(int index, char chars[]) {
validateIndex(index);
if (chars == null) {
return insert(index, nullText);
}
int len = chars.length;
if (len > 0) {
ensureCapacity(size + len);
System.arraycopy(buffer, index, buffer, index + len, size - index);
System.arraycopy(chars, 0, buffer, index, len);
size += len;
}
return this;
}
/**
* Inserts part of the character array into this builder.
* Inserting null will use the stored null text value.
*
* @param index the index to add at, must be valid
* @param chars the char array to insert
* @param offset the offset into the character array to start at, must be valid
* @param length the length of the character array part to copy, must be positive
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if any index is invalid
*/
public StrBuilder insert(int index, char chars[], int offset, int length) {
validateIndex(index);
if (chars == null) {
return insert(index, nullText);
}
if (offset < 0 || offset > chars.length) {
throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
}
if (length < 0 || offset + length > chars.length) {
throw new StringIndexOutOfBoundsException("Invalid length: " + length);
}
if (length > 0) {
ensureCapacity(size + length);
System.arraycopy(buffer, index, buffer, index + length, size - index);
System.arraycopy(chars, offset, buffer, index, length);
size += length;
}
return this;
}
/**
* Inserts the value into this builder.
*
* @param index the index to add at, must be valid
* @param value the value to insert
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if the index is invalid
*/
public StrBuilder insert(int index, boolean value) {
validateIndex(index);
if (value) {
ensureCapacity(size + 4);
System.arraycopy(buffer, index, buffer, index + 4, size - index);
buffer[index++] = 't';
buffer[index++] = 'r';
buffer[index++] = 'u';
buffer[index] = 'e';
size += 4;
} else {
ensureCapacity(size + 5);
System.arraycopy(buffer, index, buffer, index + 5, size - index);
buffer[index++] = 'f';
buffer[index++] = 'a';
buffer[index++] = 'l';
buffer[index++] = 's';
buffer[index] = 'e';
size += 5;
}
return this;
}
/**
* Inserts the value into this builder.
*
* @param index the index to add at, must be valid
* @param value the value to insert
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if the index is invalid
*/
public StrBuilder insert(int index, char value) {
validateIndex(index);
ensureCapacity(size + 1);
System.arraycopy(buffer, index, buffer, index + 1, size - index);
buffer[index] = value;
size++;
return this;
}
/**
* Inserts the value into this builder.
*
* @param index the index to add at, must be valid
* @param value the value to insert
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if the index is invalid
*/
public StrBuilder insert(int index, int value) {
return insert(index, String.valueOf(value));
}
/**
* Inserts the value into this builder.
*
* @param index the index to add at, must be valid
* @param value the value to insert
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if the index is invalid
*/
public StrBuilder insert(int index, long value) {
return insert(index, String.valueOf(value));
}
/**
* Inserts the value into this builder.
*
* @param index the index to add at, must be valid
* @param value the value to insert
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if the index is invalid
*/
public StrBuilder insert(int index, float value) {
return insert(index, String.valueOf(value));
}
/**
* Inserts the value into this builder.
*
* @param index the index to add at, must be valid
* @param value the value to insert
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if the index is invalid
*/
public StrBuilder insert(int index, double value) {
return insert(index, String.valueOf(value));
}
//-----------------------------------------------------------------------
/**
* Internal method to delete a range without validation.
*
* @param startIndex the start index, must be valid
* @param endIndex the end index (exclusive), must be valid
* @param len the length, must be valid
* @throws IndexOutOfBoundsException if any index is invalid
*/
private void deleteImpl(int startIndex, int endIndex, int len) {
System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex);
size -= len;
}
/**
* Deletes the characters between the two specified indices.
*
* @param startIndex the start index, inclusive, must be valid
* @param endIndex the end index, exclusive, must be valid except
* that if too large it is treated as end of string
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if the index is invalid
*/
public StrBuilder delete(int startIndex, int endIndex) {
endIndex = validateRange(startIndex, endIndex);
int len = endIndex - startIndex;
if (len > 0) {
deleteImpl(startIndex, endIndex, len);
}
return this;
}
//-----------------------------------------------------------------------
/**
* Deletes the character wherever it occurs in the builder.
*
* @param ch the character to delete
* @return this, to enable chaining
*/
public StrBuilder deleteAll(char ch) {
for (int i = 0; i < size; i++) {
if (buffer[i] == ch) {
int start = i;
while (++i < size) {
if (buffer[i] != ch) {
break;
}
}
int len = i - start;
deleteImpl(start, i, len);
i -= len;
}
}
return this;
}
/**
* Deletes the character wherever it occurs in the builder.
*
* @param ch the character to delete
* @return this, to enable chaining
*/
public StrBuilder deleteFirst(char ch) {
for (int i = 0; i < size; i++) {
if (buffer[i] == ch) {
deleteImpl(i, i + 1, 1);
break;
}
}
return this;
}
//-----------------------------------------------------------------------
/**
* Deletes the string wherever it occurs in the builder.
*
* @param str the string to delete, null causes no action
* @return this, to enable chaining
*/
public StrBuilder deleteAll(String str) {
int len = (str == null ? 0 : str.length());
if (len > 0) {
int index = indexOf(str, 0);
while (index >= 0) {
deleteImpl(index, index + len, len);
index = indexOf(str, index);
}
}
return this;
}
/**
* Deletes the string wherever it occurs in the builder.
*
* @param str the string to delete, null causes no action
* @return this, to enable chaining
*/
public StrBuilder deleteFirst(String str) {
int len = (str == null ? 0 : str.length());
if (len > 0) {
int index = indexOf(str, 0);
if (index >= 0) {
deleteImpl(index, index + len, len);
}
}
return this;
}
//-----------------------------------------------------------------------
/**
* Deletes all parts of the builder that the matcher matches.
*
* Matchers can be used to perform advanced deletion behaviour.
* For example you could write a matcher to delete all occurances
* where the character 'a' is followed by a number.
*
* @param matcher the matcher to use to find the deletion, null causes no action
* @return this, to enable chaining
*/
public StrBuilder deleteAll(StrMatcher matcher) {
return replace(matcher, null, 0, size, -1);
}
/**
* Deletes the first match within the builder using the specified matcher.
*
* Matchers can be used to perform advanced deletion behaviour.
* For example you could write a matcher to delete
* where the character 'a' is followed by a number.
*
* @param matcher the matcher to use to find the deletion, null causes no action
* @return this, to enable chaining
*/
public StrBuilder deleteFirst(StrMatcher matcher) {
return replace(matcher, null, 0, size, 1);
}
//-----------------------------------------------------------------------
/**
* Internal method to delete a range without validation.
*
* @param startIndex the start index, must be valid
* @param endIndex the end index (exclusive), must be valid
* @param removeLen the length to remove (endIndex - startIndex), must be valid
* @param insertStr the string to replace with, null means delete range
* @param insertLen the length of the insert string, must be valid
* @throws IndexOutOfBoundsException if any index is invalid
*/
private void replaceImpl(int startIndex, int endIndex, int removeLen, String insertStr, int insertLen) {
int newSize = size - removeLen + insertLen;
if (insertLen != removeLen) {
ensureCapacity(newSize);
System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex);
size = newSize;
}
if (insertLen > 0) {
insertStr.getChars(0, insertLen, buffer, startIndex);
}
}
/**
* Replaces a portion of the string builder with another string.
* The length of the inserted string does not have to match the removed length.
*
* @param startIndex the start index, inclusive, must be valid
* @param endIndex the end index, exclusive, must be valid except
* that if too large it is treated as end of string
* @param replaceStr the string to replace with, null means delete range
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if the index is invalid
*/
public StrBuilder replace(int startIndex, int endIndex, String replaceStr) {
endIndex = validateRange(startIndex, endIndex);
int insertLen = (replaceStr == null ? 0 : replaceStr.length());
replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen);
return this;
}
//-----------------------------------------------------------------------
/**
* Replaces the search character with the replace character
* throughout the builder.
*
* @param search the search character
* @param replace the replace character
* @return this, to enable chaining
*/
public StrBuilder replaceAll(char search, char replace) {
if (search != replace) {
for (int i = 0; i < size; i++) {
if (buffer[i] == search) {
buffer[i] = replace;
}
}
}
return this;
}
/**
* Replaces the first instance of the search character with the
* replace character in the builder.
*
* @param search the search character
* @param replace the replace character
* @return this, to enable chaining
*/
public StrBuilder replaceFirst(char search, char replace) {
if (search != replace) {
for (int i = 0; i < size; i++) {
if (buffer[i] == search) {
buffer[i] = replace;
break;
}
}
}
return this;
}
//-----------------------------------------------------------------------
/**
* Replaces the search string with the replace string throughout the builder.
*
* @param searchStr the search string, null causes no action to occur
* @param replaceStr the replace string, null is equivalent to an empty string
* @return this, to enable chaining
*/
public StrBuilder replaceAll(String searchStr, String replaceStr) {
int searchLen = (searchStr == null ? 0 : searchStr.length());
if (searchLen > 0) {
int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
int index = indexOf(searchStr, 0);
while (index >= 0) {
replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
index = indexOf(searchStr, index + replaceLen);
}
}
return this;
}
/**
* Replaces the first instance of the search string with the replace string.
*
* @param searchStr the search string, null causes no action to occur
* @param replaceStr the replace string, null is equivalent to an empty string
* @return this, to enable chaining
*/
public StrBuilder replaceFirst(String searchStr, String replaceStr) {
int searchLen = (searchStr == null ? 0 : searchStr.length());
if (searchLen > 0) {
int index = indexOf(searchStr, 0);
if (index >= 0) {
int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
}
}
return this;
}
//-----------------------------------------------------------------------
/**
* Replaces all matches within the builder with the replace string.
*
* Matchers can be used to perform advanced replace behaviour.
* For example you could write a matcher to replace all occurances
* where the character 'a' is followed by a number.
*
* @param matcher the matcher to use to find the deletion, null causes no action
* @param replaceStr the replace string, null is equivalent to an empty string
* @return this, to enable chaining
*/
public StrBuilder replaceAll(StrMatcher matcher, String replaceStr) {
return replace(matcher, replaceStr, 0, size, -1);
}
/**
* Replaces the first match within the builder with the replace string.
*
* Matchers can be used to perform advanced replace behaviour.
* For example you could write a matcher to replace
* where the character 'a' is followed by a number.
*
* @param matcher the matcher to use to find the deletion, null causes no action
* @param replaceStr the replace string, null is equivalent to an empty string
* @return this, to enable chaining
*/
public StrBuilder replaceFirst(StrMatcher matcher, String replaceStr) {
return replace(matcher, replaceStr, 0, size, 1);
}
// -----------------------------------------------------------------------
/**
* Advanced search and replaces within the builder using a matcher.
*
* Matchers can be used to perform advanced behaviour.
* For example you could write a matcher to delete all occurances
* where the character 'a' is followed by a number.
*
* @param matcher the matcher to use to find the deletion, null causes no action
* @param replaceStr the string to replace the match with, null is a delete
* @param startIndex the start index, inclusive, must be valid
* @param endIndex the end index, exclusive, must be valid except
* that if too large it is treated as end of string
* @param replaceCount the number of times to replace, -1 for replace all
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if start index is invalid
*/
public StrBuilder replace(
StrMatcher matcher, String replaceStr,
int startIndex, int endIndex, int replaceCount) {
endIndex = validateRange(startIndex, endIndex);
return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
}
/**
* Replaces within the builder using a matcher.
*
* Matchers can be used to perform advanced behaviour.
* For example you could write a matcher to delete all occurances
* where the character 'a' is followed by a number.
*
* @param matcher the matcher to use to find the deletion, null causes no action
* @param replaceStr the string to replace the match with, null is a delete
* @param from the start index, must be valid
* @param to the end index (exclusive), must be valid
* @param replaceCount the number of times to replace, -1 for replace all
* @return this, to enable chaining
* @throws IndexOutOfBoundsException if any index is invalid
*/
private StrBuilder replaceImpl(
StrMatcher matcher, String replaceStr,
int from, int to, int replaceCount) {
if (matcher == null || size == 0) {
return this;
}
int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
char[] buf = buffer;
for (int i = from; i < to && replaceCount != 0; i++) {
int removeLen = matcher.isMatch(buf, i, from, to);
if (removeLen > 0) {
replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen);
to = to - removeLen + replaceLen;
i = i + replaceLen - 1;
if (replaceCount > 0) {
replaceCount--;
}
}
}
return this;
}
//-----------------------------------------------------------------------
/**
* Reverses the string builder placing each character in the opposite index.
*
* @return this, to enable chaining
*/
public StrBuilder reverse() {
if (size == 0) {
return this;
}
int half = size / 2;
char[] buf = buffer;
for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++,rightIdx--) {
char swap = buf[leftIdx];
buf[leftIdx] = buf[rightIdx];
buf[rightIdx] = swap;
}
return this;
}
//-----------------------------------------------------------------------
/**
* Trims the builder by removing characters less than or equal to a space
* from the beginning and end.
*
* @return this, to enable chaining
*/
public StrBuilder trim() {
if (size == 0) {
return this;
}
int len = size;
char[] buf = buffer;
int pos = 0;
while (pos < len && buf[pos] <= ' ') {
pos++;
}
while (pos < len && buf[len - 1] <= ' ') {
len--;
}
if (len < size) {
delete(len, size);
}
if (pos > 0) {
delete(0, pos);
}
return this;
}
//-----------------------------------------------------------------------
/**
* Checks whether this builder starts with the specified string.
*
* Note that this method handles null input quietly, unlike String.
*
* @param str the string to search for, null returns false
* @return true if the builder starts with the string
*/
public boolean startsWith(String str) {
if (str == null) {
return false;
}
int len = str.length();
if (len == 0) {
return true;
}
if (len > size) {
return false;
}
for (int i = 0; i < len; i++) {
if (buffer[i] != str.charAt(i)) {
return false;
}
}
return true;
}
/**
* Checks whether this builder ends with the specified string.
*
* Note that this method handles null input quietly, unlike String.
*
* @param str the string to search for, null returns false
* @return true if the builder ends with the string
*/
public boolean endsWith(String str) {
if (str == null) {
return false;
}
int len = str.length();
if (len == 0) {
return true;
}
if (len > size) {
return false;
}
int pos = size - len;
for (int i = 0; i < len; i++,pos++) {
if (buffer[pos] != str.charAt(i)) {
return false;
}
}
return true;
}
//-----------------------------------------------------------------------
/**
* Extracts a portion of this string builder as a string.
*
* @param start the start index, inclusive, must be valid
* @return the new string
* @throws IndexOutOfBoundsException if the index is invalid
*/
public String substring(int start) {
return substring(start, size);
}
/**
* Extracts a portion of this string builder as a string.
*
* Note: This method treats an endIndex greater than the length of the
* builder as equal to the length of the builder, and continues
* without error, unlike StringBuffer or String.
*
* @param startIndex the start index, inclusive, must be valid
* @param endIndex the end index, exclusive, must be valid except
* that if too large it is treated as end of string
* @return the new string
* @throws IndexOutOfBoundsException if the index is invalid
*/
public String substring(int startIndex, int endIndex) {
endIndex = validateRange(startIndex, endIndex);
return new String(buffer, startIndex, endIndex - startIndex);
}
/**
* Extracts the leftmost characters from the string builder without
* throwing an exception.
*
* This method extracts the left length
characters from
* the builder. If this many characters are not available, the whole
* builder is returned. Thus the returned string may be shorter than the
* length requested.
*
* @param length the number of characters to extract, negative returns empty string
* @return the new string
*/
public String leftString(int length) {
if (length <= 0) {
return "";
} else if (length >= size) {
return new String(buffer, 0, size);
} else {
return new String(buffer, 0, length);
}
}
/**
* Extracts the rightmost characters from the string builder without
* throwing an exception.
*
* This method extracts the right length
characters from
* the builder. If this many characters are not available, the whole
* builder is returned. Thus the returned string may be shorter than the
* length requested.
*
* @param length the number of characters to extract, negative returns empty string
* @return the new string
*/
public String rightString(int length) {
if (length <= 0) {
return "";
} else if (length >= size) {
return new String(buffer, 0, size);
} else {
return new String(buffer, size - length, length);
}
}
/**
* Extracts some characters from the middle of the string builder without
* throwing an exception.
*
* This method extracts length
characters from the builder
* at the specified index.
* If the index is negative it is treated as zero.
* If the index is greater than the builder size, it is treated as the builder size.
* If the length is negative, the empty string is returned.
* If insufficient characters are available in the builder, as much as possible is returned.
* Thus the returned string may be shorter than the length requested.
*
* @param index the index to start at, negative means zero
* @param length the number of characters to extract, negative returns empty string
* @return the new string
*/
public String midString(int index, int length) {
if (index < 0) {
index = 0;
}
if (length <= 0 || index >= size) {
return "";
}
if (size <= index + length) {
return new String(buffer, index, size - index);
} else {
return new String(buffer, index, length);
}
}
//-----------------------------------------------------------------------
/**
* Checks if the string builder contains the specified char.
*
* @param ch the character to find
* @return true if the builder contains the character
*/
public boolean contains(char ch) {
char[] thisBuf = buffer;
for (int i = 0; i < this.size; i++) {
if (thisBuf[i] == ch) {
return true;
}
}
return false;
}
/**
* Checks if the string builder contains the specified string.
*
* @param str the string to find
* @return true if the builder contains the string
*/
public boolean contains(String str) {
return indexOf(str, 0) >= 0;
}
/**
* Checks if the string builder contains a string matched using the
* specified matcher.
*
* Matchers can be used to perform advanced searching behaviour.
* For example you could write a matcher to search for the character
* 'a' followed by a number.
*
* @param matcher the matcher to use, null returns -1
* @return true if the matcher finds a match in the builder
*/
public boolean contains(StrMatcher matcher) {
return indexOf(matcher, 0) >= 0;
}
//-----------------------------------------------------------------------
/**
* Searches the string builder to find the first reference to the specified char.
*
* @param ch the character to find
* @return the first index of the character, or -1 if not found
*/
public int indexOf(char ch) {
return indexOf(ch, 0);
}
/**
* Searches the string builder to find the first reference to the specified char.
*
* @param ch the character to find
* @param startIndex the index to start at, invalid index rounded to edge
* @return the first index of the character, or -1 if not found
*/
public int indexOf(char ch, int startIndex) {
startIndex = (startIndex < 0 ? 0 : startIndex);
if (startIndex >= size) {
return -1;
}
char[] thisBuf = buffer;
for (int i = startIndex; i < size; i++) {
if (thisBuf[i] == ch) {
return i;
}
}
return -1;
}
/**
* Searches the string builder to find the first reference to the specified string.
*
* Note that a null input string will return -1, whereas the JDK throws an exception.
*
* @param str the string to find, null returns -1
* @return the first index of the string, or -1 if not found
*/
public int indexOf(String str) {
return indexOf(str, 0);
}
/**
* Searches the string builder to find the first reference to the specified
* string starting searching from the given index.
*
* Note that a null input string will return -1, whereas the JDK throws an exception.
*
* @param str the string to find, null returns -1
* @param startIndex the index to start at, invalid index rounded to edge
* @return the first index of the string, or -1 if not found
*/
public int indexOf(String str, int startIndex) {
startIndex = (startIndex < 0 ? 0 : startIndex);
if (str == null || startIndex >= size) {
return -1;
}
int strLen = str.length();
if (strLen == 1) {
return indexOf(str.charAt(0), startIndex);
}
if (strLen == 0) {
return startIndex;
}
if (strLen > size) {
return -1;
}
char[] thisBuf = buffer;
int len = size - strLen + 1;
outer:
for (int i = startIndex; i < len; i++) {
for (int j = 0; j < strLen; j++) {
if (str.charAt(j) != thisBuf[i + j]) {
continue outer;
}
}
return i;
}
return -1;
}
/**
* Searches the string builder using the matcher to find the first match.
*
* Matchers can be used to perform advanced searching behaviour.
* For example you could write a matcher to find the character 'a'
* followed by a number.
*
* @param matcher the matcher to use, null returns -1
* @return the first index matched, or -1 if not found
*/
public int indexOf(StrMatcher matcher) {
return indexOf(matcher, 0);
}
/**
* Searches the string builder using the matcher to find the first
* match searching from the given index.
*
* Matchers can be used to perform advanced searching behaviour.
* For example you could write a matcher to find the character 'a'
* followed by a number.
*
* @param matcher the matcher to use, null returns -1
* @param startIndex the index to start at, invalid index rounded to edge
* @return the first index matched, or -1 if not found
*/
public int indexOf(StrMatcher matcher, int startIndex) {
startIndex = (startIndex < 0 ? 0 : startIndex);
if (matcher == null || startIndex >= size) {
return -1;
}
int len = size;
char[] buf = buffer;
for (int i = startIndex; i < len; i++) {
if (matcher.isMatch(buf, i, startIndex, len) > 0) {
return i;
}
}
return -1;
}
//-----------------------------------------------------------------------
/**
* Searches the string builder to find the last reference to the specified char.
*
* @param ch the character to find
* @return the last index of the character, or -1 if not found
*/
public int lastIndexOf(char ch) {
return lastIndexOf(ch, size - 1);
}
/**
* Searches the string builder to find the last reference to the specified char.
*
* @param ch the character to find
* @param startIndex the index to start at, invalid index rounded to edge
* @return the last index of the character, or -1 if not found
*/
public int lastIndexOf(char ch, int startIndex) {
startIndex = (startIndex >= size ? size - 1 : startIndex);
if (startIndex < 0) {
return -1;
}
for (int i = startIndex; i >= 0; i--) {
if (buffer[i] == ch) {
return i;
}
}
return -1;
}
/**
* Searches the string builder to find the last reference to the specified string.
*
* Note that a null input string will return -1, whereas the JDK throws an exception.
*
* @param str the string to find, null returns -1
* @return the last index of the string, or -1 if not found
*/
public int lastIndexOf(String str) {
return lastIndexOf(str, size - 1);
}
/**
* Searches the string builder to find the last reference to the specified
* string starting searching from the given index.
*
* Note that a null input string will return -1, whereas the JDK throws an exception.
*
* @param str the string to find, null returns -1
* @param startIndex the index to start at, invalid index rounded to edge
* @return the last index of the string, or -1 if not found
*/
public int lastIndexOf(String str, int startIndex) {
startIndex = (startIndex >= size ? size - 1 : startIndex);
if (str == null || startIndex < 0) {
return -1;
}
int strLen = str.length();
if (strLen > 0 && strLen <= size) {
if (strLen == 1) {
return lastIndexOf(str.charAt(0), startIndex);
}
outer:
for (int i = startIndex - strLen + 1; i >= 0; i--) {
for (int j = 0; j < strLen; j++) {
if (str.charAt(j) != buffer[i + j]) {
continue outer;
}
}
return i;
}
} else if (strLen == 0) {
return startIndex;
}
return -1;
}
/**
* Searches the string builder using the matcher to find the last match.
*
* Matchers can be used to perform advanced searching behaviour.
* For example you could write a matcher to find the character 'a'
* followed by a number.
*
* @param matcher the matcher to use, null returns -1
* @return the last index matched, or -1 if not found
*/
public int lastIndexOf(StrMatcher matcher) {
return lastIndexOf(matcher, size);
}
/**
* Searches the string builder using the matcher to find the last
* match searching from the given index.
*
* Matchers can be used to perform advanced searching behaviour.
* For example you could write a matcher to find the character 'a'
* followed by a number.
*
* @param matcher the matcher to use, null returns -1
* @param startIndex the index to start at, invalid index rounded to edge
* @return the last index matched, or -1 if not found
*/
public int lastIndexOf(StrMatcher matcher, int startIndex) {
startIndex = (startIndex >= size ? size - 1 : startIndex);
if (matcher == null || startIndex < 0) {
return -1;
}
char[] buf = buffer;
int endIndex = startIndex + 1;
for (int i = startIndex; i >= 0; i--) {
if (matcher.isMatch(buf, i, 0, endIndex) > 0) {
return i;
}
}
return -1;
}
//-----------------------------------------------------------------------
/**
* Creates a tokenizer that can tokenize the contents of this builder.
*
* This method allows the contents of this builder to be tokenized.
* The tokenizer will be setup by default to tokenize on space, tab,
* newline and formfeed (as per StringTokenizer). These values can be
* changed on the tokenizer class, before retrieving the tokens.
*
* The returned tokenizer is linked to this builder. You may intermix
* calls to the buider and tokenizer within certain limits, however
* there is no synchronization. Once the tokenizer has been used once,
* it must be {@link StrTokenizer#reset() reset} to pickup the latest
* changes in the builder. For example:
*
* StrBuilder b = new StrBuilder();
* b.append("a b ");
* StrTokenizer t = b.asTokenizer();
* String[] tokens1 = t.getTokenArray(); // returns a,b
* b.append("c d ");
* String[] tokens2 = t.getTokenArray(); // returns a,b (c and d ignored)
* t.reset(); // reset causes builder changes to be picked up
* String[] tokens3 = t.getTokenArray(); // returns a,b,c,d
*
* In addition to simply intermixing appends and tokenization, you can also
* call the set methods on the tokenizer to alter how it tokenizes. Just
* remember to call reset when you want to pickup builder changes.
*
* Calling {@link StrTokenizer#reset(String)} or {@link StrTokenizer#reset(char[])}
* with a non-null value will break the link with the builder.
*
* @return a tokenizer that is linked to this builder
*/
public StrTokenizer asTokenizer() {
return new StrBuilderTokenizer();
}
//-----------------------------------------------------------------------
/**
* Gets the contents of this builder as a Reader.
*
* This method allows the contents of the builder to be read
* using any standard method that expects a Reader.
*
* To use, simply create a StrBuilder
, populate it with
* data, call asReader
, and then read away.
*
* The internal character array is shared between the builder and the reader.
* This allows you to append to the builder after creating the reader,
* and the changes will be picked up.
* Note however, that no synchronization occurs, so you must perform
* all operations with the builder and the reader in one thread.
*
* The returned reader supports marking, and ignores the flush method.
*
* @return a reader that reads from this builder
*/
public Reader asReader() {
return new StrBuilderReader();
}
//-----------------------------------------------------------------------
/**
* Gets this builder as a Writer that can be written to.
*
* This method allows you to populate the contents of the builder
* using any standard method that takes a Writer.
*
* To use, simply create a StrBuilder
,
* call asWriter
, and populate away. The data is available
* at any time using the methods of the StrBuilder
.
*
* The internal character array is shared between the builder and the writer.
* This allows you to intermix calls that append to the builder and
* write using the writer and the changes will be occur correctly.
* Note however, that no synchronization occurs, so you must perform
* all operations with the builder and the writer in one thread.
*
* The returned writer ignores the close and flush methods.
*
* @return a writer that populates this builder
*/
public Writer asWriter() {
return new StrBuilderWriter();
}
//-----------------------------------------------------------------------
// /**
// * Gets a String version of the string builder by calling the internal
// * constructor of String by reflection.
// *
// * WARNING: You must not use the StrBuilder after calling this method
// * as the buffer is now shared with the String object. To ensure this,
// * the internal character array is set to null, so you will get
// * NullPointerExceptions on all method calls.
// *
// * @return the builder as a String
// */
// public String toSharedString() {
// try {
// Constructor con = String.class.getDeclaredConstructor(
// new Class[] {int.class, int.class, char[].class});
// con.setAccessible(true);
// char[] buffer = buf;
// buf = null;
// size = -1;
// nullText = null;
// return (String) con.newInstance(
// new Object[] {new Integer(0), new Integer(size), buffer});
//
// } catch (Exception ex) {
// ex.printStackTrace();
// throw new UnsupportedOperationException("StrBuilder.toSharedString is unsupported: " + ex.getMessage());
// }
// }
//-----------------------------------------------------------------------
/**
* Checks the contents of this builder against another to see if they
* contain the same character content ignoring case.
*
* @param other the object to check, null returns false
* @return true if the builders contain the same characters in the same order
*/
public boolean equalsIgnoreCase(StrBuilder other) {
if (this == other) {
return true;
}
if (this.size != other.size) {
return false;
}
char thisBuf[] = this.buffer;
char otherBuf[] = other.buffer;
for (int i = size - 1; i >= 0; i--) {
char c1 = thisBuf[i];
char c2 = otherBuf[i];
if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) {
return false;
}
}
return true;
}
/**
* Checks the contents of this builder against another to see if they
* contain the same character content.
*
* @param other the object to check, null returns false
* @return true if the builders contain the same characters in the same order
*/
public boolean equals(StrBuilder other) {
if (this == other) {
return true;
}
if (this.size != other.size) {
return false;
}
char thisBuf[] = this.buffer;
char otherBuf[] = other.buffer;
for (int i = size - 1; i >= 0; i--) {
if (thisBuf[i] != otherBuf[i]) {
return false;
}
}
return true;
}
/**
* Checks the contents of this builder against another to see if they
* contain the same character content.
*
* @param obj the object to check, null returns false
* @return true if the builders contain the same characters in the same order
*/
public boolean equals(Object obj) {
if (obj instanceof StrBuilder) {
return equals((StrBuilder) obj);
}
return false;
}
/**
* Gets a suitable hash code for this builder.
*
* @return a hash code
*/
public int hashCode() {
char buf[] = buffer;
int hash = 0;
for (int i = size - 1; i >= 0; i--) {
hash = 31 * hash + buf[i];
}
return hash;
}
//-----------------------------------------------------------------------
/**
* Gets a String version of the string builder, creating a new instance
* each time the method is called.
*
* Note that unlike StringBuffer, the string version returned is
* independent of the string builder.
*
* @return the builder as a String
*/
public String toString() {
return new String(buffer, 0, size);
}
/**
* Gets a StringBuffer version of the string builder, creating a
* new instance each time the method is called.
*
* @return the builder as a StringBuffer
*/
public StringBuffer toStringBuffer() {
return new StringBuffer(size).append(buffer, 0, size);
}
/**
* Clone this object.
*
* @return a clone of this object
* @throws CloneNotSupportedException if clone is not supported
* @since 2.6
*/
public Object clone() throws CloneNotSupportedException {
StrBuilder clone = (StrBuilder)super.clone();
clone.buffer = new char[buffer.length];
System.arraycopy(buffer, 0, clone.buffer, 0, buffer.length);
return clone;
}
//-----------------------------------------------------------------------
/**
* Validates parameters defining a range of the builder.
*
* @param startIndex the start index, inclusive, must be valid
* @param endIndex the end index, exclusive, must be valid except
* that if too large it is treated as end of string
* @return the new string
* @throws IndexOutOfBoundsException if the index is invalid
*/
protected int validateRange(int startIndex, int endIndex) {
if (startIndex < 0) {
throw new StringIndexOutOfBoundsException(startIndex);
}
if (endIndex > size) {
endIndex = size;
}
if (startIndex > endIndex) {
throw new StringIndexOutOfBoundsException("end < start");
}
return endIndex;
}
/**
* Validates parameters defining a single index in the builder.
*
* @param index the index, must be valid
* @throws IndexOutOfBoundsException if the index is invalid
*/
protected void validateIndex(int index) {
if (index < 0 || index > size) {
throw new StringIndexOutOfBoundsException(index);
}
}
//-----------------------------------------------------------------------
/**
* Inner class to allow StrBuilder to operate as a tokenizer.
*/
class StrBuilderTokenizer extends StrTokenizer {
/**
* Default constructor.
*/
StrBuilderTokenizer() {
super();
}
/** {@inheritDoc} */
protected List tokenize(char[] chars, int offset, int count) {
if (chars == null) {
return super.tokenize(StrBuilder.this.buffer, 0, StrBuilder.this.size());
} else {
return super.tokenize(chars, offset, count);
}
}
/** {@inheritDoc} */
public String getContent() {
String str = super.getContent();
if (str == null) {
return StrBuilder.this.toString();
} else {
return str;
}
}
}
//-----------------------------------------------------------------------
/**
* Inner class to allow StrBuilder to operate as a writer.
*/
class StrBuilderReader extends Reader {
/** The current stream position. */
private int pos;
/** The last mark position. */
private int mark;
/**
* Default constructor.
*/
StrBuilderReader() {
super();
}
/** {@inheritDoc} */
public void close() {
// do nothing
}
/** {@inheritDoc} */
public int read() {
if (ready() == false) {
return -1;
}
return StrBuilder.this.charAt(pos++);
}
/** {@inheritDoc} */
public int read(char b[], int off, int len) {
if (off < 0 || len < 0 || off > b.length ||
(off + len) > b.length || (off + len) < 0) {
throw new IndexOutOfBoundsException();
}
if (len == 0) {
return 0;
}
if (pos >= StrBuilder.this.size()) {
return -1;
}
if (pos + len > size()) {
len = StrBuilder.this.size() - pos;
}
StrBuilder.this.getChars(pos, pos + len, b, off);
pos += len;
return len;
}
/** {@inheritDoc} */
public long skip(long n) {
if (pos + n > StrBuilder.this.size()) {
n = StrBuilder.this.size() - pos;
}
if (n < 0) {
return 0;
}
pos += n;
return n;
}
/** {@inheritDoc} */
public boolean ready() {
return pos < StrBuilder.this.size();
}
/** {@inheritDoc} */
public boolean markSupported() {
return true;
}
/** {@inheritDoc} */
public void mark(int readAheadLimit) {
mark = pos;
}
/** {@inheritDoc} */
public void reset() {
pos = mark;
}
}
//-----------------------------------------------------------------------
/**
* Inner class to allow StrBuilder to operate as a writer.
*/
class StrBuilderWriter extends Writer {
/**
* Default constructor.
*/
StrBuilderWriter() {
super();
}
/** {@inheritDoc} */
public void close() {
// do nothing
}
/** {@inheritDoc} */
public void flush() {
// do nothing
}
/** {@inheritDoc} */
public void write(int c) {
StrBuilder.this.append((char) c);
}
/** {@inheritDoc} */
public void write(char[] cbuf) {
StrBuilder.this.append(cbuf);
}
/** {@inheritDoc} */
public void write(char[] cbuf, int off, int len) {
StrBuilder.this.append(cbuf, off, len);
}
/** {@inheritDoc} */
public void write(String str) {
StrBuilder.this.append(str);
}
/** {@inheritDoc} */
public void write(String str, int off, int len) {
StrBuilder.this.append(str, off, len);
}
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/text/StrLookup.java 100644 0 0 13437 11513702441 24546 0 ustar 0 0 /*
* 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.lang.text;
import java.util.Map;
/**
* Lookup a String key to a String value.
*
* This class represents the simplest form of a string to string map.
* It has a benefit over a map in that it can create the result on
* demand based on the key.
*
* This class comes complete with various factory methods.
* If these do not suffice, you can subclass and implement your own matcher.
*
* For example, it would be possible to implement a lookup that used the
* key as a primary key, and looked up the value on demand from the database
*
* @author Apache Software Foundation
* @since 2.2
* @version $Id: StrLookup.java 905636 2010-02-02 14:03:32Z niallp $
*/
public abstract class StrLookup {
/**
* Lookup that always returns null.
*/
private static final StrLookup NONE_LOOKUP;
/**
* Lookup that uses System properties.
*/
private static final StrLookup SYSTEM_PROPERTIES_LOOKUP;
static {
NONE_LOOKUP = new MapStrLookup(null);
StrLookup lookup = null;
try {
lookup = new MapStrLookup(System.getProperties());
} catch (SecurityException ex) {
lookup = NONE_LOOKUP;
}
SYSTEM_PROPERTIES_LOOKUP = lookup;
}
//-----------------------------------------------------------------------
/**
* Returns a lookup which always returns null.
*
* @return a lookup that always returns null, not null
*/
public static StrLookup noneLookup() {
return NONE_LOOKUP;
}
/**
* Returns a lookup which uses {@link System#getProperties() System properties}
* to lookup the key to value.
*
* If a security manager blocked access to system properties, then null will
* be returned from every lookup.
*
* If a null key is used, this lookup will throw a NullPointerException.
*
* @return a lookup using system properties, not null
*/
public static StrLookup systemPropertiesLookup() {
return SYSTEM_PROPERTIES_LOOKUP;
}
/**
* Returns a lookup which looks up values using a map.
*
* If the map is null, then null will be returned from every lookup.
* The map result object is converted to a string using toString().
*
* @param map the map of keys to values, may be null
* @return a lookup using the map, not null
*/
public static StrLookup mapLookup(Map map) {
return new MapStrLookup(map);
}
//-----------------------------------------------------------------------
/**
* Constructor.
*/
protected StrLookup() {
super();
}
/**
* Looks up a String key to a String value.
*
* The internal implementation may use any mechanism to return the value.
* The simplest implementation is to use a Map. However, virtually any
* implementation is possible.
*
* For example, it would be possible to implement a lookup that used the
* key as a primary key, and looked up the value on demand from the database
* Or, a numeric based implementation could be created that treats the key
* as an integer, increments the value and return the result as a string -
* converting 1 to 2, 15 to 16 etc.
*
* The {@link #lookup(String)} method always returns a String, regardless of
* the underlying data, by converting it as necessary. For example:
*
* Map map = new HashMap();
* map.put("number", new Integer(2));
* assertEquals("2", StrLookup.mapLookup(map).lookup("number"));
*
* @param key the key to be looked up, may be null
* @return the matching value, null if no match
*/
public abstract String lookup(String key);
//-----------------------------------------------------------------------
/**
* Lookup implementation that uses a Map.
*/
static class MapStrLookup extends StrLookup {
/** Map keys are variable names and value. */
private final Map map;
/**
* Creates a new instance backed by a Map.
*
* @param map the map of keys to values, may be null
*/
MapStrLookup(Map map) {
this.map = map;
}
/**
* Looks up a String key to a String value using the map.
*
* If the map is null, then null is returned.
* The map result object is converted to a string using toString().
*
* @param key the key to be looked up, may be null
* @return the matching value, null if no match
*/
public String lookup(String key) {
if (map == null) {
return null;
}
Object obj = map.get(key);
if (obj == null) {
return null;
}
return obj.toString();
}
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/text/StrMatcher.java 100644 0 0 35706 11513702441 24663 0 ustar 0 0 /*
* 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.lang.text;
import java.util.Arrays;
/**
* A matcher class that can be queried to determine if a character array
* portion matches.
*
* This class comes complete with various factory methods.
* If these do not suffice, you can subclass and implement your own matcher.
*
* @author Apache Software Foundation
* @since 2.2
* @version $Id: StrMatcher.java 905636 2010-02-02 14:03:32Z niallp $
*/
public abstract class StrMatcher {
/**
* Matches the comma character.
*/
private static final StrMatcher COMMA_MATCHER = new CharMatcher(',');
/**
* Matches the tab character.
*/
private static final StrMatcher TAB_MATCHER = new CharMatcher('\t');
/**
* Matches the space character.
*/
private static final StrMatcher SPACE_MATCHER = new CharMatcher(' ');
/**
* Matches the same characters as StringTokenizer,
* namely space, tab, newline, formfeed.
*/
private static final StrMatcher SPLIT_MATCHER = new CharSetMatcher(" \t\n\r\f".toCharArray());
/**
* Matches the String trim() whitespace characters.
*/
private static final StrMatcher TRIM_MATCHER = new TrimMatcher();
/**
* Matches the double quote character.
*/
private static final StrMatcher SINGLE_QUOTE_MATCHER = new CharMatcher('\'');
/**
* Matches the double quote character.
*/
private static final StrMatcher DOUBLE_QUOTE_MATCHER = new CharMatcher('"');
/**
* Matches the single or double quote character.
*/
private static final StrMatcher QUOTE_MATCHER = new CharSetMatcher("'\"".toCharArray());
/**
* Matches no characters.
*/
private static final StrMatcher NONE_MATCHER = new NoMatcher();
// -----------------------------------------------------------------------
/**
* Returns a matcher which matches the comma character.
*
* @return a matcher for a comma
*/
public static StrMatcher commaMatcher() {
return COMMA_MATCHER;
}
/**
* Returns a matcher which matches the tab character.
*
* @return a matcher for a tab
*/
public static StrMatcher tabMatcher() {
return TAB_MATCHER;
}
/**
* Returns a matcher which matches the space character.
*
* @return a matcher for a space
*/
public static StrMatcher spaceMatcher() {
return SPACE_MATCHER;
}
/**
* Matches the same characters as StringTokenizer,
* namely space, tab, newline and formfeed.
*
* @return the split matcher
*/
public static StrMatcher splitMatcher() {
return SPLIT_MATCHER;
}
/**
* Matches the String trim() whitespace characters.
*
* @return the trim matcher
*/
public static StrMatcher trimMatcher() {
return TRIM_MATCHER;
}
/**
* Returns a matcher which matches the single quote character.
*
* @return a matcher for a single quote
*/
public static StrMatcher singleQuoteMatcher() {
return SINGLE_QUOTE_MATCHER;
}
/**
* Returns a matcher which matches the double quote character.
*
* @return a matcher for a double quote
*/
public static StrMatcher doubleQuoteMatcher() {
return DOUBLE_QUOTE_MATCHER;
}
/**
* Returns a matcher which matches the single or double quote character.
*
* @return a matcher for a single or double quote
*/
public static StrMatcher quoteMatcher() {
return QUOTE_MATCHER;
}
/**
* Matches no characters.
*
* @return a matcher that matches nothing
*/
public static StrMatcher noneMatcher() {
return NONE_MATCHER;
}
/**
* Constructor that creates a matcher from a character.
*
* @param ch the character to match, must not be null
* @return a new Matcher for the given char
*/
public static StrMatcher charMatcher(char ch) {
return new CharMatcher(ch);
}
/**
* Constructor that creates a matcher from a set of characters.
*
* @param chars the characters to match, null or empty matches nothing
* @return a new matcher for the given char[]
*/
public static StrMatcher charSetMatcher(char[] chars) {
if (chars == null || chars.length == 0) {
return NONE_MATCHER;
}
if (chars.length == 1) {
return new CharMatcher(chars[0]);
}
return new CharSetMatcher(chars);
}
/**
* Constructor that creates a matcher from a string representing a set of characters.
*
* @param chars the characters to match, null or empty matches nothing
* @return a new Matcher for the given characters
*/
public static StrMatcher charSetMatcher(String chars) {
if (chars == null || chars.length() == 0) {
return NONE_MATCHER;
}
if (chars.length() == 1) {
return new CharMatcher(chars.charAt(0));
}
return new CharSetMatcher(chars.toCharArray());
}
/**
* Constructor that creates a matcher from a string.
*
* @param str the string to match, null or empty matches nothing
* @return a new Matcher for the given String
*/
public static StrMatcher stringMatcher(String str) {
if (str == null || str.length() == 0) {
return NONE_MATCHER;
}
return new StringMatcher(str);
}
//-----------------------------------------------------------------------
/**
* Constructor.
*/
protected StrMatcher() {
super();
}
/**
* Returns the number of matching characters, zero for no match.
*
* This method is called to check for a match.
* The parameter pos
represents the current position to be
* checked in the string buffer
(a character array which must
* not be changed).
* The API guarantees that pos
is a valid index for buffer
.
*
* The character array may be larger than the active area to be matched.
* Only values in the buffer between the specifed indices may be accessed.
*
* The matching code may check one character or many.
* It may check characters preceeding pos
as well as those
* after, so long as no checks exceed the bounds specified.
*
* It must return zero for no match, or a positive number if a match was found.
* The number indicates the number of characters that matched.
*
* @param buffer the text content to match against, do not change
* @param pos the starting position for the match, valid for buffer
* @param bufferStart the first active index in the buffer, valid for buffer
* @param bufferEnd the end index (exclusive) of the active buffer, valid for buffer
* @return the number of matching characters, zero for no match
*/
public abstract int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd);
/**
* Returns the number of matching characters, zero for no match.
*
* This method is called to check for a match.
* The parameter pos
represents the current position to be
* checked in the string buffer
(a character array which must
* not be changed).
* The API guarantees that pos
is a valid index for buffer
.
*
* The matching code may check one character or many.
* It may check characters preceeding pos
as well as those after.
*
* It must return zero for no match, or a positive number if a match was found.
* The number indicates the number of characters that matched.
*
* @param buffer the text content to match against, do not change
* @param pos the starting position for the match, valid for buffer
* @return the number of matching characters, zero for no match
* @since 2.4
*/
public int isMatch(char[] buffer, int pos) {
return isMatch(buffer, pos, 0, buffer.length);
}
//-----------------------------------------------------------------------
/**
* Class used to define a set of characters for matching purposes.
*/
static final class CharSetMatcher extends StrMatcher {
/** The set of characters to match. */
private final char[] chars;
/**
* Constructor that creates a matcher from a character array.
*
* @param chars the characters to match, must not be null
*/
CharSetMatcher(char chars[]) {
super();
this.chars = (char[]) chars.clone();
Arrays.sort(this.chars);
}
/**
* Returns whether or not the given character matches.
*
* @param buffer the text content to match against, do not change
* @param pos the starting position for the match, valid for buffer
* @param bufferStart the first active index in the buffer, valid for buffer
* @param bufferEnd the end index of the active buffer, valid for buffer
* @return the number of matching characters, zero for no match
*/
public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) {
return Arrays.binarySearch(chars, buffer[pos]) >= 0 ? 1 : 0;
}
}
//-----------------------------------------------------------------------
/**
* Class used to define a character for matching purposes.
*/
static final class CharMatcher extends StrMatcher {
/** The character to match. */
private final char ch;
/**
* Constructor that creates a matcher that matches a single character.
*
* @param ch the character to match
*/
CharMatcher(char ch) {
super();
this.ch = ch;
}
/**
* Returns whether or not the given character matches.
*
* @param buffer the text content to match against, do not change
* @param pos the starting position for the match, valid for buffer
* @param bufferStart the first active index in the buffer, valid for buffer
* @param bufferEnd the end index of the active buffer, valid for buffer
* @return the number of matching characters, zero for no match
*/
public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) {
return ch == buffer[pos] ? 1 : 0;
}
}
//-----------------------------------------------------------------------
/**
* Class used to define a set of characters for matching purposes.
*/
static final class StringMatcher extends StrMatcher {
/** The string to match, as a character array. */
private final char[] chars;
/**
* Constructor that creates a matcher from a String.
*
* @param str the string to match, must not be null
*/
StringMatcher(String str) {
super();
chars = str.toCharArray();
}
/**
* Returns whether or not the given text matches the stored string.
*
* @param buffer the text content to match against, do not change
* @param pos the starting position for the match, valid for buffer
* @param bufferStart the first active index in the buffer, valid for buffer
* @param bufferEnd the end index of the active buffer, valid for buffer
* @return the number of matching characters, zero for no match
*/
public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) {
int len = chars.length;
if (pos + len > bufferEnd) {
return 0;
}
for (int i = 0; i < chars.length; i++, pos++) {
if (chars[i] != buffer[pos]) {
return 0;
}
}
return len;
}
}
//-----------------------------------------------------------------------
/**
* Class used to match no characters.
*/
static final class NoMatcher extends StrMatcher {
/**
* Constructs a new instance of NoMatcher
.
*/
NoMatcher() {
super();
}
/**
* Always returns false
.
*
* @param buffer the text content to match against, do not change
* @param pos the starting position for the match, valid for buffer
* @param bufferStart the first active index in the buffer, valid for buffer
* @param bufferEnd the end index of the active buffer, valid for buffer
* @return the number of matching characters, zero for no match
*/
public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) {
return 0;
}
}
//-----------------------------------------------------------------------
/**
* Class used to match whitespace as per trim().
*/
static final class TrimMatcher extends StrMatcher {
/**
* Constructs a new instance of TrimMatcher
.
*/
TrimMatcher() {
super();
}
/**
* Returns whether or not the given character matches.
*
* @param buffer the text content to match against, do not change
* @param pos the starting position for the match, valid for buffer
* @param bufferStart the first active index in the buffer, valid for buffer
* @param bufferEnd the end index of the active buffer, valid for buffer
* @return the number of matching characters, zero for no match
*/
public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) {
return buffer[pos] <= 32 ? 1 : 0;
}
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/text/StrSubstitutor.java 100644 0 0 113024 11513702441 25655 0 ustar 0 0 /*
* 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.lang.text;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* Substitutes variables within a string by values.
*
* This class takes a piece of text and substitutes all the variables within it.
* The default definition of a variable is ${variableName}
.
* The prefix and suffix can be changed via constructors and set methods.
*
* Variable values are typically resolved from a map, but could also be resolved
* from system properties, or by supplying a custom variable resolver.
*
* The simplest example is to use this class to replace Java System properties. For example:
*
* StrSubstitutor.replaceSystemProperties(
* "You are running with java.version = ${java.version} and os.name = ${os.name}.");
*
*
* Typical usage of this class follows the following pattern: First an instance is created
* and initialized with the map that contains the values for the available variables.
* If a prefix and/or suffix for variables should be used other than the default ones,
* the appropriate settings can be performed. After that the replace()
* method can be called passing in the source text for interpolation. In the returned
* text all variable references (as long as their values are known) will be resolved.
* The following example demonstrates this:
*
* Map valuesMap = HashMap();
* valuesMap.put("animal", "quick brown fox");
* valuesMap.put("target", "lazy dog");
* String templateString = "The ${animal} jumped over the ${target}.";
* StrSubstitutor sub = new StrSubstitutor(valuesMap);
* String resolvedString = sub.replace(templateString);
*
* yielding:
*
* The quick brown fox jumped over the lazy dog.
*
*
* In addition to this usage pattern there are some static convenience methods that
* cover the most common use cases. These methods can be used without the need of
* manually creating an instance. However if multiple replace operations are to be
* performed, creating and reusing an instance of this class will be more efficient.
*
* Variable replacement works in a recursive way. Thus, if a variable value contains
* a variable then that variable will also be replaced. Cyclic replacements are
* detected and will cause an exception to be thrown.
*
* Sometimes the interpolation's result must contain a variable prefix. As an example
* take the following source text:
*
* The variable ${${name}} must be used.
*
* Here only the variable's name referred to in the text should be replaced resulting
* in the text (assuming that the value of the name
variable is x
):
*
* The variable ${x} must be used.
*
* To achieve this effect there are two possibilities: Either set a different prefix
* and suffix for variables which do not conflict with the result text you want to
* produce. The other possibility is to use the escape character, by default '$'.
* If this character is placed before a variable reference, this reference is ignored
* and won't be replaced. For example:
*
* The variable $${${name}} must be used.
*
*
* In some complex scenarios you might even want to perform substitution in the
* names of variables, for instance
*
* ${jre-${java.specification.version}}
*
* StrSubstitutor
supports this recursive substitution in variable
* names, but it has to be enabled explicitly by setting the
* {@link #setEnableSubstitutionInVariables(boolean) enableSubstitutionInVariables}
* property to true.
*
* @author Apache Software Foundation
* @author Oliver Heger
* @version $Id: StrSubstitutor.java 1057354 2011-01-10 20:48:47Z niallp $
* @since 2.2
*/
public class StrSubstitutor {
/**
* Constant for the default escape character.
*/
public static final char DEFAULT_ESCAPE = '$';
/**
* Constant for the default variable prefix.
*/
public static final StrMatcher DEFAULT_PREFIX = StrMatcher.stringMatcher("${");
/**
* Constant for the default variable suffix.
*/
public static final StrMatcher DEFAULT_SUFFIX = StrMatcher.stringMatcher("}");
/**
* Stores the escape character.
*/
private char escapeChar;
/**
* Stores the variable prefix.
*/
private StrMatcher prefixMatcher;
/**
* Stores the variable suffix.
*/
private StrMatcher suffixMatcher;
/**
* Variable resolution is delegated to an implementor of VariableResolver.
*/
private StrLookup variableResolver;
/**
* The flag whether substitution in variable names is enabled.
*/
private boolean enableSubstitutionInVariables;
//-----------------------------------------------------------------------
/**
* Replaces all the occurrences of variables in the given source object with
* their matching values from the map.
*
* @param source the source text containing the variables to substitute, null returns null
* @param valueMap the map with the values, may be null
* @return the result of the replace operation
*/
public static String replace(Object source, Map valueMap) {
return new StrSubstitutor(valueMap).replace(source);
}
/**
* Replaces all the occurrences of variables in the given source object with
* their matching values from the map. This method allows to specifiy a
* custom variable prefix and suffix
*
* @param source the source text containing the variables to substitute, null returns null
* @param valueMap the map with the values, may be null
* @param prefix the prefix of variables, not null
* @param suffix the suffix of variables, not null
* @return the result of the replace operation
* @throws IllegalArgumentException if the prefix or suffix is null
*/
public static String replace(Object source, Map valueMap, String prefix, String suffix) {
return new StrSubstitutor(valueMap, prefix, suffix).replace(source);
}
/**
* Replaces all the occurrences of variables in the given source object with their matching
* values from the properties.
*
* @param source the source text containing the variables to substitute, null returns null
* @param valueProperties the properties with values, may be null
* @return the result of the replace operation
* @since 2.6
*/
public static String replace(Object source, Properties valueProperties)
{
if (valueProperties == null) {
return source.toString();
}
Map valueMap = new HashMap();
Enumeration propNames = valueProperties.propertyNames();
while (propNames.hasMoreElements())
{
String propName = (String)propNames.nextElement();
String propValue = valueProperties.getProperty(propName);
valueMap.put(propName, propValue);
}
return StrSubstitutor.replace(source, valueMap);
}
/**
* Replaces all the occurrences of variables in the given source object with
* their matching values from the system properties.
*
* @param source the source text containing the variables to substitute, null returns null
* @return the result of the replace operation
*/
public static String replaceSystemProperties(Object source) {
return new StrSubstitutor(StrLookup.systemPropertiesLookup()).replace(source);
}
//-----------------------------------------------------------------------
/**
* Creates a new instance with defaults for variable prefix and suffix
* and the escaping character.
*/
public StrSubstitutor() {
this((StrLookup) null, DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE);
}
/**
* Creates a new instance and initializes it. Uses defaults for variable
* prefix and suffix and the escaping character.
*
* @param valueMap the map with the variables' values, may be null
*/
public StrSubstitutor(Map valueMap) {
this(StrLookup.mapLookup(valueMap), DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE);
}
/**
* Creates a new instance and initializes it. Uses a default escaping character.
*
* @param valueMap the map with the variables' values, may be null
* @param prefix the prefix for variables, not null
* @param suffix the suffix for variables, not null
* @throws IllegalArgumentException if the prefix or suffix is null
*/
public StrSubstitutor(Map valueMap, String prefix, String suffix) {
this(StrLookup.mapLookup(valueMap), prefix, suffix, DEFAULT_ESCAPE);
}
/**
* Creates a new instance and initializes it.
*
* @param valueMap the map with the variables' values, may be null
* @param prefix the prefix for variables, not null
* @param suffix the suffix for variables, not null
* @param escape the escape character
* @throws IllegalArgumentException if the prefix or suffix is null
*/
public StrSubstitutor(Map valueMap, String prefix, String suffix, char escape) {
this(StrLookup.mapLookup(valueMap), prefix, suffix, escape);
}
/**
* Creates a new instance and initializes it.
*
* @param variableResolver the variable resolver, may be null
*/
public StrSubstitutor(StrLookup variableResolver) {
this(variableResolver, DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE);
}
/**
* Creates a new instance and initializes it.
*
* @param variableResolver the variable resolver, may be null
* @param prefix the prefix for variables, not null
* @param suffix the suffix for variables, not null
* @param escape the escape character
* @throws IllegalArgumentException if the prefix or suffix is null
*/
public StrSubstitutor(StrLookup variableResolver, String prefix, String suffix, char escape) {
this.setVariableResolver(variableResolver);
this.setVariablePrefix(prefix);
this.setVariableSuffix(suffix);
this.setEscapeChar(escape);
}
/**
* Creates a new instance and initializes it.
*
* @param variableResolver the variable resolver, may be null
* @param prefixMatcher the prefix for variables, not null
* @param suffixMatcher the suffix for variables, not null
* @param escape the escape character
* @throws IllegalArgumentException if the prefix or suffix is null
*/
public StrSubstitutor(
StrLookup variableResolver, StrMatcher prefixMatcher, StrMatcher suffixMatcher, char escape) {
this.setVariableResolver(variableResolver);
this.setVariablePrefixMatcher(prefixMatcher);
this.setVariableSuffixMatcher(suffixMatcher);
this.setEscapeChar(escape);
}
//-----------------------------------------------------------------------
/**
* Replaces all the occurrences of variables with their matching values
* from the resolver using the given source string as a template.
*
* @param source the string to replace in, null returns null
* @return the result of the replace operation
*/
public String replace(String source) {
if (source == null) {
return null;
}
StrBuilder buf = new StrBuilder(source);
if (substitute(buf, 0, source.length()) == false) {
return source;
}
return buf.toString();
}
/**
* Replaces all the occurrences of variables with their matching values
* from the resolver using the given source string as a template.
*
* Only the specified portion of the string will be processed.
* The rest of the string is not processed, and is not returned.
*
* @param source the string to replace in, null returns null
* @param offset the start offset within the array, must be valid
* @param length the length within the array to be processed, must be valid
* @return the result of the replace operation
*/
public String replace(String source, int offset, int length) {
if (source == null) {
return null;
}
StrBuilder buf = new StrBuilder(length).append(source, offset, length);
if (substitute(buf, 0, length) == false) {
return source.substring(offset, offset + length);
}
return buf.toString();
}
//-----------------------------------------------------------------------
/**
* Replaces all the occurrences of variables with their matching values
* from the resolver using the given source array as a template.
* The array is not altered by this method.
*
* @param source the character array to replace in, not altered, null returns null
* @return the result of the replace operation
*/
public String replace(char[] source) {
if (source == null) {
return null;
}
StrBuilder buf = new StrBuilder(source.length).append(source);
substitute(buf, 0, source.length);
return buf.toString();
}
/**
* Replaces all the occurrences of variables with their matching values
* from the resolver using the given source array as a template.
* The array is not altered by this method.
*
* Only the specified portion of the array will be processed.
* The rest of the array is not processed, and is not returned.
*
* @param source the character array to replace in, not altered, null returns null
* @param offset the start offset within the array, must be valid
* @param length the length within the array to be processed, must be valid
* @return the result of the replace operation
*/
public String replace(char[] source, int offset, int length) {
if (source == null) {
return null;
}
StrBuilder buf = new StrBuilder(length).append(source, offset, length);
substitute(buf, 0, length);
return buf.toString();
}
//-----------------------------------------------------------------------
/**
* Replaces all the occurrences of variables with their matching values
* from the resolver using the given source buffer as a template.
* The buffer is not altered by this method.
*
* @param source the buffer to use as a template, not changed, null returns null
* @return the result of the replace operation
*/
public String replace(StringBuffer source) {
if (source == null) {
return null;
}
StrBuilder buf = new StrBuilder(source.length()).append(source);
substitute(buf, 0, buf.length());
return buf.toString();
}
/**
* Replaces all the occurrences of variables with their matching values
* from the resolver using the given source buffer as a template.
* The buffer is not altered by this method.
*
* Only the specified portion of the buffer will be processed.
* The rest of the buffer is not processed, and is not returned.
*
* @param source the buffer to use as a template, not changed, null returns null
* @param offset the start offset within the array, must be valid
* @param length the length within the array to be processed, must be valid
* @return the result of the replace operation
*/
public String replace(StringBuffer source, int offset, int length) {
if (source == null) {
return null;
}
StrBuilder buf = new StrBuilder(length).append(source, offset, length);
substitute(buf, 0, length);
return buf.toString();
}
//-----------------------------------------------------------------------
/**
* Replaces all the occurrences of variables with their matching values
* from the resolver using the given source builder as a template.
* The builder is not altered by this method.
*
* @param source the builder to use as a template, not changed, null returns null
* @return the result of the replace operation
*/
public String replace(StrBuilder source) {
if (source == null) {
return null;
}
StrBuilder buf = new StrBuilder(source.length()).append(source);
substitute(buf, 0, buf.length());
return buf.toString();
}
/**
* Replaces all the occurrences of variables with their matching values
* from the resolver using the given source builder as a template.
* The builder is not altered by this method.
*
* Only the specified portion of the builder will be processed.
* The rest of the builder is not processed, and is not returned.
*
* @param source the builder to use as a template, not changed, null returns null
* @param offset the start offset within the array, must be valid
* @param length the length within the array to be processed, must be valid
* @return the result of the replace operation
*/
public String replace(StrBuilder source, int offset, int length) {
if (source == null) {
return null;
}
StrBuilder buf = new StrBuilder(length).append(source, offset, length);
substitute(buf, 0, length);
return buf.toString();
}
//-----------------------------------------------------------------------
/**
* Replaces all the occurrences of variables in the given source object with
* their matching values from the resolver. The input source object is
* converted to a string using toString
and is not altered.
*
* @param source the source to replace in, null returns null
* @return the result of the replace operation
*/
public String replace(Object source) {
if (source == null) {
return null;
}
StrBuilder buf = new StrBuilder().append(source);
substitute(buf, 0, buf.length());
return buf.toString();
}
//-----------------------------------------------------------------------
/**
* Replaces all the occurrences of variables within the given source buffer
* with their matching values from the resolver.
* The buffer is updated with the result.
*
* @param source the buffer to replace in, updated, null returns zero
* @return true if altered
*/
public boolean replaceIn(StringBuffer source) {
if (source == null) {
return false;
}
return replaceIn(source, 0, source.length());
}
/**
* Replaces all the occurrences of variables within the given source buffer
* with their matching values from the resolver.
* The buffer is updated with the result.
*
* Only the specified portion of the buffer will be processed.
* The rest of the buffer is not processed, but it is not deleted.
*
* @param source the buffer to replace in, updated, null returns zero
* @param offset the start offset within the array, must be valid
* @param length the length within the buffer to be processed, must be valid
* @return true if altered
*/
public boolean replaceIn(StringBuffer source, int offset, int length) {
if (source == null) {
return false;
}
StrBuilder buf = new StrBuilder(length).append(source, offset, length);
if (substitute(buf, 0, length) == false) {
return false;
}
source.replace(offset, offset + length, buf.toString());
return true;
}
//-----------------------------------------------------------------------
/**
* Replaces all the occurrences of variables within the given source
* builder with their matching values from the resolver.
*
* @param source the builder to replace in, updated, null returns zero
* @return true if altered
*/
public boolean replaceIn(StrBuilder source) {
if (source == null) {
return false;
}
return substitute(source, 0, source.length());
}
/**
* Replaces all the occurrences of variables within the given source
* builder with their matching values from the resolver.
*
* Only the specified portion of the builder will be processed.
* The rest of the builder is not processed, but it is not deleted.
*
* @param source the builder to replace in, null returns zero
* @param offset the start offset within the array, must be valid
* @param length the length within the builder to be processed, must be valid
* @return true if altered
*/
public boolean replaceIn(StrBuilder source, int offset, int length) {
if (source == null) {
return false;
}
return substitute(source, offset, length);
}
//-----------------------------------------------------------------------
/**
* Internal method that substitutes the variables.
*
* Most users of this class do not need to call this method. This method will
* be called automatically by another (public) method.
*
* Writers of subclasses can override this method if they need access to
* the substitution process at the start or end.
*
* @param buf the string builder to substitute into, not null
* @param offset the start offset within the builder, must be valid
* @param length the length within the builder to be processed, must be valid
* @return true if altered
*/
protected boolean substitute(StrBuilder buf, int offset, int length) {
return substitute(buf, offset, length, null) > 0;
}
/**
* Recursive handler for multiple levels of interpolation. This is the main
* interpolation method, which resolves the values of all variable references
* contained in the passed in text.
*
* @param buf the string builder to substitute into, not null
* @param offset the start offset within the builder, must be valid
* @param length the length within the builder to be processed, must be valid
* @param priorVariables the stack keeping track of the replaced variables, may be null
* @return the length change that occurs, unless priorVariables is null when the int
* represents a boolean flag as to whether any change occurred.
*/
private int substitute(StrBuilder buf, int offset, int length, List priorVariables) {
StrMatcher prefixMatcher = getVariablePrefixMatcher();
StrMatcher suffixMatcher = getVariableSuffixMatcher();
char escape = getEscapeChar();
boolean top = (priorVariables == null);
boolean altered = false;
int lengthChange = 0;
char[] chars = buf.buffer;
int bufEnd = offset + length;
int pos = offset;
while (pos < bufEnd) {
int startMatchLen = prefixMatcher.isMatch(chars, pos, offset,
bufEnd);
if (startMatchLen == 0) {
pos++;
} else {
// found variable start marker
if (pos > offset && chars[pos - 1] == escape) {
// escaped
buf.deleteCharAt(pos - 1);
chars = buf.buffer; // in case buffer was altered
lengthChange--;
altered = true;
bufEnd--;
} else {
// find suffix
int startPos = pos;
pos += startMatchLen;
int endMatchLen = 0;
int nestedVarCount = 0;
while (pos < bufEnd) {
if (isEnableSubstitutionInVariables()
&& (endMatchLen = prefixMatcher.isMatch(chars,
pos, offset, bufEnd)) != 0) {
// found a nested variable start
nestedVarCount++;
pos += endMatchLen;
continue;
}
endMatchLen = suffixMatcher.isMatch(chars, pos, offset,
bufEnd);
if (endMatchLen == 0) {
pos++;
} else {
// found variable end marker
if (nestedVarCount == 0) {
String varName = new String(chars, startPos
+ startMatchLen, pos - startPos
- startMatchLen);
if (isEnableSubstitutionInVariables()) {
StrBuilder bufName = new StrBuilder(varName);
substitute(bufName, 0, bufName.length());
varName = bufName.toString();
}
pos += endMatchLen;
int endPos = pos;
// on the first call initialize priorVariables
if (priorVariables == null) {
priorVariables = new ArrayList();
priorVariables.add(new String(chars,
offset, length));
}
// handle cyclic substitution
checkCyclicSubstitution(varName, priorVariables);
priorVariables.add(varName);
// resolve the variable
String varValue = resolveVariable(varName, buf,
startPos, endPos);
if (varValue != null) {
// recursive replace
int varLen = varValue.length();
buf.replace(startPos, endPos, varValue);
altered = true;
int change = substitute(buf, startPos,
varLen, priorVariables);
change = change
+ (varLen - (endPos - startPos));
pos += change;
bufEnd += change;
lengthChange += change;
chars = buf.buffer; // in case buffer was
// altered
}
// remove variable from the cyclic stack
priorVariables
.remove(priorVariables.size() - 1);
break;
} else {
nestedVarCount--;
pos += endMatchLen;
}
}
}
}
}
}
if (top) {
return (altered ? 1 : 0);
}
return lengthChange;
}
/**
* Checks if the specified variable is already in the stack (list) of variables.
*
* @param varName the variable name to check
* @param priorVariables the list of prior variables
*/
private void checkCyclicSubstitution(String varName, List priorVariables) {
if (priorVariables.contains(varName) == false) {
return;
}
StrBuilder buf = new StrBuilder(256);
buf.append("Infinite loop in property interpolation of ");
buf.append(priorVariables.remove(0));
buf.append(": ");
buf.appendWithSeparators(priorVariables, "->");
throw new IllegalStateException(buf.toString());
}
/**
* Internal method that resolves the value of a variable.
*
* Most users of this class do not need to call this method. This method is
* called automatically by the substitution process.
*
* Writers of subclasses can override this method if they need to alter
* how each substitution occurs. The method is passed the variable's name
* and must return the corresponding value. This implementation uses the
* {@link #getVariableResolver()} with the variable's name as the key.
*
* @param variableName the name of the variable, not null
* @param buf the buffer where the substitution is occurring, not null
* @param startPos the start position of the variable including the prefix, valid
* @param endPos the end position of the variable including the suffix, valid
* @return the variable's value or null if the variable is unknown
*/
protected String resolveVariable(String variableName, StrBuilder buf, int startPos, int endPos) {
StrLookup resolver = getVariableResolver();
if (resolver == null) {
return null;
}
return resolver.lookup(variableName);
}
// Escape
//-----------------------------------------------------------------------
/**
* Returns the escape character.
*
* @return the character used for escaping variable references
*/
public char getEscapeChar() {
return this.escapeChar;
}
/**
* Sets the escape character.
* If this character is placed before a variable reference in the source
* text, this variable will be ignored.
*
* @param escapeCharacter the escape character (0 for disabling escaping)
*/
public void setEscapeChar(char escapeCharacter) {
this.escapeChar = escapeCharacter;
}
// Prefix
//-----------------------------------------------------------------------
/**
* Gets the variable prefix matcher currently in use.
*
* The variable prefix is the characer or characters that identify the
* start of a variable. This prefix is expressed in terms of a matcher
* allowing advanced prefix matches.
*
* @return the prefix matcher in use
*/
public StrMatcher getVariablePrefixMatcher() {
return prefixMatcher;
}
/**
* Sets the variable prefix matcher currently in use.
*
* The variable prefix is the characer or characters that identify the
* start of a variable. This prefix is expressed in terms of a matcher
* allowing advanced prefix matches.
*
* @param prefixMatcher the prefix matcher to use, null ignored
* @return this, to enable chaining
* @throws IllegalArgumentException if the prefix matcher is null
*/
public StrSubstitutor setVariablePrefixMatcher(StrMatcher prefixMatcher) {
if (prefixMatcher == null) {
throw new IllegalArgumentException("Variable prefix matcher must not be null!");
}
this.prefixMatcher = prefixMatcher;
return this;
}
/**
* Sets the variable prefix to use.
*
* The variable prefix is the character or characters that identify the
* start of a variable. This method allows a single character prefix to
* be easily set.
*
* @param prefix the prefix character to use
* @return this, to enable chaining
*/
public StrSubstitutor setVariablePrefix(char prefix) {
return setVariablePrefixMatcher(StrMatcher.charMatcher(prefix));
}
/**
* Sets the variable prefix to use.
*
* The variable prefix is the characer or characters that identify the
* start of a variable. This method allows a string prefix to be easily set.
*
* @param prefix the prefix for variables, not null
* @return this, to enable chaining
* @throws IllegalArgumentException if the prefix is null
*/
public StrSubstitutor setVariablePrefix(String prefix) {
if (prefix == null) {
throw new IllegalArgumentException("Variable prefix must not be null!");
}
return setVariablePrefixMatcher(StrMatcher.stringMatcher(prefix));
}
// Suffix
//-----------------------------------------------------------------------
/**
* Gets the variable suffix matcher currently in use.
*
* The variable suffix is the characer or characters that identify the
* end of a variable. This suffix is expressed in terms of a matcher
* allowing advanced suffix matches.
*
* @return the suffix matcher in use
*/
public StrMatcher getVariableSuffixMatcher() {
return suffixMatcher;
}
/**
* Sets the variable suffix matcher currently in use.
*
* The variable suffix is the characer or characters that identify the
* end of a variable. This suffix is expressed in terms of a matcher
* allowing advanced suffix matches.
*
* @param suffixMatcher the suffix matcher to use, null ignored
* @return this, to enable chaining
* @throws IllegalArgumentException if the suffix matcher is null
*/
public StrSubstitutor setVariableSuffixMatcher(StrMatcher suffixMatcher) {
if (suffixMatcher == null) {
throw new IllegalArgumentException("Variable suffix matcher must not be null!");
}
this.suffixMatcher = suffixMatcher;
return this;
}
/**
* Sets the variable suffix to use.
*
* The variable suffix is the characer or characters that identify the
* end of a variable. This method allows a single character suffix to
* be easily set.
*
* @param suffix the suffix character to use
* @return this, to enable chaining
*/
public StrSubstitutor setVariableSuffix(char suffix) {
return setVariableSuffixMatcher(StrMatcher.charMatcher(suffix));
}
/**
* Sets the variable suffix to use.
*
* The variable suffix is the character or characters that identify the
* end of a variable. This method allows a string suffix to be easily set.
*
* @param suffix the suffix for variables, not null
* @return this, to enable chaining
* @throws IllegalArgumentException if the suffix is null
*/
public StrSubstitutor setVariableSuffix(String suffix) {
if (suffix == null) {
throw new IllegalArgumentException("Variable suffix must not be null!");
}
return setVariableSuffixMatcher(StrMatcher.stringMatcher(suffix));
}
// Resolver
//-----------------------------------------------------------------------
/**
* Gets the VariableResolver that is used to lookup variables.
*
* @return the VariableResolver
*/
public StrLookup getVariableResolver() {
return this.variableResolver;
}
/**
* Sets the VariableResolver that is used to lookup variables.
*
* @param variableResolver the VariableResolver
*/
public void setVariableResolver(StrLookup variableResolver) {
this.variableResolver = variableResolver;
}
// Substitution support in variable names
//-----------------------------------------------------------------------
/**
* Returns a flag whether substitution is done in variable names.
*
* @return the substitution in variable names flag
* @since 2.6
*/
public boolean isEnableSubstitutionInVariables() {
return enableSubstitutionInVariables;
}
/**
* Sets a flag whether substitution is done in variable names. If set to
* true, the names of variables can contain other variables which are
* processed first before the original variable is evaluated, e.g.
* ${jre-${java.version}}
. The default value is false.
*
* @param enableSubstitutionInVariables the new value of the flag
* @since 2.6
*/
public void setEnableSubstitutionInVariables(
boolean enableSubstitutionInVariables) {
this.enableSubstitutionInVariables = enableSubstitutionInVariables;
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/text/StrTokenizer.java 100644 0 0 115051 11513702441 25262 0 ustar 0 0 /*
* 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.lang.text;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
/**
* Tokenizes a string based based on delimiters (separators)
* and supporting quoting and ignored character concepts.
*
* This class can split a String into many smaller strings. It aims
* to do a similar job to {@link java.util.StringTokenizer StringTokenizer},
* however it offers much more control and flexibility including implementing
* the ListIterator
interface. By default, it is set up
* like StringTokenizer
.
*
* The input String is split into a number of tokens.
* Each token is separated from the next String by a delimiter.
* One or more delimiter characters must be specified.
*
* Each token may be surrounded by quotes.
* The quote matcher specifies the quote character(s).
* A quote may be escaped within a quoted section by duplicating itself.
*
* Between each token and the delimiter are potentially characters that need trimming.
* The trimmer matcher specifies these characters.
* One usage might be to trim whitespace characters.
*
* At any point outside the quotes there might potentially be invalid characters.
* The ignored matcher specifies these characters to be removed.
* One usage might be to remove new line characters.
*
* Empty tokens may be removed or returned as null.
*
* "a,b,c" - Three tokens "a","b","c" (comma delimiter)
* " a, b , c " - Three tokens "a","b","c" (default CSV processing trims whitespace)
* "a, ", b ,", c" - Three tokens "a, " , " b ", ", c" (quoted text untouched)
*
*
*
* This tokenizer has the following properties and options:
*
*
*
* Property Type Default
*
*
* delim CharSetMatcher { \t\n\r\f}
*
*
* quote NoneMatcher {}
*
*
* ignore NoneMatcher {}
*
*
* emptyTokenAsNull boolean false
*
*
* ignoreEmptyTokens boolean true
*
*
*
* @author Apache Software Foundation
* @author Matthew Inger
* @author Gary D. Gregory
* @since 2.2
* @version $Id: StrTokenizer.java 907631 2010-02-08 12:22:48Z sebb $
*/
public class StrTokenizer implements ListIterator, Cloneable {
private static final StrTokenizer CSV_TOKENIZER_PROTOTYPE;
private static final StrTokenizer TSV_TOKENIZER_PROTOTYPE;
static {
CSV_TOKENIZER_PROTOTYPE = new StrTokenizer();
CSV_TOKENIZER_PROTOTYPE.setDelimiterMatcher(StrMatcher.commaMatcher());
CSV_TOKENIZER_PROTOTYPE.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
CSV_TOKENIZER_PROTOTYPE.setIgnoredMatcher(StrMatcher.noneMatcher());
CSV_TOKENIZER_PROTOTYPE.setTrimmerMatcher(StrMatcher.trimMatcher());
CSV_TOKENIZER_PROTOTYPE.setEmptyTokenAsNull(false);
CSV_TOKENIZER_PROTOTYPE.setIgnoreEmptyTokens(false);
TSV_TOKENIZER_PROTOTYPE = new StrTokenizer();
TSV_TOKENIZER_PROTOTYPE.setDelimiterMatcher(StrMatcher.tabMatcher());
TSV_TOKENIZER_PROTOTYPE.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
TSV_TOKENIZER_PROTOTYPE.setIgnoredMatcher(StrMatcher.noneMatcher());
TSV_TOKENIZER_PROTOTYPE.setTrimmerMatcher(StrMatcher.trimMatcher());
TSV_TOKENIZER_PROTOTYPE.setEmptyTokenAsNull(false);
TSV_TOKENIZER_PROTOTYPE.setIgnoreEmptyTokens(false);
}
/** The text to work on. */
private char chars[];
/** The parsed tokens */
private String tokens[];
/** The current iteration position */
private int tokenPos;
/** The delimiter matcher */
private StrMatcher delimMatcher = StrMatcher.splitMatcher();
/** The quote matcher */
private StrMatcher quoteMatcher = StrMatcher.noneMatcher();
/** The ignored matcher */
private StrMatcher ignoredMatcher = StrMatcher.noneMatcher();
/** The trimmer matcher */
private StrMatcher trimmerMatcher = StrMatcher.noneMatcher();
/** Whether to return empty tokens as null */
private boolean emptyAsNull = false;
/** Whether to ignore empty tokens */
private boolean ignoreEmptyTokens = true;
//-----------------------------------------------------------------------
/**
* Returns a clone of CSV_TOKENIZER_PROTOTYPE
.
*
* @return a clone of CSV_TOKENIZER_PROTOTYPE
.
*/
private static StrTokenizer getCSVClone() {
return (StrTokenizer) CSV_TOKENIZER_PROTOTYPE.clone();
}
/**
* Gets a new tokenizer instance which parses Comma Separated Value strings
* initializing it with the given input. The default for CSV processing
* will be trim whitespace from both ends (which can be overridden with
* the setTrimmer method).
*
* You must call a "reset" method to set the string which you want to parse.
* @return a new tokenizer instance which parses Comma Separated Value strings
*/
public static StrTokenizer getCSVInstance() {
return getCSVClone();
}
/**
* Gets a new tokenizer instance which parses Comma Separated Value strings
* initializing it with the given input. The default for CSV processing
* will be trim whitespace from both ends (which can be overridden with
* the setTrimmer method).
*
* @param input the text to parse
* @return a new tokenizer instance which parses Comma Separated Value strings
*/
public static StrTokenizer getCSVInstance(String input) {
StrTokenizer tok = getCSVClone();
tok.reset(input);
return tok;
}
/**
* Gets a new tokenizer instance which parses Comma Separated Value strings
* initializing it with the given input. The default for CSV processing
* will be trim whitespace from both ends (which can be overridden with
* the setTrimmer method).
*
* @param input the text to parse
* @return a new tokenizer instance which parses Comma Separated Value strings
*/
public static StrTokenizer getCSVInstance(char[] input) {
StrTokenizer tok = getCSVClone();
tok.reset(input);
return tok;
}
/**
* Returns a clone of TSV_TOKENIZER_PROTOTYPE
.
*
* @return a clone of TSV_TOKENIZER_PROTOTYPE
.
*/
private static StrTokenizer getTSVClone() {
return (StrTokenizer) TSV_TOKENIZER_PROTOTYPE.clone();
}
/**
* Gets a new tokenizer instance which parses Tab Separated Value strings.
* The default for CSV processing will be trim whitespace from both ends
* (which can be overridden with the setTrimmer method).
*
* You must call a "reset" method to set the string which you want to parse.
* @return a new tokenizer instance which parses Tab Separated Value strings.
*/
public static StrTokenizer getTSVInstance() {
return getTSVClone();
}
/**
* Gets a new tokenizer instance which parses Tab Separated Value strings.
* The default for CSV processing will be trim whitespace from both ends
* (which can be overridden with the setTrimmer method).
* @param input the string to parse
* @return a new tokenizer instance which parses Tab Separated Value strings.
*/
public static StrTokenizer getTSVInstance(String input) {
StrTokenizer tok = getTSVClone();
tok.reset(input);
return tok;
}
/**
* Gets a new tokenizer instance which parses Tab Separated Value strings.
* The default for CSV processing will be trim whitespace from both ends
* (which can be overridden with the setTrimmer method).
* @param input the string to parse
* @return a new tokenizer instance which parses Tab Separated Value strings.
*/
public static StrTokenizer getTSVInstance(char[] input) {
StrTokenizer tok = getTSVClone();
tok.reset(input);
return tok;
}
//-----------------------------------------------------------------------
/**
* Constructs a tokenizer splitting on space, tab, newline and formfeed
* as per StringTokenizer, but with no text to tokenize.
*
* This constructor is normally used with {@link #reset(String)}.
*/
public StrTokenizer() {
super();
this.chars = null;
}
/**
* Constructs a tokenizer splitting on space, tab, newline and formfeed
* as per StringTokenizer.
*
* @param input the string which is to be parsed
*/
public StrTokenizer(String input) {
super();
if (input != null) {
chars = input.toCharArray();
} else {
chars = null;
}
}
/**
* Constructs a tokenizer splitting on the specified delimiter character.
*
* @param input the string which is to be parsed
* @param delim the field delimiter character
*/
public StrTokenizer(String input, char delim) {
this(input);
setDelimiterChar(delim);
}
/**
* Constructs a tokenizer splitting on the specified delimiter string.
*
* @param input the string which is to be parsed
* @param delim the field delimiter string
*/
public StrTokenizer(String input, String delim) {
this(input);
setDelimiterString(delim);
}
/**
* Constructs a tokenizer splitting using the specified delimiter matcher.
*
* @param input the string which is to be parsed
* @param delim the field delimiter matcher
*/
public StrTokenizer(String input, StrMatcher delim) {
this(input);
setDelimiterMatcher(delim);
}
/**
* Constructs a tokenizer splitting on the specified delimiter character
* and handling quotes using the specified quote character.
*
* @param input the string which is to be parsed
* @param delim the field delimiter character
* @param quote the field quoted string character
*/
public StrTokenizer(String input, char delim, char quote) {
this(input, delim);
setQuoteChar(quote);
}
/**
* Constructs a tokenizer splitting using the specified delimiter matcher
* and handling quotes using the specified quote matcher.
*
* @param input the string which is to be parsed
* @param delim the field delimiter matcher
* @param quote the field quoted string matcher
*/
public StrTokenizer(String input, StrMatcher delim, StrMatcher quote) {
this(input, delim);
setQuoteMatcher(quote);
}
/**
* Constructs a tokenizer splitting on space, tab, newline and formfeed
* as per StringTokenizer.
*
* The input character array is not cloned, and must not be altered after
* passing in to this method.
*
* @param input the string which is to be parsed, not cloned
*/
public StrTokenizer(char[] input) {
super();
this.chars = input;
}
/**
* Constructs a tokenizer splitting on the specified character.
*
* The input character array is not cloned, and must not be altered after
* passing in to this method.
*
* @param input the string which is to be parsed, not cloned
* @param delim the field delimiter character
*/
public StrTokenizer(char[] input, char delim) {
this(input);
setDelimiterChar(delim);
}
/**
* Constructs a tokenizer splitting on the specified string.
*
* The input character array is not cloned, and must not be altered after
* passing in to this method.
*
* @param input the string which is to be parsed, not cloned
* @param delim the field delimiter string
*/
public StrTokenizer(char[] input, String delim) {
this(input);
setDelimiterString(delim);
}
/**
* Constructs a tokenizer splitting using the specified delimiter matcher.
*
* The input character array is not cloned, and must not be altered after
* passing in to this method.
*
* @param input the string which is to be parsed, not cloned
* @param delim the field delimiter matcher
*/
public StrTokenizer(char[] input, StrMatcher delim) {
this(input);
setDelimiterMatcher(delim);
}
/**
* Constructs a tokenizer splitting on the specified delimiter character
* and handling quotes using the specified quote character.
*
* The input character array is not cloned, and must not be altered after
* passing in to this method.
*
* @param input the string which is to be parsed, not cloned
* @param delim the field delimiter character
* @param quote the field quoted string character
*/
public StrTokenizer(char[] input, char delim, char quote) {
this(input, delim);
setQuoteChar(quote);
}
/**
* Constructs a tokenizer splitting using the specified delimiter matcher
* and handling quotes using the specified quote matcher.
*
* The input character array is not cloned, and must not be altered after
* passing in to this method.
*
* @param input the string which is to be parsed, not cloned
* @param delim the field delimiter character
* @param quote the field quoted string character
*/
public StrTokenizer(char[] input, StrMatcher delim, StrMatcher quote) {
this(input, delim);
setQuoteMatcher(quote);
}
// API
//-----------------------------------------------------------------------
/**
* Gets the number of tokens found in the String.
*
* @return the number of matched tokens
*/
public int size() {
checkTokenized();
return tokens.length;
}
/**
* Gets the next token from the String.
* Equivalent to {@link #next()} except it returns null rather than
* throwing {@link NoSuchElementException} when no tokens remain.
*
* @return the next sequential token, or null when no more tokens are found
*/
public String nextToken() {
if (hasNext()) {
return tokens[tokenPos++];
}
return null;
}
/**
* Gets the previous token from the String.
*
* @return the previous sequential token, or null when no more tokens are found
*/
public String previousToken() {
if (hasPrevious()) {
return tokens[--tokenPos];
}
return null;
}
/**
* Gets a copy of the full token list as an independent modifiable array.
*
* @return the tokens as a String array
*/
public String[] getTokenArray() {
checkTokenized();
return (String[]) tokens.clone();
}
/**
* Gets a copy of the full token list as an independent modifiable list.
*
* @return the tokens as a String array
*/
public List getTokenList() {
checkTokenized();
List list = new ArrayList(tokens.length);
for (int i = 0; i < tokens.length; i++) {
list.add(tokens[i]);
}
return list;
}
/**
* Resets this tokenizer, forgetting all parsing and iteration already completed.
*
* This method allows the same tokenizer to be reused for the same String.
*
* @return this, to enable chaining
*/
public StrTokenizer reset() {
tokenPos = 0;
tokens = null;
return this;
}
/**
* Reset this tokenizer, giving it a new input string to parse.
* In this manner you can re-use a tokenizer with the same settings
* on multiple input lines.
*
* @param input the new string to tokenize, null sets no text to parse
* @return this, to enable chaining
*/
public StrTokenizer reset(String input) {
reset();
if (input != null) {
this.chars = input.toCharArray();
} else {
this.chars = null;
}
return this;
}
/**
* Reset this tokenizer, giving it a new input string to parse.
* In this manner you can re-use a tokenizer with the same settings
* on multiple input lines.
*
* The input character array is not cloned, and must not be altered after
* passing in to this method.
*
* @param input the new character array to tokenize, not cloned, null sets no text to parse
* @return this, to enable chaining
*/
public StrTokenizer reset(char[] input) {
reset();
this.chars = input;
return this;
}
// ListIterator
//-----------------------------------------------------------------------
/**
* Checks whether there are any more tokens.
*
* @return true if there are more tokens
*/
public boolean hasNext() {
checkTokenized();
return tokenPos < tokens.length;
}
/**
* Gets the next token.
*
* @return the next String token
* @throws NoSuchElementException if there are no more elements
*/
public Object next() {
if (hasNext()) {
return tokens[tokenPos++];
}
throw new NoSuchElementException();
}
/**
* Gets the index of the next token to return.
*
* @return the next token index
*/
public int nextIndex() {
return tokenPos;
}
/**
* Checks whether there are any previous tokens that can be iterated to.
*
* @return true if there are previous tokens
*/
public boolean hasPrevious() {
checkTokenized();
return tokenPos > 0;
}
/**
* Gets the token previous to the last returned token.
*
* @return the previous token
*/
public Object previous() {
if (hasPrevious()) {
return tokens[--tokenPos];
}
throw new NoSuchElementException();
}
/**
* Gets the index of the previous token.
*
* @return the previous token index
*/
public int previousIndex() {
return tokenPos - 1;
}
/**
* Unsupported ListIterator operation.
*
* @throws UnsupportedOperationException always
*/
public void remove() {
throw new UnsupportedOperationException("remove() is unsupported");
}
/**
* Unsupported ListIterator operation.
* @param obj this parameter ignored.
* @throws UnsupportedOperationException always
*/
public void set(Object obj) {
throw new UnsupportedOperationException("set() is unsupported");
}
/**
* Unsupported ListIterator operation.
* @param obj this parameter ignored.
* @throws UnsupportedOperationException always
*/
public void add(Object obj) {
throw new UnsupportedOperationException("add() is unsupported");
}
// Implementation
//-----------------------------------------------------------------------
/**
* Checks if tokenization has been done, and if not then do it.
*/
private void checkTokenized() {
if (tokens == null) {
if (chars == null) {
// still call tokenize as subclass may do some work
List split = tokenize(null, 0, 0);
tokens = (String[]) split.toArray(new String[split.size()]);
} else {
List split = tokenize(chars, 0, chars.length);
tokens = (String[]) split.toArray(new String[split.size()]);
}
}
}
/**
* Internal method to performs the tokenization.
*
* Most users of this class do not need to call this method. This method
* will be called automatically by other (public) methods when required.
*
* This method exists to allow subclasses to add code before or after the
* tokenization. For example, a subclass could alter the character array,
* offset or count to be parsed, or call the tokenizer multiple times on
* multiple strings. It is also be possible to filter the results.
*
* StrTokenizer
will always pass a zero offset and a count
* equal to the length of the array to this method, however a subclass
* may pass other values, or even an entirely different array.
*
* @param chars the character array being tokenized, may be null
* @param offset the start position within the character array, must be valid
* @param count the number of characters to tokenize, must be valid
* @return the modifiable list of String tokens, unmodifiable if null array or zero count
*/
protected List tokenize(char[] chars, int offset, int count) {
if (chars == null || count == 0) {
return Collections.EMPTY_LIST;
}
StrBuilder buf = new StrBuilder();
List tokens = new ArrayList();
int pos = offset;
// loop around the entire buffer
while (pos >= 0 && pos < count) {
// find next token
pos = readNextToken(chars, pos, count, buf, tokens);
// handle case where end of string is a delimiter
if (pos >= count) {
addToken(tokens, "");
}
}
return tokens;
}
/**
* Adds a token to a list, paying attention to the parameters we've set.
*
* @param list the list to add to
* @param tok the token to add
*/
private void addToken(List list, String tok) {
if (tok == null || tok.length() == 0) {
if (isIgnoreEmptyTokens()) {
return;
}
if (isEmptyTokenAsNull()) {
tok = null;
}
}
list.add(tok);
}
/**
* Reads character by character through the String to get the next token.
*
* @param chars the character array being tokenized
* @param start the first character of field
* @param len the length of the character array being tokenized
* @param workArea a temporary work area
* @param tokens the list of parsed tokens
* @return the starting position of the next field (the character
* immediately after the delimiter), or -1 if end of string found
*/
private int readNextToken(char[] chars, int start, int len, StrBuilder workArea, List tokens) {
// skip all leading whitespace, unless it is the
// field delimiter or the quote character
while (start < len) {
int removeLen = Math.max(
getIgnoredMatcher().isMatch(chars, start, start, len),
getTrimmerMatcher().isMatch(chars, start, start, len));
if (removeLen == 0 ||
getDelimiterMatcher().isMatch(chars, start, start, len) > 0 ||
getQuoteMatcher().isMatch(chars, start, start, len) > 0) {
break;
}
start += removeLen;
}
// handle reaching end
if (start >= len) {
addToken(tokens, "");
return -1;
}
// handle empty token
int delimLen = getDelimiterMatcher().isMatch(chars, start, start, len);
if (delimLen > 0) {
addToken(tokens, "");
return start + delimLen;
}
// handle found token
int quoteLen = getQuoteMatcher().isMatch(chars, start, start, len);
if (quoteLen > 0) {
return readWithQuotes(chars, start + quoteLen, len, workArea, tokens, start, quoteLen);
}
return readWithQuotes(chars, start, len, workArea, tokens, 0, 0);
}
/**
* Reads a possibly quoted string token.
*
* @param chars the character array being tokenized
* @param start the first character of field
* @param len the length of the character array being tokenized
* @param workArea a temporary work area
* @param tokens the list of parsed tokens
* @param quoteStart the start position of the matched quote, 0 if no quoting
* @param quoteLen the length of the matched quote, 0 if no quoting
* @return the starting position of the next field (the character
* immediately after the delimiter, or if end of string found,
* then the length of string
*/
private int readWithQuotes(char[] chars, int start, int len, StrBuilder workArea,
List tokens, int quoteStart, int quoteLen)
{
// Loop until we've found the end of the quoted
// string or the end of the input
workArea.clear();
int pos = start;
boolean quoting = (quoteLen > 0);
int trimStart = 0;
while (pos < len) {
// quoting mode can occur several times throughout a string
// we must switch between quoting and non-quoting until we
// encounter a non-quoted delimiter, or end of string
if (quoting) {
// In quoting mode
// If we've found a quote character, see if it's
// followed by a second quote. If so, then we need
// to actually put the quote character into the token
// rather than end the token.
if (isQuote(chars, pos, len, quoteStart, quoteLen)) {
if (isQuote(chars, pos + quoteLen, len, quoteStart, quoteLen)) {
// matched pair of quotes, thus an escaped quote
workArea.append(chars, pos, quoteLen);
pos += (quoteLen * 2);
trimStart = workArea.size();
continue;
}
// end of quoting
quoting = false;
pos += quoteLen;
continue;
}
// copy regular character from inside quotes
workArea.append(chars[pos++]);
trimStart = workArea.size();
} else {
// Not in quoting mode
// check for delimiter, and thus end of token
int delimLen = getDelimiterMatcher().isMatch(chars, pos, start, len);
if (delimLen > 0) {
// return condition when end of token found
addToken(tokens, workArea.substring(0, trimStart));
return pos + delimLen;
}
// check for quote, and thus back into quoting mode
if (quoteLen > 0) {
if (isQuote(chars, pos, len, quoteStart, quoteLen)) {
quoting = true;
pos += quoteLen;
continue;
}
}
// check for ignored (outside quotes), and ignore
int ignoredLen = getIgnoredMatcher().isMatch(chars, pos, start, len);
if (ignoredLen > 0) {
pos += ignoredLen;
continue;
}
// check for trimmed character
// don't yet know if its at the end, so copy to workArea
// use trimStart to keep track of trim at the end
int trimmedLen = getTrimmerMatcher().isMatch(chars, pos, start, len);
if (trimmedLen > 0) {
workArea.append(chars, pos, trimmedLen);
pos += trimmedLen;
continue;
}
// copy regular character from outside quotes
workArea.append(chars[pos++]);
trimStart = workArea.size();
}
}
// return condition when end of string found
addToken(tokens, workArea.substring(0, trimStart));
return -1;
}
/**
* Checks if the characters at the index specified match the quote
* already matched in readNextToken().
*
* @param chars the character array being tokenized
* @param pos the position to check for a quote
* @param len the length of the character array being tokenized
* @param quoteStart the start position of the matched quote, 0 if no quoting
* @param quoteLen the length of the matched quote, 0 if no quoting
* @return true if a quote is matched
*/
private boolean isQuote(char[] chars, int pos, int len, int quoteStart, int quoteLen) {
for (int i = 0; i < quoteLen; i++) {
if ((pos + i) >= len || chars[pos + i] != chars[quoteStart + i]) {
return false;
}
}
return true;
}
// Delimiter
//-----------------------------------------------------------------------
/**
* Gets the field delimiter matcher.
*
* @return the delimiter matcher in use
*/
public StrMatcher getDelimiterMatcher() {
return this.delimMatcher;
}
/**
* Sets the field delimiter matcher.
*
* The delimitier is used to separate one token from another.
*
* @param delim the delimiter matcher to use
* @return this, to enable chaining
*/
public StrTokenizer setDelimiterMatcher(StrMatcher delim) {
if (delim == null) {
this.delimMatcher = StrMatcher.noneMatcher();
} else {
this.delimMatcher = delim;
}
return this;
}
/**
* Sets the field delimiter character.
*
* @param delim the delimiter character to use
* @return this, to enable chaining
*/
public StrTokenizer setDelimiterChar(char delim) {
return setDelimiterMatcher(StrMatcher.charMatcher(delim));
}
/**
* Sets the field delimiter string.
*
* @param delim the delimiter string to use
* @return this, to enable chaining
*/
public StrTokenizer setDelimiterString(String delim) {
return setDelimiterMatcher(StrMatcher.stringMatcher(delim));
}
// Quote
//-----------------------------------------------------------------------
/**
* Gets the quote matcher currently in use.
*
* The quote character is used to wrap data between the tokens.
* This enables delimiters to be entered as data.
* The default value is '"' (double quote).
*
* @return the quote matcher in use
*/
public StrMatcher getQuoteMatcher() {
return quoteMatcher;
}
/**
* Set the quote matcher to use.
*
* The quote character is used to wrap data between the tokens.
* This enables delimiters to be entered as data.
*
* @param quote the quote matcher to use, null ignored
* @return this, to enable chaining
*/
public StrTokenizer setQuoteMatcher(StrMatcher quote) {
if (quote != null) {
this.quoteMatcher = quote;
}
return this;
}
/**
* Sets the quote character to use.
*
* The quote character is used to wrap data between the tokens.
* This enables delimiters to be entered as data.
*
* @param quote the quote character to use
* @return this, to enable chaining
*/
public StrTokenizer setQuoteChar(char quote) {
return setQuoteMatcher(StrMatcher.charMatcher(quote));
}
// Ignored
//-----------------------------------------------------------------------
/**
* Gets the ignored character matcher.
*
* These characters are ignored when parsing the String, unless they are
* within a quoted region.
* The default value is not to ignore anything.
*
* @return the ignored matcher in use
*/
public StrMatcher getIgnoredMatcher() {
return ignoredMatcher;
}
/**
* Set the matcher for characters to ignore.
*
* These characters are ignored when parsing the String, unless they are
* within a quoted region.
*
* @param ignored the ignored matcher to use, null ignored
* @return this, to enable chaining
*/
public StrTokenizer setIgnoredMatcher(StrMatcher ignored) {
if (ignored != null) {
this.ignoredMatcher = ignored;
}
return this;
}
/**
* Set the character to ignore.
*
* This character is ignored when parsing the String, unless it is
* within a quoted region.
*
* @param ignored the ignored character to use
* @return this, to enable chaining
*/
public StrTokenizer setIgnoredChar(char ignored) {
return setIgnoredMatcher(StrMatcher.charMatcher(ignored));
}
// Trimmer
//-----------------------------------------------------------------------
/**
* Gets the trimmer character matcher.
*
* These characters are trimmed off on each side of the delimiter
* until the token or quote is found.
* The default value is not to trim anything.
*
* @return the trimmer matcher in use
*/
public StrMatcher getTrimmerMatcher() {
return trimmerMatcher;
}
/**
* Sets the matcher for characters to trim.
*
* These characters are trimmed off on each side of the delimiter
* until the token or quote is found.
*
* @param trimmer the trimmer matcher to use, null ignored
* @return this, to enable chaining
*/
public StrTokenizer setTrimmerMatcher(StrMatcher trimmer) {
if (trimmer != null) {
this.trimmerMatcher = trimmer;
}
return this;
}
//-----------------------------------------------------------------------
/**
* Gets whether the tokenizer currently returns empty tokens as null.
* The default for this property is false.
*
* @return true if empty tokens are returned as null
*/
public boolean isEmptyTokenAsNull() {
return this.emptyAsNull;
}
/**
* Sets whether the tokenizer should return empty tokens as null.
* The default for this property is false.
*
* @param emptyAsNull whether empty tokens are returned as null
* @return this, to enable chaining
*/
public StrTokenizer setEmptyTokenAsNull(boolean emptyAsNull) {
this.emptyAsNull = emptyAsNull;
return this;
}
//-----------------------------------------------------------------------
/**
* Gets whether the tokenizer currently ignores empty tokens.
* The default for this property is true.
*
* @return true if empty tokens are not returned
*/
public boolean isIgnoreEmptyTokens() {
return ignoreEmptyTokens;
}
/**
* Sets whether the tokenizer should ignore and not return empty tokens.
* The default for this property is true.
*
* @param ignoreEmptyTokens whether empty tokens are not returned
* @return this, to enable chaining
*/
public StrTokenizer setIgnoreEmptyTokens(boolean ignoreEmptyTokens) {
this.ignoreEmptyTokens = ignoreEmptyTokens;
return this;
}
//-----------------------------------------------------------------------
/**
* Gets the String content that the tokenizer is parsing.
*
* @return the string content being parsed
*/
public String getContent() {
if (chars == null) {
return null;
}
return new String(chars);
}
//-----------------------------------------------------------------------
/**
* Creates a new instance of this Tokenizer. The new instance is reset so
* that it will be at the start of the token list.
* If a {@link CloneNotSupportedException} is caught, return null
.
*
* @return a new instance of this Tokenizer which has been reset.
*/
public Object clone() {
try {
return cloneReset();
} catch (CloneNotSupportedException ex) {
return null;
}
}
/**
* Creates a new instance of this Tokenizer. The new instance is reset so that
* it will be at the start of the token list.
*
* @return a new instance of this Tokenizer which has been reset.
* @throws CloneNotSupportedException if there is a problem cloning
*/
Object cloneReset() throws CloneNotSupportedException {
// this method exists to enable 100% test coverage
StrTokenizer cloned = (StrTokenizer) super.clone();
if (cloned.chars != null) {
cloned.chars = (char[]) cloned.chars.clone();
}
cloned.reset();
return cloned;
}
//-----------------------------------------------------------------------
/**
* Gets the String content that the tokenizer is parsing.
*
* @return the string content being parsed
*/
public String toString() {
if (tokens == null) {
return "StrTokenizer[not tokenized yet]";
}
return "StrTokenizer" + getTokenList();
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/time/DateFormatUtils.java 100644 0 0 30345 11513702443 25624 0 ustar 0 0 /*
* 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.lang.time;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/**
*
Date and time formatting utilities and constants.
*
* Formatting is performed using the
* {@link org.apache.commons.lang.time.FastDateFormat} class.
*
* @author Apache Software Foundation
* @author Apache Ant - DateUtils
* @author Stephane Bailliez
* @author Stefan Bodewig
* @author Gary Gregory
* @since 2.0
* @version $Id: DateFormatUtils.java 905636 2010-02-02 14:03:32Z niallp $
*/
public class DateFormatUtils {
/**
* ISO8601 formatter for date-time without time zone.
* The format used is yyyy-MM-dd'T'HH:mm:ss.
*/
public static final FastDateFormat ISO_DATETIME_FORMAT
= FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");
/**
* ISO8601 formatter for date-time with time zone.
* The format used is yyyy-MM-dd'T'HH:mm:ssZZ.
*/
public static final FastDateFormat ISO_DATETIME_TIME_ZONE_FORMAT
= FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZZ");
/**
* ISO8601 formatter for date without time zone.
* The format used is yyyy-MM-dd.
*/
public static final FastDateFormat ISO_DATE_FORMAT
= FastDateFormat.getInstance("yyyy-MM-dd");
/**
* ISO8601-like formatter for date with time zone.
* The format used is yyyy-MM-ddZZ.
* This pattern does not comply with the formal ISO8601 specification
* as the standard does not allow a time zone without a time.
*/
public static final FastDateFormat ISO_DATE_TIME_ZONE_FORMAT
= FastDateFormat.getInstance("yyyy-MM-ddZZ");
/**
* ISO8601 formatter for time without time zone.
* The format used is 'T'HH:mm:ss.
*/
public static final FastDateFormat ISO_TIME_FORMAT
= FastDateFormat.getInstance("'T'HH:mm:ss");
/**
* ISO8601 formatter for time with time zone.
* The format used is 'T'HH:mm:ssZZ.
*/
public static final FastDateFormat ISO_TIME_TIME_ZONE_FORMAT
= FastDateFormat.getInstance("'T'HH:mm:ssZZ");
/**
* ISO8601-like formatter for time without time zone.
* The format used is HH:mm:ss.
* This pattern does not comply with the formal ISO8601 specification
* as the standard requires the 'T' prefix for times.
*/
public static final FastDateFormat ISO_TIME_NO_T_FORMAT
= FastDateFormat.getInstance("HH:mm:ss");
/**
* ISO8601-like formatter for time with time zone.
* The format used is HH:mm:ssZZ.
* This pattern does not comply with the formal ISO8601 specification
* as the standard requires the 'T' prefix for times.
*/
public static final FastDateFormat ISO_TIME_NO_T_TIME_ZONE_FORMAT
= FastDateFormat.getInstance("HH:mm:ssZZ");
/**
* SMTP (and probably other) date headers.
* The format used is EEE, dd MMM yyyy HH:mm:ss Z in US locale.
*/
public static final FastDateFormat SMTP_DATETIME_FORMAT
= FastDateFormat.getInstance("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
//-----------------------------------------------------------------------
/**
* DateFormatUtils instances should NOT be constructed in standard programming.
*
* This constructor is public to permit tools that require a JavaBean instance
* to operate.
*/
public DateFormatUtils() {
super();
}
/**
* Formats a date/time into a specific pattern using the UTC time zone.
*
* @param millis the date to format expressed in milliseconds
* @param pattern the pattern to use to format the date
* @return the formatted date
*/
public static String formatUTC(long millis, String pattern) {
return format(new Date(millis), pattern, DateUtils.UTC_TIME_ZONE, null);
}
/**
* Formats a date/time into a specific pattern using the UTC time zone.
*
* @param date the date to format
* @param pattern the pattern to use to format the date
* @return the formatted date
*/
public static String formatUTC(Date date, String pattern) {
return format(date, pattern, DateUtils.UTC_TIME_ZONE, null);
}
/**
* Formats a date/time into a specific pattern using the UTC time zone.
*
* @param millis the date to format expressed in milliseconds
* @param pattern the pattern to use to format the date
* @param locale the locale to use, may be null
* @return the formatted date
*/
public static String formatUTC(long millis, String pattern, Locale locale) {
return format(new Date(millis), pattern, DateUtils.UTC_TIME_ZONE, locale);
}
/**
* Formats a date/time into a specific pattern using the UTC time zone.
*
* @param date the date to format
* @param pattern the pattern to use to format the date
* @param locale the locale to use, may be null
* @return the formatted date
*/
public static String formatUTC(Date date, String pattern, Locale locale) {
return format(date, pattern, DateUtils.UTC_TIME_ZONE, locale);
}
/**
* Formats a date/time into a specific pattern.
*
* @param millis the date to format expressed in milliseconds
* @param pattern the pattern to use to format the date
* @return the formatted date
*/
public static String format(long millis, String pattern) {
return format(new Date(millis), pattern, null, null);
}
/**
* Formats a date/time into a specific pattern.
*
* @param date the date to format
* @param pattern the pattern to use to format the date
* @return the formatted date
*/
public static String format(Date date, String pattern) {
return format(date, pattern, null, null);
}
/**
* Formats a calendar into a specific pattern.
*
* @param calendar the calendar to format
* @param pattern the pattern to use to format the calendar
* @return the formatted calendar
* @see FastDateFormat#format(Calendar)
* @since 2.4
*/
public static String format(Calendar calendar, String pattern) {
return format(calendar, pattern, null, null);
}
/**
* Formats a date/time into a specific pattern in a time zone.
*
* @param millis the time expressed in milliseconds
* @param pattern the pattern to use to format the date
* @param timeZone the time zone to use, may be null
* @return the formatted date
*/
public static String format(long millis, String pattern, TimeZone timeZone) {
return format(new Date(millis), pattern, timeZone, null);
}
/**
* Formats a date/time into a specific pattern in a time zone.
*
* @param date the date to format
* @param pattern the pattern to use to format the date
* @param timeZone the time zone to use, may be null
* @return the formatted date
*/
public static String format(Date date, String pattern, TimeZone timeZone) {
return format(date, pattern, timeZone, null);
}
/**
* Formats a calendar into a specific pattern in a time zone.
*
* @param calendar the calendar to format
* @param pattern the pattern to use to format the calendar
* @param timeZone the time zone to use, may be null
* @return the formatted calendar
* @see FastDateFormat#format(Calendar)
* @since 2.4
*/
public static String format(Calendar calendar, String pattern, TimeZone timeZone) {
return format(calendar, pattern, timeZone, null);
}
/**
* Formats a date/time into a specific pattern in a locale.
*
* @param millis the date to format expressed in milliseconds
* @param pattern the pattern to use to format the date
* @param locale the locale to use, may be null
* @return the formatted date
*/
public static String format(long millis, String pattern, Locale locale) {
return format(new Date(millis), pattern, null, locale);
}
/**
* Formats a date/time into a specific pattern in a locale.
*
* @param date the date to format
* @param pattern the pattern to use to format the date
* @param locale the locale to use, may be null
* @return the formatted date
*/
public static String format(Date date, String pattern, Locale locale) {
return format(date, pattern, null, locale);
}
/**
* Formats a calendar into a specific pattern in a locale.
*
* @param calendar the calendar to format
* @param pattern the pattern to use to format the calendar
* @param locale the locale to use, may be null
* @return the formatted calendar
* @see FastDateFormat#format(Calendar)
* @since 2.4
*/
public static String format(Calendar calendar, String pattern, Locale locale) {
return format(calendar, pattern, null, locale);
}
/**
* Formats a date/time into a specific pattern in a time zone and locale.
*
* @param millis the date to format expressed in milliseconds
* @param pattern the pattern to use to format the date
* @param timeZone the time zone to use, may be null
* @param locale the locale to use, may be null
* @return the formatted date
*/
public static String format(long millis, String pattern, TimeZone timeZone, Locale locale) {
return format(new Date(millis), pattern, timeZone, locale);
}
/**
* Formats a date/time into a specific pattern in a time zone and locale.
*
* @param date the date to format
* @param pattern the pattern to use to format the date
* @param timeZone the time zone to use, may be null
* @param locale the locale to use, may be null
* @return the formatted date
*/
public static String format(Date date, String pattern, TimeZone timeZone, Locale locale) {
FastDateFormat df = FastDateFormat.getInstance(pattern, timeZone, locale);
return df.format(date);
}
/**
* Formats a calendar into a specific pattern in a time zone and locale.
*
* @param calendar the calendar to format
* @param pattern the pattern to use to format the calendar
* @param timeZone the time zone to use, may be null
* @param locale the locale to use, may be null
* @return the formatted calendar
* @see FastDateFormat#format(Calendar)
* @since 2.4
*/
public static String format(Calendar calendar, String pattern, TimeZone timeZone, Locale locale) {
FastDateFormat df = FastDateFormat.getInstance(pattern, timeZone, locale);
return df.format(calendar);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/time/DateUtils.java 100644 0 0 243404 11513702443 24475 0 ustar 0 0 /*
* 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.lang.time;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.TimeZone;
import org.apache.commons.lang.StringUtils;
/**
* A suite of utilities surrounding the use of the
* {@link java.util.Calendar} and {@link java.util.Date} object.
*
* DateUtils contains a lot of common methods considering manipulations
* of Dates or Calendars. Some methods require some extra explanation.
* The truncate, ceiling and round methods could be considered the Math.floor(),
* Math.ceil() or Math.round versions for dates
* This way date-fields will be ignored in bottom-up order.
* As a complement to these methods we've introduced some fragment-methods.
* With these methods the Date-fields will be ignored in top-down order.
* Since a date without a year is not a valid date, you have to decide in what
* kind of date-field you want your result, for instance milliseconds or days.
*
*
*
*
* @author Apache Software Foundation
* @author Serge Knystautas
* @author Janek Bogucki
* @author Gary Gregory
* @author Phil Steitz
* @author Robert Scholte
* @since 2.0
* @version $Id: DateUtils.java 1056840 2011-01-09 00:12:23Z niallp $
*/
public class DateUtils {
/**
* The UTC time zone (often referred to as GMT).
*/
public static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("GMT");
/**
* Number of milliseconds in a standard second.
* @since 2.1
*/
public static final long MILLIS_PER_SECOND = 1000;
/**
* Number of milliseconds in a standard minute.
* @since 2.1
*/
public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
/**
* Number of milliseconds in a standard hour.
* @since 2.1
*/
public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
/**
* Number of milliseconds in a standard day.
* @since 2.1
*/
public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
/**
* This is half a month, so this represents whether a date is in the top
* or bottom half of the month.
*/
public final static int SEMI_MONTH = 1001;
private static final int[][] fields = {
{Calendar.MILLISECOND},
{Calendar.SECOND},
{Calendar.MINUTE},
{Calendar.HOUR_OF_DAY, Calendar.HOUR},
{Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM
/* Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK_IN_MONTH */
},
{Calendar.MONTH, DateUtils.SEMI_MONTH},
{Calendar.YEAR},
{Calendar.ERA}};
/**
* A week range, starting on Sunday.
*/
public final static int RANGE_WEEK_SUNDAY = 1;
/**
* A week range, starting on Monday.
*/
public final static int RANGE_WEEK_MONDAY = 2;
/**
* A week range, starting on the day focused.
*/
public final static int RANGE_WEEK_RELATIVE = 3;
/**
* A week range, centered around the day focused.
*/
public final static int RANGE_WEEK_CENTER = 4;
/**
* A month range, the week starting on Sunday.
*/
public final static int RANGE_MONTH_SUNDAY = 5;
/**
* A month range, the week starting on Monday.
*/
public final static int RANGE_MONTH_MONDAY = 6;
/**
* Constant marker for truncating
*/
private final static int MODIFY_TRUNCATE = 0;
/**
* Constant marker for rounding
*/
private final static int MODIFY_ROUND = 1;
/**
* Constant marker for ceiling
*/
private final static int MODIFY_CEILING= 2;
/**
* DateUtils
instances should NOT be constructed in
* standard programming. Instead, the class should be used as
* DateUtils.parse(str);
.
*
* This constructor is public to permit tools that require a JavaBean
* instance to operate.
*/
public DateUtils() {
super();
}
//-----------------------------------------------------------------------
/**
* Checks if two date objects are on the same day ignoring time.
*
* 28 Mar 2002 13:45 and 28 Mar 2002 06:01 would return true.
* 28 Mar 2002 13:45 and 12 Mar 2002 13:45 would return false.
*
*
* @param date1 the first date, not altered, not null
* @param date2 the second date, not altered, not null
* @return true if they represent the same day
* @throws IllegalArgumentException if either date is null
* @since 2.1
*/
public static boolean isSameDay(Date date1, Date date2) {
if (date1 == null || date2 == null) {
throw new IllegalArgumentException("The date must not be null");
}
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date1);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(date2);
return isSameDay(cal1, cal2);
}
/**
* Checks if two calendar objects are on the same day ignoring time.
*
* 28 Mar 2002 13:45 and 28 Mar 2002 06:01 would return true.
* 28 Mar 2002 13:45 and 12 Mar 2002 13:45 would return false.
*
*
* @param cal1 the first calendar, not altered, not null
* @param cal2 the second calendar, not altered, not null
* @return true if they represent the same day
* @throws IllegalArgumentException if either calendar is null
* @since 2.1
*/
public static boolean isSameDay(Calendar cal1, Calendar cal2) {
if (cal1 == null || cal2 == null) {
throw new IllegalArgumentException("The date must not be null");
}
return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) &&
cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR));
}
//-----------------------------------------------------------------------
/**
* Checks if two date objects represent the same instant in time.
*
* This method compares the long millisecond time of the two objects.
*
* @param date1 the first date, not altered, not null
* @param date2 the second date, not altered, not null
* @return true if they represent the same millisecond instant
* @throws IllegalArgumentException if either date is null
* @since 2.1
*/
public static boolean isSameInstant(Date date1, Date date2) {
if (date1 == null || date2 == null) {
throw new IllegalArgumentException("The date must not be null");
}
return date1.getTime() == date2.getTime();
}
/**
* Checks if two calendar objects represent the same instant in time.
*
* This method compares the long millisecond time of the two objects.
*
* @param cal1 the first calendar, not altered, not null
* @param cal2 the second calendar, not altered, not null
* @return true if they represent the same millisecond instant
* @throws IllegalArgumentException if either date is null
* @since 2.1
*/
public static boolean isSameInstant(Calendar cal1, Calendar cal2) {
if (cal1 == null || cal2 == null) {
throw new IllegalArgumentException("The date must not be null");
}
return cal1.getTime().getTime() == cal2.getTime().getTime();
}
//-----------------------------------------------------------------------
/**
* Checks if two calendar objects represent the same local time.
*
* This method compares the values of the fields of the two objects.
* In addition, both calendars must be the same of the same type.
*
* @param cal1 the first calendar, not altered, not null
* @param cal2 the second calendar, not altered, not null
* @return true if they represent the same millisecond instant
* @throws IllegalArgumentException if either date is null
* @since 2.1
*/
public static boolean isSameLocalTime(Calendar cal1, Calendar cal2) {
if (cal1 == null || cal2 == null) {
throw new IllegalArgumentException("The date must not be null");
}
return (cal1.get(Calendar.MILLISECOND) == cal2.get(Calendar.MILLISECOND) &&
cal1.get(Calendar.SECOND) == cal2.get(Calendar.SECOND) &&
cal1.get(Calendar.MINUTE) == cal2.get(Calendar.MINUTE) &&
cal1.get(Calendar.HOUR) == cal2.get(Calendar.HOUR) &&
cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) &&
cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) &&
cal1.getClass() == cal2.getClass());
}
//-----------------------------------------------------------------------
/**
* Parses a string representing a date by trying a variety of different parsers.
*
* The parse will try each parse pattern in turn.
* A parse is only deemed successful if it parses the whole of the input string.
* If no parse patterns match, a ParseException is thrown.
* The parser will be lenient toward the parsed date.
*
* @param str the date to parse, not null
* @param parsePatterns the date format patterns to use, see SimpleDateFormat, not null
* @return the parsed date
* @throws IllegalArgumentException if the date string or pattern array is null
* @throws ParseException if none of the date patterns were suitable (or there were none)
*/
public static Date parseDate(String str, String[] parsePatterns) throws ParseException {
return parseDateWithLeniency(str, parsePatterns, true);
}
//-----------------------------------------------------------------------
/**
* Parses a string representing a date by trying a variety of different parsers.
*
* The parse will try each parse pattern in turn.
* A parse is only deemed successful if it parses the whole of the input string.
* If no parse patterns match, a ParseException is thrown.
* The parser parses strictly - it does not allow for dates such as "February 942, 1996".
*
* @param str the date to parse, not null
* @param parsePatterns the date format patterns to use, see SimpleDateFormat, not null
* @return the parsed date
* @throws IllegalArgumentException if the date string or pattern array is null
* @throws ParseException if none of the date patterns were suitable
* @since 2.5
*/
public static Date parseDateStrictly(String str, String[] parsePatterns) throws ParseException {
return parseDateWithLeniency(str, parsePatterns, false);
}
/**
* Parses a string representing a date by trying a variety of different parsers.
*
* The parse will try each parse pattern in turn.
* A parse is only deemed successful if it parses the whole of the input string.
* If no parse patterns match, a ParseException is thrown.
*
* @param str the date to parse, not null
* @param parsePatterns the date format patterns to use, see SimpleDateFormat, not null
* @param lenient Specify whether or not date/time parsing is to be lenient.
* @return the parsed date
* @throws IllegalArgumentException if the date string or pattern array is null
* @throws ParseException if none of the date patterns were suitable
* @see java.util.Calender#isLenient()
*/
private static Date parseDateWithLeniency(String str, String[] parsePatterns,
boolean lenient) throws ParseException {
if (str == null || parsePatterns == null) {
throw new IllegalArgumentException("Date and Patterns must not be null");
}
SimpleDateFormat parser = new SimpleDateFormat();
parser.setLenient(lenient);
ParsePosition pos = new ParsePosition(0);
for (int i = 0; i < parsePatterns.length; i++) {
String pattern = parsePatterns[i];
// LANG-530 - need to make sure 'ZZ' output doesn't get passed to SimpleDateFormat
if (parsePatterns[i].endsWith("ZZ")) {
pattern = pattern.substring(0, pattern.length() - 1);
}
parser.applyPattern(pattern);
pos.setIndex(0);
String str2 = str;
// LANG-530 - need to make sure 'ZZ' output doesn't hit SimpleDateFormat as it will ParseException
if (parsePatterns[i].endsWith("ZZ")) {
int signIdx = indexOfSignChars(str2, 0);
while (signIdx >=0) {
str2 = reformatTimezone(str2, signIdx);
signIdx = indexOfSignChars(str2, ++signIdx);
}
}
Date date = parser.parse(str2, pos);
if (date != null && pos.getIndex() == str2.length()) {
return date;
}
}
throw new ParseException("Unable to parse the date: " + str, -1);
}
/**
* Index of sign charaters (i.e. '+' or '-').
*
* @param str The string to search
* @param startPos The start position
* @return the index of the first sign character or -1 if not found
*/
private static int indexOfSignChars(String str, int startPos) {
int idx = StringUtils.indexOf(str, '+', startPos);
if (idx < 0) {
idx = StringUtils.indexOf(str, '-', startPos);
}
return idx;
}
/**
* Reformat the timezone in a date string.
*
* @param str The input string
* @param signIdx The index position of the sign characters
* @return The reformatted string
*/
private static String reformatTimezone(String str, int signIdx) {
String str2 = str;
if (signIdx >= 0 &&
signIdx + 5 < str.length() &&
Character.isDigit(str.charAt(signIdx + 1)) &&
Character.isDigit(str.charAt(signIdx + 2)) &&
str.charAt(signIdx + 3) == ':' &&
Character.isDigit(str.charAt(signIdx + 4)) &&
Character.isDigit(str.charAt(signIdx + 5))) {
str2 = str.substring(0, signIdx + 3) + str.substring(signIdx + 4);
}
return str2;
}
//-----------------------------------------------------------------------
/**
* Adds a number of years to a date returning a new object.
* The original date object is unchanged.
*
* @param date the date, not null
* @param amount the amount to add, may be negative
* @return the new date object with the amount added
* @throws IllegalArgumentException if the date is null
*/
public static Date addYears(Date date, int amount) {
return add(date, Calendar.YEAR, amount);
}
//-----------------------------------------------------------------------
/**
* Adds a number of months to a date returning a new object.
* The original date object is unchanged.
*
* @param date the date, not null
* @param amount the amount to add, may be negative
* @return the new date object with the amount added
* @throws IllegalArgumentException if the date is null
*/
public static Date addMonths(Date date, int amount) {
return add(date, Calendar.MONTH, amount);
}
//-----------------------------------------------------------------------
/**
* Adds a number of weeks to a date returning a new object.
* The original date object is unchanged.
*
* @param date the date, not null
* @param amount the amount to add, may be negative
* @return the new date object with the amount added
* @throws IllegalArgumentException if the date is null
*/
public static Date addWeeks(Date date, int amount) {
return add(date, Calendar.WEEK_OF_YEAR, amount);
}
//-----------------------------------------------------------------------
/**
* Adds a number of days to a date returning a new object.
* The original date object is unchanged.
*
* @param date the date, not null
* @param amount the amount to add, may be negative
* @return the new date object with the amount added
* @throws IllegalArgumentException if the date is null
*/
public static Date addDays(Date date, int amount) {
return add(date, Calendar.DAY_OF_MONTH, amount);
}
//-----------------------------------------------------------------------
/**
* Adds a number of hours to a date returning a new object.
* The original date object is unchanged.
*
* @param date the date, not null
* @param amount the amount to add, may be negative
* @return the new date object with the amount added
* @throws IllegalArgumentException if the date is null
*/
public static Date addHours(Date date, int amount) {
return add(date, Calendar.HOUR_OF_DAY, amount);
}
//-----------------------------------------------------------------------
/**
* Adds a number of minutes to a date returning a new object.
* The original date object is unchanged.
*
* @param date the date, not null
* @param amount the amount to add, may be negative
* @return the new date object with the amount added
* @throws IllegalArgumentException if the date is null
*/
public static Date addMinutes(Date date, int amount) {
return add(date, Calendar.MINUTE, amount);
}
//-----------------------------------------------------------------------
/**
* Adds a number of seconds to a date returning a new object.
* The original date object is unchanged.
*
* @param date the date, not null
* @param amount the amount to add, may be negative
* @return the new date object with the amount added
* @throws IllegalArgumentException if the date is null
*/
public static Date addSeconds(Date date, int amount) {
return add(date, Calendar.SECOND, amount);
}
//-----------------------------------------------------------------------
/**
* Adds a number of milliseconds to a date returning a new object.
* The original date object is unchanged.
*
* @param date the date, not null
* @param amount the amount to add, may be negative
* @return the new date object with the amount added
* @throws IllegalArgumentException if the date is null
*/
public static Date addMilliseconds(Date date, int amount) {
return add(date, Calendar.MILLISECOND, amount);
}
//-----------------------------------------------------------------------
/**
* Adds to a date returning a new object.
* The original date object is unchanged.
*
* @param date the date, not null
* @param calendarField the calendar field to add to
* @param amount the amount to add, may be negative
* @return the new date object with the amount added
* @throws IllegalArgumentException if the date is null
* @deprecated Will become privately scoped in 3.0
*/
public static Date add(Date date, int calendarField, int amount) {
if (date == null) {
throw new IllegalArgumentException("The date must not be null");
}
Calendar c = Calendar.getInstance();
c.setTime(date);
c.add(calendarField, amount);
return c.getTime();
}
//-----------------------------------------------------------------------
/**
* Sets the years field to a date returning a new object.
* The original date object is unchanged.
*
* @param date the date, not null
* @param amount the amount to set
* @return a new Date object set with the specified value
* @throws IllegalArgumentException if the date is null
* @since 2.4
*/
public static Date setYears(Date date, int amount) {
return set(date, Calendar.YEAR, amount);
}
//-----------------------------------------------------------------------
/**
* Sets the months field to a date returning a new object.
* The original date object is unchanged.
*
* @param date the date, not null
* @param amount the amount to set
* @return a new Date object set with the specified value
* @throws IllegalArgumentException if the date is null
* @since 2.4
*/
public static Date setMonths(Date date, int amount) {
return set(date, Calendar.MONTH, amount);
}
//-----------------------------------------------------------------------
/**
* Sets the day of month field to a date returning a new object.
* The original date object is unchanged.
*
* @param date the date, not null
* @param amount the amount to set
* @return a new Date object set with the specified value
* @throws IllegalArgumentException if the date is null
* @since 2.4
*/
public static Date setDays(Date date, int amount) {
return set(date, Calendar.DAY_OF_MONTH, amount);
}
//-----------------------------------------------------------------------
/**
* Sets the hours field to a date returning a new object. Hours range
* from 0-23.
* The original date object is unchanged.
*
* @param date the date, not null
* @param amount the amount to set
* @return a new Date object set with the specified value
* @throws IllegalArgumentException if the date is null
* @since 2.4
*/
public static Date setHours(Date date, int amount) {
return set(date, Calendar.HOUR_OF_DAY, amount);
}
//-----------------------------------------------------------------------
/**
* Sets the minute field to a date returning a new object.
* The original date object is unchanged.
*
* @param date the date, not null
* @param amount the amount to set
* @return a new Date object set with the specified value
* @throws IllegalArgumentException if the date is null
* @since 2.4
*/
public static Date setMinutes(Date date, int amount) {
return set(date, Calendar.MINUTE, amount);
}
//-----------------------------------------------------------------------
/**
* Sets the seconds field to a date returning a new object.
* The original date object is unchanged.
*
* @param date the date, not null
* @param amount the amount to set
* @return a new Date object set with the specified value
* @throws IllegalArgumentException if the date is null
* @since 2.4
*/
public static Date setSeconds(Date date, int amount) {
return set(date, Calendar.SECOND, amount);
}
//-----------------------------------------------------------------------
/**
* Sets the miliseconds field to a date returning a new object.
* The original date object is unchanged.
*
* @param date the date, not null
* @param amount the amount to set
* @return a new Date object set with the specified value
* @throws IllegalArgumentException if the date is null
* @since 2.4
*/
public static Date setMilliseconds(Date date, int amount) {
return set(date, Calendar.MILLISECOND, amount);
}
//-----------------------------------------------------------------------
/**
* Sets the specified field to a date returning a new object.
* This does not use a lenient calendar.
* The original date object is unchanged.
*
* @param date the date, not null
* @param calendarField the calendar field to set the amount to
* @param amount the amount to set
* @return a new Date object set with the specified value
* @throws IllegalArgumentException if the date is null
* @since 2.4
*/
private static Date set(Date date, int calendarField, int amount) {
if (date == null) {
throw new IllegalArgumentException("The date must not be null");
}
// getInstance() returns a new object, so this method is thread safe.
Calendar c = Calendar.getInstance();
c.setLenient(false);
c.setTime(date);
c.set(calendarField, amount);
return c.getTime();
}
//-----------------------------------------------------------------------
/**
* Convert a Date into a Calendar object.
*
* @param date the date to convert to a Calendar
* @return the created Calendar
* @throws NullPointerException if null is passed in
* @since 2.6
*/
public static Calendar toCalendar(Date date) {
Calendar c = Calendar.getInstance();
c.setTime(date);
return c;
}
//-----------------------------------------------------------------------
/**
* Round this date, leaving the field specified as the most
* significant field.
*
* For example, if you had the datetime of 28 Mar 2002
* 13:45:01.231, if this was passed with HOUR, it would return
* 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it
* would return 1 April 2002 0:00:00.000.
*
* For a date in a timezone that handles the change to daylight
* saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows.
* Suppose daylight saving time begins at 02:00 on March 30. Rounding a
* date that crosses this time would produce the following values:
*
* - March 30, 2003 01:10 rounds to March 30, 2003 01:00
* - March 30, 2003 01:40 rounds to March 30, 2003 03:00
* - March 30, 2003 02:10 rounds to March 30, 2003 03:00
* - March 30, 2003 02:40 rounds to March 30, 2003 04:00
*
*
*
* @param date the date to work with
* @param field the field from Calendar
* or SEMI_MONTH
* @return the rounded date
* @throws IllegalArgumentException if the date is null
* @throws ArithmeticException if the year is over 280 million
*/
public static Date round(Date date, int field) {
if (date == null) {
throw new IllegalArgumentException("The date must not be null");
}
Calendar gval = Calendar.getInstance();
gval.setTime(date);
modify(gval, field, MODIFY_ROUND);
return gval.getTime();
}
/**
* Round this date, leaving the field specified as the most
* significant field.
*
* For example, if you had the datetime of 28 Mar 2002
* 13:45:01.231, if this was passed with HOUR, it would return
* 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it
* would return 1 April 2002 0:00:00.000.
*
* For a date in a timezone that handles the change to daylight
* saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows.
* Suppose daylight saving time begins at 02:00 on March 30. Rounding a
* date that crosses this time would produce the following values:
*
* - March 30, 2003 01:10 rounds to March 30, 2003 01:00
* - March 30, 2003 01:40 rounds to March 30, 2003 03:00
* - March 30, 2003 02:10 rounds to March 30, 2003 03:00
* - March 30, 2003 02:40 rounds to March 30, 2003 04:00
*
*
*
* @param date the date to work with
* @param field the field from Calendar
* or SEMI_MONTH
* @return the rounded date (a different object)
* @throws IllegalArgumentException if the date is null
* @throws ArithmeticException if the year is over 280 million
*/
public static Calendar round(Calendar date, int field) {
if (date == null) {
throw new IllegalArgumentException("The date must not be null");
}
Calendar rounded = (Calendar) date.clone();
modify(rounded, field, MODIFY_ROUND);
return rounded;
}
/**
* Round this date, leaving the field specified as the most
* significant field.
*
* For example, if you had the datetime of 28 Mar 2002
* 13:45:01.231, if this was passed with HOUR, it would return
* 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it
* would return 1 April 2002 0:00:00.000.
*
* For a date in a timezone that handles the change to daylight
* saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows.
* Suppose daylight saving time begins at 02:00 on March 30. Rounding a
* date that crosses this time would produce the following values:
*
* - March 30, 2003 01:10 rounds to March 30, 2003 01:00
* - March 30, 2003 01:40 rounds to March 30, 2003 03:00
* - March 30, 2003 02:10 rounds to March 30, 2003 03:00
* - March 30, 2003 02:40 rounds to March 30, 2003 04:00
*
*
*
* @param date the date to work with, either Date or Calendar
* @param field the field from Calendar
* or SEMI_MONTH
* @return the rounded date
* @throws IllegalArgumentException if the date is null
* @throws ClassCastException if the object type is not a Date
* or Calendar
* @throws ArithmeticException if the year is over 280 million
*/
public static Date round(Object date, int field) {
if (date == null) {
throw new IllegalArgumentException("The date must not be null");
}
if (date instanceof Date) {
return round((Date) date, field);
} else if (date instanceof Calendar) {
return round((Calendar) date, field).getTime();
} else {
throw new ClassCastException("Could not round " + date);
}
}
//-----------------------------------------------------------------------
/**
* Truncate this date, leaving the field specified as the most
* significant field.
*
* For example, if you had the datetime of 28 Mar 2002
* 13:45:01.231, if you passed with HOUR, it would return 28 Mar
* 2002 13:00:00.000. If this was passed with MONTH, it would
* return 1 Mar 2002 0:00:00.000.
*
* @param date the date to work with
* @param field the field from Calendar
* or SEMI_MONTH
* @return the rounded date
* @throws IllegalArgumentException if the date is null
* @throws ArithmeticException if the year is over 280 million
*/
public static Date truncate(Date date, int field) {
if (date == null) {
throw new IllegalArgumentException("The date must not be null");
}
Calendar gval = Calendar.getInstance();
gval.setTime(date);
modify(gval, field, MODIFY_TRUNCATE);
return gval.getTime();
}
/**
* Truncate this date, leaving the field specified as the most
* significant field.
*
* For example, if you had the datetime of 28 Mar 2002
* 13:45:01.231, if you passed with HOUR, it would return 28 Mar
* 2002 13:00:00.000. If this was passed with MONTH, it would
* return 1 Mar 2002 0:00:00.000.
*
* @param date the date to work with
* @param field the field from Calendar
* or SEMI_MONTH
* @return the rounded date (a different object)
* @throws IllegalArgumentException if the date is null
* @throws ArithmeticException if the year is over 280 million
*/
public static Calendar truncate(Calendar date, int field) {
if (date == null) {
throw new IllegalArgumentException("The date must not be null");
}
Calendar truncated = (Calendar) date.clone();
modify(truncated, field, MODIFY_TRUNCATE);
return truncated;
}
/**
* Truncate this date, leaving the field specified as the most
* significant field.
*
* For example, if you had the datetime of 28 Mar 2002
* 13:45:01.231, if you passed with HOUR, it would return 28 Mar
* 2002 13:00:00.000. If this was passed with MONTH, it would
* return 1 Mar 2002 0:00:00.000.
*
* @param date the date to work with, either Date
* or Calendar
* @param field the field from Calendar
* or SEMI_MONTH
* @return the rounded date
* @throws IllegalArgumentException if the date
* is null
* @throws ClassCastException if the object type is not a
* Date
or Calendar
* @throws ArithmeticException if the year is over 280 million
*/
public static Date truncate(Object date, int field) {
if (date == null) {
throw new IllegalArgumentException("The date must not be null");
}
if (date instanceof Date) {
return truncate((Date) date, field);
} else if (date instanceof Calendar) {
return truncate((Calendar) date, field).getTime();
} else {
throw new ClassCastException("Could not truncate " + date);
}
}
//-----------------------------------------------------------------------
/**
* Ceil this date, leaving the field specified as the most
* significant field.
*
* For example, if you had the datetime of 28 Mar 2002
* 13:45:01.231, if you passed with HOUR, it would return 28 Mar
* 2002 13:00:00.000. If this was passed with MONTH, it would
* return 1 Mar 2002 0:00:00.000.
*
* @param date the date to work with
* @param field the field from Calendar
* or SEMI_MONTH
* @return the rounded date
* @throws IllegalArgumentException if the date is null
* @throws ArithmeticException if the year is over 280 million
* @since 2.5
*/
public static Date ceiling(Date date, int field) {
if (date == null) {
throw new IllegalArgumentException("The date must not be null");
}
Calendar gval = Calendar.getInstance();
gval.setTime(date);
modify(gval, field, MODIFY_CEILING);
return gval.getTime();
}
/**
* Ceil this date, leaving the field specified as the most
* significant field.
*
* For example, if you had the datetime of 28 Mar 2002
* 13:45:01.231, if you passed with HOUR, it would return 28 Mar
* 2002 13:00:00.000. If this was passed with MONTH, it would
* return 1 Mar 2002 0:00:00.000.
*
* @param date the date to work with
* @param field the field from Calendar
* or SEMI_MONTH
* @return the rounded date (a different object)
* @throws IllegalArgumentException if the date is null
* @throws ArithmeticException if the year is over 280 million
* @since 2.5
*/
public static Calendar ceiling(Calendar date, int field) {
if (date == null) {
throw new IllegalArgumentException("The date must not be null");
}
Calendar ceiled = (Calendar) date.clone();
modify(ceiled, field, MODIFY_CEILING);
return ceiled;
}
/**
* Ceil this date, leaving the field specified as the most
* significant field.
*
* For example, if you had the datetime of 28 Mar 2002
* 13:45:01.231, if you passed with HOUR, it would return 28 Mar
* 2002 13:00:00.000. If this was passed with MONTH, it would
* return 1 Mar 2002 0:00:00.000.
*
* @param date the date to work with, either Date
* or Calendar
* @param field the field from Calendar
* or SEMI_MONTH
* @return the rounded date
* @throws IllegalArgumentException if the date
* is null
* @throws ClassCastException if the object type is not a
* Date
or Calendar
* @throws ArithmeticException if the year is over 280 million
* @since 2.5
*/
public static Date ceiling(Object date, int field) {
if (date == null) {
throw new IllegalArgumentException("The date must not be null");
}
if (date instanceof Date) {
return ceiling((Date) date, field);
} else if (date instanceof Calendar) {
return ceiling((Calendar) date, field).getTime();
} else {
throw new ClassCastException("Could not find ceiling of for type: " + date.getClass());
}
}
//-----------------------------------------------------------------------
/**
* Internal calculation method.
*
* @param val the calendar
* @param field the field constant
* @param modType type to truncate, round or ceiling
* @throws ArithmeticException if the year is over 280 million
*/
private static void modify(Calendar val, int field, int modType) {
if (val.get(Calendar.YEAR) > 280000000) {
throw new ArithmeticException("Calendar value too large for accurate calculations");
}
if (field == Calendar.MILLISECOND) {
return;
}
// ----------------- Fix for LANG-59 ---------------------- START ---------------
// see http://issues.apache.org/jira/browse/LANG-59
//
// Manually truncate milliseconds, seconds and minutes, rather than using
// Calendar methods.
Date date = val.getTime();
long time = date.getTime();
boolean done = false;
// truncate milliseconds
int millisecs = val.get(Calendar.MILLISECOND);
if (MODIFY_TRUNCATE == modType || millisecs < 500) {
time = time - millisecs;
}
if (field == Calendar.SECOND) {
done = true;
}
// truncate seconds
int seconds = val.get(Calendar.SECOND);
if (!done && (MODIFY_TRUNCATE == modType || seconds < 30)) {
time = time - (seconds * 1000L);
}
if (field == Calendar.MINUTE) {
done = true;
}
// truncate minutes
int minutes = val.get(Calendar.MINUTE);
if (!done && (MODIFY_TRUNCATE == modType || minutes < 30)) {
time = time - (minutes * 60000L);
}
// reset time
if (date.getTime() != time) {
date.setTime(time);
val.setTime(date);
}
// ----------------- Fix for LANG-59 ----------------------- END ----------------
boolean roundUp = false;
for (int i = 0; i < fields.length; i++) {
for (int j = 0; j < fields[i].length; j++) {
if (fields[i][j] == field) {
//This is our field... we stop looping
if (modType == MODIFY_CEILING || (modType == MODIFY_ROUND && roundUp)) {
if (field == DateUtils.SEMI_MONTH) {
//This is a special case that's hard to generalize
//If the date is 1, we round up to 16, otherwise
// we subtract 15 days and add 1 month
if (val.get(Calendar.DATE) == 1) {
val.add(Calendar.DATE, 15);
} else {
val.add(Calendar.DATE, -15);
val.add(Calendar.MONTH, 1);
}
// ----------------- Fix for LANG-440 ---------------------- START ---------------
} else if (field == Calendar.AM_PM) {
// This is a special case
// If the time is 0, we round up to 12, otherwise
// we subtract 12 hours and add 1 day
if (val.get(Calendar.HOUR_OF_DAY) == 0) {
val.add(Calendar.HOUR_OF_DAY, 12);
} else {
val.add(Calendar.HOUR_OF_DAY, -12);
val.add(Calendar.DATE, 1);
}
// ----------------- Fix for LANG-440 ---------------------- END ---------------
} else {
//We need at add one to this field since the
// last number causes us to round up
val.add(fields[i][0], 1);
}
}
return;
}
}
//We have various fields that are not easy roundings
int offset = 0;
boolean offsetSet = false;
//These are special types of fields that require different rounding rules
switch (field) {
case DateUtils.SEMI_MONTH:
if (fields[i][0] == Calendar.DATE) {
//If we're going to drop the DATE field's value,
// we want to do this our own way.
//We need to subtrace 1 since the date has a minimum of 1
offset = val.get(Calendar.DATE) - 1;
//If we're above 15 days adjustment, that means we're in the
// bottom half of the month and should stay accordingly.
if (offset >= 15) {
offset -= 15;
}
//Record whether we're in the top or bottom half of that range
roundUp = offset > 7;
offsetSet = true;
}
break;
case Calendar.AM_PM:
if (fields[i][0] == Calendar.HOUR_OF_DAY) {
//If we're going to drop the HOUR field's value,
// we want to do this our own way.
offset = val.get(Calendar.HOUR_OF_DAY);
if (offset >= 12) {
offset -= 12;
}
roundUp = offset >= 6;
offsetSet = true;
}
break;
}
if (!offsetSet) {
int min = val.getActualMinimum(fields[i][0]);
int max = val.getActualMaximum(fields[i][0]);
//Calculate the offset from the minimum allowed value
offset = val.get(fields[i][0]) - min;
//Set roundUp if this is more than half way between the minimum and maximum
roundUp = offset > ((max - min) / 2);
}
//We need to remove this field
if (offset != 0) {
val.set(fields[i][0], val.get(fields[i][0]) - offset);
}
}
throw new IllegalArgumentException("The field " + field + " is not supported");
}
//-----------------------------------------------------------------------
/**
* This constructs an Iterator
over each day in a date
* range defined by a focus date and range style.
*
* For instance, passing Thursday, July 4, 2002 and a
* RANGE_MONTH_SUNDAY
will return an Iterator
* that starts with Sunday, June 30, 2002 and ends with Saturday, August 3,
* 2002, returning a Calendar instance for each intermediate day.
*
* This method provides an iterator that returns Calendar objects.
* The days are progressed using {@link Calendar#add(int, int)}.
*
* @param focus the date to work with, not null
* @param rangeStyle the style constant to use. Must be one of
* {@link DateUtils#RANGE_MONTH_SUNDAY},
* {@link DateUtils#RANGE_MONTH_MONDAY},
* {@link DateUtils#RANGE_WEEK_SUNDAY},
* {@link DateUtils#RANGE_WEEK_MONDAY},
* {@link DateUtils#RANGE_WEEK_RELATIVE},
* {@link DateUtils#RANGE_WEEK_CENTER}
* @return the date iterator, which always returns Calendar instances
* @throws IllegalArgumentException if the date is null
* @throws IllegalArgumentException if the rangeStyle is invalid
*/
public static Iterator iterator(Date focus, int rangeStyle) {
if (focus == null) {
throw new IllegalArgumentException("The date must not be null");
}
Calendar gval = Calendar.getInstance();
gval.setTime(focus);
return iterator(gval, rangeStyle);
}
/**
* This constructs an Iterator
over each day in a date
* range defined by a focus date and range style.
*
* For instance, passing Thursday, July 4, 2002 and a
* RANGE_MONTH_SUNDAY
will return an Iterator
* that starts with Sunday, June 30, 2002 and ends with Saturday, August 3,
* 2002, returning a Calendar instance for each intermediate day.
*
* This method provides an iterator that returns Calendar objects.
* The days are progressed using {@link Calendar#add(int, int)}.
*
* @param focus the date to work with
* @param rangeStyle the style constant to use. Must be one of
* {@link DateUtils#RANGE_MONTH_SUNDAY},
* {@link DateUtils#RANGE_MONTH_MONDAY},
* {@link DateUtils#RANGE_WEEK_SUNDAY},
* {@link DateUtils#RANGE_WEEK_MONDAY},
* {@link DateUtils#RANGE_WEEK_RELATIVE},
* {@link DateUtils#RANGE_WEEK_CENTER}
* @return the date iterator
* @throws IllegalArgumentException if the date is null
* @throws IllegalArgumentException if the rangeStyle is invalid
*/
public static Iterator iterator(Calendar focus, int rangeStyle) {
if (focus == null) {
throw new IllegalArgumentException("The date must not be null");
}
Calendar start = null;
Calendar end = null;
int startCutoff = Calendar.SUNDAY;
int endCutoff = Calendar.SATURDAY;
switch (rangeStyle) {
case RANGE_MONTH_SUNDAY:
case RANGE_MONTH_MONDAY:
//Set start to the first of the month
start = truncate(focus, Calendar.MONTH);
//Set end to the last of the month
end = (Calendar) start.clone();
end.add(Calendar.MONTH, 1);
end.add(Calendar.DATE, -1);
//Loop start back to the previous sunday or monday
if (rangeStyle == RANGE_MONTH_MONDAY) {
startCutoff = Calendar.MONDAY;
endCutoff = Calendar.SUNDAY;
}
break;
case RANGE_WEEK_SUNDAY:
case RANGE_WEEK_MONDAY:
case RANGE_WEEK_RELATIVE:
case RANGE_WEEK_CENTER:
//Set start and end to the current date
start = truncate(focus, Calendar.DATE);
end = truncate(focus, Calendar.DATE);
switch (rangeStyle) {
case RANGE_WEEK_SUNDAY:
//already set by default
break;
case RANGE_WEEK_MONDAY:
startCutoff = Calendar.MONDAY;
endCutoff = Calendar.SUNDAY;
break;
case RANGE_WEEK_RELATIVE:
startCutoff = focus.get(Calendar.DAY_OF_WEEK);
endCutoff = startCutoff - 1;
break;
case RANGE_WEEK_CENTER:
startCutoff = focus.get(Calendar.DAY_OF_WEEK) - 3;
endCutoff = focus.get(Calendar.DAY_OF_WEEK) + 3;
break;
}
break;
default:
throw new IllegalArgumentException("The range style " + rangeStyle + " is not valid.");
}
if (startCutoff < Calendar.SUNDAY) {
startCutoff += 7;
}
if (startCutoff > Calendar.SATURDAY) {
startCutoff -= 7;
}
if (endCutoff < Calendar.SUNDAY) {
endCutoff += 7;
}
if (endCutoff > Calendar.SATURDAY) {
endCutoff -= 7;
}
while (start.get(Calendar.DAY_OF_WEEK) != startCutoff) {
start.add(Calendar.DATE, -1);
}
while (end.get(Calendar.DAY_OF_WEEK) != endCutoff) {
end.add(Calendar.DATE, 1);
}
return new DateIterator(start, end);
}
/**
* This constructs an Iterator
over each day in a date
* range defined by a focus date and range style.
*
* For instance, passing Thursday, July 4, 2002 and a
* RANGE_MONTH_SUNDAY
will return an Iterator
* that starts with Sunday, June 30, 2002 and ends with Saturday, August 3,
* 2002, returning a Calendar instance for each intermediate day.
*
* @param focus the date to work with, either
* Date
or Calendar
* @param rangeStyle the style constant to use. Must be one of the range
* styles listed for the {@link #iterator(Calendar, int)} method.
* @return the date iterator
* @throws IllegalArgumentException if the date
* is null
* @throws ClassCastException if the object type is
* not a Date
or Calendar
*/
public static Iterator iterator(Object focus, int rangeStyle) {
if (focus == null) {
throw new IllegalArgumentException("The date must not be null");
}
if (focus instanceof Date) {
return iterator((Date) focus, rangeStyle);
} else if (focus instanceof Calendar) {
return iterator((Calendar) focus, rangeStyle);
} else {
throw new ClassCastException("Could not iterate based on " + focus);
}
}
/**
* Returns the number of milliseconds within the
* fragment. All datefields greater than the fragment will be ignored.
*
* Asking the milliseconds of any date will only return the number of milliseconds
* of the current second (resulting in a number between 0 and 999). This
* method will retrieve the number of milliseconds for any fragment.
* For example, if you want to calculate the number of milliseconds past today,
* your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will
* be all milliseconds of the past hour(s), minutes(s) and second(s).
*
* Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
* Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
* Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
* A fragment less than or equal to a SECOND field will return 0.
*
*
*
* - January 1, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538
* - January 6, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538
* - January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10538 (10*1000 + 538)
* - January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
* (a millisecond cannot be split in milliseconds)
*
*
*
* @param date the date to work with, not null
* @param fragment the Calendar field part of date to calculate
* @return number of milliseconds within the fragment of date
* @throws IllegalArgumentException if the date is null
or
* fragment is not supported
* @since 2.4
*/
public static long getFragmentInMilliseconds(Date date, int fragment) {
return getFragment(date, fragment, Calendar.MILLISECOND);
}
/**
* Returns the number of seconds within the
* fragment. All datefields greater than the fragment will be ignored.
*
* Asking the seconds of any date will only return the number of seconds
* of the current minute (resulting in a number between 0 and 59). This
* method will retrieve the number of seconds for any fragment.
* For example, if you want to calculate the number of seconds past today,
* your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will
* be all seconds of the past hour(s) and minutes(s).
*
* Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
* Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
* Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
* A fragment less than or equal to a SECOND field will return 0.
*
*
*
* - January 1, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10
* (equivalent to deprecated date.getSeconds())
* - January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10
* (equivalent to deprecated date.getSeconds())
* - January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 26110
* (7*3600 + 15*60 + 10)
* - January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
* (a millisecond cannot be split in seconds)
*
*
*
* @param date the date to work with, not null
* @param fragment the Calendar field part of date to calculate
* @return number of seconds within the fragment of date
* @throws IllegalArgumentException if the date is null
or
* fragment is not supported
* @since 2.4
*/
public static long getFragmentInSeconds(Date date, int fragment) {
return getFragment(date, fragment, Calendar.SECOND);
}
/**
* Returns the number of minutes within the
* fragment. All datefields greater than the fragment will be ignored.
*
* Asking the minutes of any date will only return the number of minutes
* of the current hour (resulting in a number between 0 and 59). This
* method will retrieve the number of minutes for any fragment.
* For example, if you want to calculate the number of minutes past this month,
* your fragment is Calendar.MONTH. The result will be all minutes of the
* past day(s) and hour(s).
*
* Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
* Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
* Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
* A fragment less than or equal to a MINUTE field will return 0.
*
*
*
* - January 1, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15
* (equivalent to deprecated date.getMinutes())
* - January 6, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15
* (equivalent to deprecated date.getMinutes())
* - January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 15
* - January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 435 (7*60 + 15)
* - January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
* (a millisecond cannot be split in minutes)
*
*
*
* @param date the date to work with, not null
* @param fragment the Calendar field part of date to calculate
* @return number of minutes within the fragment of date
* @throws IllegalArgumentException if the date is null
or
* fragment is not supported
* @since 2.4
*/
public static long getFragmentInMinutes(Date date, int fragment) {
return getFragment(date, fragment, Calendar.MINUTE);
}
/**
* Returns the number of hours within the
* fragment. All datefields greater than the fragment will be ignored.
*
* Asking the hours of any date will only return the number of hours
* of the current day (resulting in a number between 0 and 23). This
* method will retrieve the number of hours for any fragment.
* For example, if you want to calculate the number of hours past this month,
* your fragment is Calendar.MONTH. The result will be all hours of the
* past day(s).
*
* Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
* Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
* Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
* A fragment less than or equal to a HOUR field will return 0.
*
*
*
* - January 1, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7
* (equivalent to deprecated date.getHours())
* - January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7
* (equivalent to deprecated date.getHours())
* - January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 7
* - January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 127 (5*24 + 7)
* - January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
* (a millisecond cannot be split in hours)
*
*
*
* @param date the date to work with, not null
* @param fragment the Calendar field part of date to calculate
* @return number of hours within the fragment of date
* @throws IllegalArgumentException if the date is null
or
* fragment is not supported
* @since 2.4
*/
public static long getFragmentInHours(Date date, int fragment) {
return getFragment(date, fragment, Calendar.HOUR_OF_DAY);
}
/**
* Returns the number of days within the
* fragment. All datefields greater than the fragment will be ignored.
*
* Asking the days of any date will only return the number of days
* of the current month (resulting in a number between 1 and 31). This
* method will retrieve the number of days for any fragment.
* For example, if you want to calculate the number of days past this year,
* your fragment is Calendar.YEAR. The result will be all days of the
* past month(s).
*
* Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
* Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
* Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
* A fragment less than or equal to a DAY field will return 0.
*
*
*
* - January 28, 2008 with Calendar.MONTH as fragment will return 28
* (equivalent to deprecated date.getDay())
* - February 28, 2008 with Calendar.MONTH as fragment will return 28
* (equivalent to deprecated date.getDay())
* - January 28, 2008 with Calendar.YEAR as fragment will return 28
* - February 28, 2008 with Calendar.YEAR as fragment will return 59
* - January 28, 2008 with Calendar.MILLISECOND as fragment will return 0
* (a millisecond cannot be split in days)
*
*
*
* @param date the date to work with, not null
* @param fragment the Calendar field part of date to calculate
* @return number of days within the fragment of date
* @throws IllegalArgumentException if the date is null
or
* fragment is not supported
* @since 2.4
*/
public static long getFragmentInDays(Date date, int fragment) {
return getFragment(date, fragment, Calendar.DAY_OF_YEAR);
}
/**
* Returns the number of milliseconds within the
* fragment. All datefields greater than the fragment will be ignored.
*
* Asking the milliseconds of any date will only return the number of milliseconds
* of the current second (resulting in a number between 0 and 999). This
* method will retrieve the number of milliseconds for any fragment.
* For example, if you want to calculate the number of seconds past today,
* your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will
* be all seconds of the past hour(s), minutes(s) and second(s).
*
* Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
* Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
* Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
* A fragment less than or equal to a MILLISECOND field will return 0.
*
*
*
* - January 1, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538
* (equivalent to calendar.get(Calendar.MILLISECOND))
* - January 6, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538
* (equivalent to calendar.get(Calendar.MILLISECOND))
* - January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10538
* (10*1000 + 538)
* - January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
* (a millisecond cannot be split in milliseconds)
*
*
*
* @param calendar the calendar to work with, not null
* @param fragment the Calendar field part of calendar to calculate
* @return number of milliseconds within the fragment of date
* @throws IllegalArgumentException if the date is null
or
* fragment is not supported
* @since 2.4
*/
public static long getFragmentInMilliseconds(Calendar calendar, int fragment) {
return getFragment(calendar, fragment, Calendar.MILLISECOND);
}
/**
* Returns the number of seconds within the
* fragment. All datefields greater than the fragment will be ignored.
*
* Asking the seconds of any date will only return the number of seconds
* of the current minute (resulting in a number between 0 and 59). This
* method will retrieve the number of seconds for any fragment.
* For example, if you want to calculate the number of seconds past today,
* your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will
* be all seconds of the past hour(s) and minutes(s).
*
* Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
* Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
* Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
* A fragment less than or equal to a SECOND field will return 0.
*
*
*
* - January 1, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10
* (equivalent to calendar.get(Calendar.SECOND))
* - January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10
* (equivalent to calendar.get(Calendar.SECOND))
* - January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 26110
* (7*3600 + 15*60 + 10)
* - January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
* (a millisecond cannot be split in seconds)
*
*
*
* @param calendar the calendar to work with, not null
* @param fragment the Calendar field part of calendar to calculate
* @return number of seconds within the fragment of date
* @throws IllegalArgumentException if the date is null
or
* fragment is not supported
* @since 2.4
*/
public static long getFragmentInSeconds(Calendar calendar, int fragment) {
return getFragment(calendar, fragment, Calendar.SECOND);
}
/**
* Returns the number of minutes within the
* fragment. All datefields greater than the fragment will be ignored.
*
* Asking the minutes of any date will only return the number of minutes
* of the current hour (resulting in a number between 0 and 59). This
* method will retrieve the number of minutes for any fragment.
* For example, if you want to calculate the number of minutes past this month,
* your fragment is Calendar.MONTH. The result will be all minutes of the
* past day(s) and hour(s).
*
* Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
* Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
* Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
* A fragment less than or equal to a MINUTE field will return 0.
*
*
*
* - January 1, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15
* (equivalent to calendar.get(Calendar.MINUTES))
* - January 6, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15
* (equivalent to calendar.get(Calendar.MINUTES))
* - January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 15
* - January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 435 (7*60 + 15)
* - January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
* (a millisecond cannot be split in minutes)
*
*
*
* @param calendar the calendar to work with, not null
* @param fragment the Calendar field part of calendar to calculate
* @return number of minutes within the fragment of date
* @throws IllegalArgumentException if the date is null
or
* fragment is not supported
* @since 2.4
*/
public static long getFragmentInMinutes(Calendar calendar, int fragment) {
return getFragment(calendar, fragment, Calendar.MINUTE);
}
/**
* Returns the number of hours within the
* fragment. All datefields greater than the fragment will be ignored.
*
* Asking the hours of any date will only return the number of hours
* of the current day (resulting in a number between 0 and 23). This
* method will retrieve the number of hours for any fragment.
* For example, if you want to calculate the number of hours past this month,
* your fragment is Calendar.MONTH. The result will be all hours of the
* past day(s).
*
* Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
* Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
* Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
* A fragment less than or equal to a HOUR field will return 0.
*
*
*
* - January 1, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7
* (equivalent to calendar.get(Calendar.HOUR_OF_DAY))
* - January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7
* (equivalent to calendar.get(Calendar.HOUR_OF_DAY))
* - January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 7
* - January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 127 (5*24 + 7)
* - January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
* (a millisecond cannot be split in hours)
*
*
*
* @param calendar the calendar to work with, not null
* @param fragment the Calendar field part of calendar to calculate
* @return number of hours within the fragment of date
* @throws IllegalArgumentException if the date is null
or
* fragment is not supported
* @since 2.4
*/
public static long getFragmentInHours(Calendar calendar, int fragment) {
return getFragment(calendar, fragment, Calendar.HOUR_OF_DAY);
}
/**
* Returns the number of days within the
* fragment. All datefields greater than the fragment will be ignored.
*
* Asking the days of any date will only return the number of days
* of the current month (resulting in a number between 1 and 31). This
* method will retrieve the number of days for any fragment.
* For example, if you want to calculate the number of days past this year,
* your fragment is Calendar.YEAR. The result will be all days of the
* past month(s).
*
* Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
* Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
* Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
* A fragment less than or equal to a DAY field will return 0.
*
*
*
* - January 28, 2008 with Calendar.MONTH as fragment will return 28
* (equivalent to calendar.get(Calendar.DAY_OF_MONTH))
* - February 28, 2008 with Calendar.MONTH as fragment will return 28
* (equivalent to calendar.get(Calendar.DAY_OF_MONTH))
* - January 28, 2008 with Calendar.YEAR as fragment will return 28
* (equivalent to calendar.get(Calendar.DAY_OF_YEAR))
* - February 28, 2008 with Calendar.YEAR as fragment will return 59
* (equivalent to calendar.get(Calendar.DAY_OF_YEAR))
* - January 28, 2008 with Calendar.MILLISECOND as fragment will return 0
* (a millisecond cannot be split in days)
*
*
*
* @param calendar the calendar to work with, not null
* @param fragment the Calendar field part of calendar to calculate
* @return number of days within the fragment of date
* @throws IllegalArgumentException if the date is null
or
* fragment is not supported
* @since 2.4
*/
public static long getFragmentInDays(Calendar calendar, int fragment) {
return getFragment(calendar, fragment, Calendar.DAY_OF_YEAR);
}
/**
* Date-version for fragment-calculation in any unit
*
* @param date the date to work with, not null
* @param fragment the Calendar field part of date to calculate
* @param unit Calendar field defining the unit
* @return number of units within the fragment of the date
* @throws IllegalArgumentException if the date is null
or
* fragment is not supported
* @since 2.4
*/
private static long getFragment(Date date, int fragment, int unit) {
if(date == null) {
throw new IllegalArgumentException("The date must not be null");
}
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return getFragment(calendar, fragment, unit);
}
/**
* Calendar-version for fragment-calculation in any unit
*
* @param calendar the calendar to work with, not null
* @param fragment the Calendar field part of calendar to calculate
* @param unit Calendar field defining the unit
* @return number of units within the fragment of the calendar
* @throws IllegalArgumentException if the date is null
or
* fragment is not supported
* @since 2.4
*/
private static long getFragment(Calendar calendar, int fragment, int unit) {
if(calendar == null) {
throw new IllegalArgumentException("The date must not be null");
}
long millisPerUnit = getMillisPerUnit(unit);
long result = 0;
// Fragments bigger than a day require a breakdown to days
switch (fragment) {
case Calendar.YEAR:
result += (calendar.get(Calendar.DAY_OF_YEAR) * MILLIS_PER_DAY) / millisPerUnit;
break;
case Calendar.MONTH:
result += (calendar.get(Calendar.DAY_OF_MONTH) * MILLIS_PER_DAY) / millisPerUnit;
break;
}
switch (fragment) {
// Number of days already calculated for these cases
case Calendar.YEAR:
case Calendar.MONTH:
// The rest of the valid cases
case Calendar.DAY_OF_YEAR:
case Calendar.DATE:
result += (calendar.get(Calendar.HOUR_OF_DAY) * MILLIS_PER_HOUR) / millisPerUnit;
//$FALL-THROUGH$
case Calendar.HOUR_OF_DAY:
result += (calendar.get(Calendar.MINUTE) * MILLIS_PER_MINUTE) / millisPerUnit;
//$FALL-THROUGH$
case Calendar.MINUTE:
result += (calendar.get(Calendar.SECOND) * MILLIS_PER_SECOND) / millisPerUnit;
//$FALL-THROUGH$
case Calendar.SECOND:
result += (calendar.get(Calendar.MILLISECOND) * 1) / millisPerUnit;
break;
case Calendar.MILLISECOND:
break;//never useful
default:
throw new IllegalArgumentException("The fragment " + fragment + " is not supported");
}
return result;
}
/**
* Determines if two calendars are equal up to no more than the specified
* most significant field.
*
* @param cal1 the first calendar, not null
* @param cal2 the second calendar, not null
* @param field the field from Calendar
* @return true
if equal; otherwise false
* @throws IllegalArgumentException if any argument is null
* @see #truncate(Calendar, int)
* @see #truncatedEquals(Date, Date, int)
* @since 2.6
*/
public static boolean truncatedEquals(Calendar cal1, Calendar cal2, int field) {
return truncatedCompareTo(cal1, cal2, field) == 0;
}
/**
* Determines if two dates are equal up to no more than the specified
* most significant field.
*
* @param date1 the first date, not null
* @param date2 the second date, not null
* @param field the field from Calendar
* @return true
if equal; otherwise false
* @throws IllegalArgumentException if any argument is null
* @see #truncate(Date, int)
* @see #truncatedEquals(Calendar, Calendar, int)
* @since 2.6
*/
public static boolean truncatedEquals(Date date1, Date date2, int field) {
return truncatedCompareTo(date1, date2, field) == 0;
}
/**
* Determines how two calendars compare up to no more than the specified
* most significant field.
*
* @param cal1 the first calendar, not null
* @param cal2 the second calendar, not null
* @param field the field from Calendar
* @return a negative integer, zero, or a positive integer as the first
* calendar is less than, equal to, or greater than the second.
* @throws IllegalArgumentException if any argument is null
* @see #truncate(Calendar, int)
* @see #truncatedCompareTo(Date, Date, int)
* @since 2.6
*/
public static int truncatedCompareTo(Calendar cal1, Calendar cal2, int field) {
Calendar truncatedCal1 = truncate(cal1, field);
Calendar truncatedCal2 = truncate(cal2, field);
return truncatedCal1.getTime().compareTo(truncatedCal2.getTime());
}
/**
* Determines how two dates compare up to no more than the specified
* most significant field.
*
* @param date1 the first date, not null
* @param date2 the second date, not null
* @param field the field from Calendar
* @return a negative integer, zero, or a positive integer as the first
* date is less than, equal to, or greater than the second.
* @throws IllegalArgumentException if any argument is null
* @see #truncate(Calendar, int)
* @see #truncatedCompareTo(Date, Date, int)
* @since 2.6
*/
public static int truncatedCompareTo(Date date1, Date date2, int field) {
Date truncatedDate1 = truncate(date1, field);
Date truncatedDate2 = truncate(date2, field);
return truncatedDate1.compareTo(truncatedDate2);
}
/**
* Returns the number of millis of a datefield, if this is a constant value
*
* @param unit A Calendar field which is a valid unit for a fragment
* @return number of millis
* @throws IllegalArgumentException if date can't be represented in millisenconds
* @since 2.4
*/
private static long getMillisPerUnit(int unit) {
long result = Long.MAX_VALUE;
switch (unit) {
case Calendar.DAY_OF_YEAR:
case Calendar.DATE:
result = MILLIS_PER_DAY;
break;
case Calendar.HOUR_OF_DAY:
result = MILLIS_PER_HOUR;
break;
case Calendar.MINUTE:
result = MILLIS_PER_MINUTE;
break;
case Calendar.SECOND:
result = MILLIS_PER_SECOND;
break;
case Calendar.MILLISECOND:
result = 1;
break;
default: throw new IllegalArgumentException("The unit " + unit + " cannot be represented is milleseconds");
}
return result;
}
/**
* Date iterator.
*/
static class DateIterator implements Iterator {
private final Calendar endFinal;
private final Calendar spot;
/**
* Constructs a DateIterator that ranges from one date to another.
*
* @param startFinal start date (inclusive)
* @param endFinal end date (not inclusive)
*/
DateIterator(Calendar startFinal, Calendar endFinal) {
super();
this.endFinal = endFinal;
spot = startFinal;
spot.add(Calendar.DATE, -1);
}
/**
* Has the iterator not reached the end date yet?
*
* @return true
if the iterator has yet to reach the end date
*/
public boolean hasNext() {
return spot.before(endFinal);
}
/**
* Return the next calendar in the iteration
*
* @return Object calendar for the next date
*/
public Object next() {
if (spot.equals(endFinal)) {
throw new NoSuchElementException();
}
spot.add(Calendar.DATE, 1);
return spot.clone();
}
/**
* Always throws UnsupportedOperationException.
*
* @throws UnsupportedOperationException
* @see java.util.Iterator#remove()
*/
public void remove() {
throw new UnsupportedOperationException();
}
}
//-------------------------------------------------------------------------
// Deprecated int constants
// TODO: Remove in 3.0
/**
* Number of milliseconds in a standard second.
*
* @deprecated Use MILLIS_PER_SECOND. This will be removed in Commons Lang 3.0.
*/
public static final int MILLIS_IN_SECOND = 1000;
/**
* Number of milliseconds in a standard minute.
*
* @deprecated Use MILLIS_PER_MINUTE. This will be removed in Commons Lang 3.0.
*/
public static final int MILLIS_IN_MINUTE = 60 * 1000;
/**
* Number of milliseconds in a standard hour.
*
* @deprecated Use MILLIS_PER_HOUR. This will be removed in Commons Lang 3.0.
*/
public static final int MILLIS_IN_HOUR = 60 * 60 * 1000;
/**
* Number of milliseconds in a standard day.
*
* @deprecated Use MILLIS_PER_DAY. This will be removed in Commons Lang 3.0.
*/
public static final int MILLIS_IN_DAY = 24 * 60 * 60 * 1000;
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/time/DurationFormatUtils.java 100644 0 0 63243 11513702443 26537 0 ustar 0 0 /*
* 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.lang.time;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.text.StrBuilder;
/**
* Duration formatting utilities and constants. The following table describes the tokens
* used in the pattern language for formatting.
*
* character duration element
* y years
* M months
* d days
* H hours
* m minutes
* s seconds
* S milliseconds
*
*
* @author Apache Software Foundation
* @author Apache Ant - DateUtils
* @author Stephane Bailliez
* @author Stefan Bodewig
* @author Gary Gregory
* @since 2.1
* @version $Id: DurationFormatUtils.java 1057072 2011-01-10 01:55:57Z niallp $
*/
public class DurationFormatUtils {
/**
* DurationFormatUtils instances should NOT be constructed in standard programming.
*
* This constructor is public to permit tools that require a JavaBean instance
* to operate.
*/
public DurationFormatUtils() {
super();
}
/**
* Pattern used with FastDateFormat
and SimpleDateFormat
* for the ISO8601 period format used in durations.
*
* @see org.apache.commons.lang.time.FastDateFormat
* @see java.text.SimpleDateFormat
*/
public static final String ISO_EXTENDED_FORMAT_PATTERN = "'P'yyyy'Y'M'M'd'DT'H'H'm'M's.S'S'";
//-----------------------------------------------------------------------
/**
* Formats the time gap as a string.
*
* The format used is ISO8601-like:
* H:m:s.S.
*
* @param durationMillis the duration to format
* @return the time as a String
*/
public static String formatDurationHMS(long durationMillis) {
return formatDuration(durationMillis, "H:mm:ss.SSS");
}
/**
* Formats the time gap as a string.
*
* The format used is the ISO8601 period format.
*
* This method formats durations using the days and lower fields of the
* ISO format pattern, such as P7D6TH5M4.321S.
*
* @param durationMillis the duration to format
* @return the time as a String
*/
public static String formatDurationISO(long durationMillis) {
return formatDuration(durationMillis, ISO_EXTENDED_FORMAT_PATTERN, false);
}
/**
* Formats the time gap as a string, using the specified format, and padding with zeros and
* using the default timezone.
*
* This method formats durations using the days and lower fields of the
* format pattern. Months and larger are not used.
*
* @param durationMillis the duration to format
* @param format the way in which to format the duration
* @return the time as a String
*/
public static String formatDuration(long durationMillis, String format) {
return formatDuration(durationMillis, format, true);
}
/**
* Formats the time gap as a string, using the specified format.
* Padding the left hand side of numbers with zeroes is optional and
* the timezone may be specified.
*
* This method formats durations using the days and lower fields of the
* format pattern. Months and larger are not used.
*
* @param durationMillis the duration to format
* @param format the way in which to format the duration
* @param padWithZeros whether to pad the left hand side of numbers with 0's
* @return the time as a String
*/
public static String formatDuration(long durationMillis, String format, boolean padWithZeros) {
Token[] tokens = lexx(format);
int days = 0;
int hours = 0;
int minutes = 0;
int seconds = 0;
int milliseconds = 0;
if (Token.containsTokenWithValue(tokens, d) ) {
days = (int) (durationMillis / DateUtils.MILLIS_PER_DAY);
durationMillis = durationMillis - (days * DateUtils.MILLIS_PER_DAY);
}
if (Token.containsTokenWithValue(tokens, H) ) {
hours = (int) (durationMillis / DateUtils.MILLIS_PER_HOUR);
durationMillis = durationMillis - (hours * DateUtils.MILLIS_PER_HOUR);
}
if (Token.containsTokenWithValue(tokens, m) ) {
minutes = (int) (durationMillis / DateUtils.MILLIS_PER_MINUTE);
durationMillis = durationMillis - (minutes * DateUtils.MILLIS_PER_MINUTE);
}
if (Token.containsTokenWithValue(tokens, s) ) {
seconds = (int) (durationMillis / DateUtils.MILLIS_PER_SECOND);
durationMillis = durationMillis - (seconds * DateUtils.MILLIS_PER_SECOND);
}
if (Token.containsTokenWithValue(tokens, S) ) {
milliseconds = (int) durationMillis;
}
return format(tokens, 0, 0, days, hours, minutes, seconds, milliseconds, padWithZeros);
}
/**
* Formats an elapsed time into a plurialization correct string.
*
* This method formats durations using the days and lower fields of the
* format pattern. Months and larger are not used.
*
* @param durationMillis the elapsed time to report in milliseconds
* @param suppressLeadingZeroElements suppresses leading 0 elements
* @param suppressTrailingZeroElements suppresses trailing 0 elements
* @return the formatted text in days/hours/minutes/seconds
*/
public static String formatDurationWords(
long durationMillis,
boolean suppressLeadingZeroElements,
boolean suppressTrailingZeroElements) {
// This method is generally replacable by the format method, but
// there are a series of tweaks and special cases that require
// trickery to replicate.
String duration = formatDuration(durationMillis, "d' days 'H' hours 'm' minutes 's' seconds'");
if (suppressLeadingZeroElements) {
// this is a temporary marker on the front. Like ^ in regexp.
duration = " " + duration;
String tmp = StringUtils.replaceOnce(duration, " 0 days", "");
if (tmp.length() != duration.length()) {
duration = tmp;
tmp = StringUtils.replaceOnce(duration, " 0 hours", "");
if (tmp.length() != duration.length()) {
duration = tmp;
tmp = StringUtils.replaceOnce(duration, " 0 minutes", "");
duration = tmp;
if (tmp.length() != duration.length()) {
duration = StringUtils.replaceOnce(tmp, " 0 seconds", "");
}
}
}
if (duration.length() != 0) {
// strip the space off again
duration = duration.substring(1);
}
}
if (suppressTrailingZeroElements) {
String tmp = StringUtils.replaceOnce(duration, " 0 seconds", "");
if (tmp.length() != duration.length()) {
duration = tmp;
tmp = StringUtils.replaceOnce(duration, " 0 minutes", "");
if (tmp.length() != duration.length()) {
duration = tmp;
tmp = StringUtils.replaceOnce(duration, " 0 hours", "");
if (tmp.length() != duration.length()) {
duration = StringUtils.replaceOnce(tmp, " 0 days", "");
}
}
}
}
// handle plurals
duration = " " + duration;
duration = StringUtils.replaceOnce(duration, " 1 seconds", " 1 second");
duration = StringUtils.replaceOnce(duration, " 1 minutes", " 1 minute");
duration = StringUtils.replaceOnce(duration, " 1 hours", " 1 hour");
duration = StringUtils.replaceOnce(duration, " 1 days", " 1 day");
return duration.trim();
}
//-----------------------------------------------------------------------
/**
* Formats the time gap as a string.
*
* The format used is the ISO8601 period format.
*
* @param startMillis the start of the duration to format
* @param endMillis the end of the duration to format
* @return the time as a String
*/
public static String formatPeriodISO(long startMillis, long endMillis) {
return formatPeriod(startMillis, endMillis, ISO_EXTENDED_FORMAT_PATTERN, false, TimeZone.getDefault());
}
/**
* Formats the time gap as a string, using the specified format.
* Padding the left hand side of numbers with zeroes is optional.
*
* @param startMillis the start of the duration
* @param endMillis the end of the duration
* @param format the way in which to format the duration
* @return the time as a String
*/
public static String formatPeriod(long startMillis, long endMillis, String format) {
return formatPeriod(startMillis, endMillis, format, true, TimeZone.getDefault());
}
/**
*
Formats the time gap as a string, using the specified format.
* Padding the left hand side of numbers with zeroes is optional and
* the timezone may be specified.
*
* When calculating the difference between months/days, it chooses to
* calculate months first. So when working out the number of months and
* days between January 15th and March 10th, it choose 1 month and
* 23 days gained by choosing January->February = 1 month and then
* calculating days forwards, and not the 1 month and 26 days gained by
* choosing March -> February = 1 month and then calculating days
* backwards.
*
* For more control, the Joda-Time
* library is recommended.
*
* @param startMillis the start of the duration
* @param endMillis the end of the duration
* @param format the way in which to format the duration
* @param padWithZeros whether to pad the left hand side of numbers with 0's
* @param timezone the millis are defined in
* @return the time as a String
*/
public static String formatPeriod(long startMillis, long endMillis, String format, boolean padWithZeros,
TimeZone timezone) {
// Used to optimise for differences under 28 days and
// called formatDuration(millis, format); however this did not work
// over leap years.
// TODO: Compare performance to see if anything was lost by
// losing this optimisation.
Token[] tokens = lexx(format);
// timezones get funky around 0, so normalizing everything to GMT
// stops the hours being off
Calendar start = Calendar.getInstance(timezone);
start.setTime(new Date(startMillis));
Calendar end = Calendar.getInstance(timezone);
end.setTime(new Date(endMillis));
// initial estimates
int milliseconds = end.get(Calendar.MILLISECOND) - start.get(Calendar.MILLISECOND);
int seconds = end.get(Calendar.SECOND) - start.get(Calendar.SECOND);
int minutes = end.get(Calendar.MINUTE) - start.get(Calendar.MINUTE);
int hours = end.get(Calendar.HOUR_OF_DAY) - start.get(Calendar.HOUR_OF_DAY);
int days = end.get(Calendar.DAY_OF_MONTH) - start.get(Calendar.DAY_OF_MONTH);
int months = end.get(Calendar.MONTH) - start.get(Calendar.MONTH);
int years = end.get(Calendar.YEAR) - start.get(Calendar.YEAR);
// each initial estimate is adjusted in case it is under 0
while (milliseconds < 0) {
milliseconds += 1000;
seconds -= 1;
}
while (seconds < 0) {
seconds += 60;
minutes -= 1;
}
while (minutes < 0) {
minutes += 60;
hours -= 1;
}
while (hours < 0) {
hours += 24;
days -= 1;
}
if (Token.containsTokenWithValue(tokens, M)) {
while (days < 0) {
days += start.getActualMaximum(Calendar.DAY_OF_MONTH);
months -= 1;
start.add(Calendar.MONTH, 1);
}
while (months < 0) {
months += 12;
years -= 1;
}
if (!Token.containsTokenWithValue(tokens, y) && years != 0) {
while (years != 0) {
months += 12 * years;
years = 0;
}
}
} else {
// there are no M's in the format string
if( !Token.containsTokenWithValue(tokens, y) ) {
int target = end.get(Calendar.YEAR);
if (months < 0) {
// target is end-year -1
target -= 1;
}
while ( (start.get(Calendar.YEAR) != target)) {
days += start.getActualMaximum(Calendar.DAY_OF_YEAR) - start.get(Calendar.DAY_OF_YEAR);
// Not sure I grok why this is needed, but the brutal tests show it is
if(start instanceof GregorianCalendar) {
if( (start.get(Calendar.MONTH) == Calendar.FEBRUARY) &&
(start.get(Calendar.DAY_OF_MONTH) == 29 ) )
{
days += 1;
}
}
start.add(Calendar.YEAR, 1);
days += start.get(Calendar.DAY_OF_YEAR);
}
years = 0;
}
while( start.get(Calendar.MONTH) != end.get(Calendar.MONTH) ) {
days += start.getActualMaximum(Calendar.DAY_OF_MONTH);
start.add(Calendar.MONTH, 1);
}
months = 0;
while (days < 0) {
days += start.getActualMaximum(Calendar.DAY_OF_MONTH);
months -= 1;
start.add(Calendar.MONTH, 1);
}
}
// The rest of this code adds in values that
// aren't requested. This allows the user to ask for the
// number of months and get the real count and not just 0->11.
if (!Token.containsTokenWithValue(tokens, d)) {
hours += 24 * days;
days = 0;
}
if (!Token.containsTokenWithValue(tokens, H)) {
minutes += 60 * hours;
hours = 0;
}
if (!Token.containsTokenWithValue(tokens, m)) {
seconds += 60 * minutes;
minutes = 0;
}
if (!Token.containsTokenWithValue(tokens, s)) {
milliseconds += 1000 * seconds;
seconds = 0;
}
return format(tokens, years, months, days, hours, minutes, seconds, milliseconds, padWithZeros);
}
//-----------------------------------------------------------------------
/**
* The internal method to do the formatting.
*
* @param tokens the tokens
* @param years the number of years
* @param months the number of months
* @param days the number of days
* @param hours the number of hours
* @param minutes the number of minutes
* @param seconds the number of seconds
* @param milliseconds the number of millis
* @param padWithZeros whether to pad
* @return the formatted string
*/
static String format(Token[] tokens, int years, int months, int days, int hours, int minutes, int seconds,
int milliseconds, boolean padWithZeros) {
StrBuilder buffer = new StrBuilder();
boolean lastOutputSeconds = false;
int sz = tokens.length;
for (int i = 0; i < sz; i++) {
Token token = tokens[i];
Object value = token.getValue();
int count = token.getCount();
if (value instanceof StringBuffer) {
buffer.append(value.toString());
} else {
if (value == y) {
buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(years), count, '0') : Integer
.toString(years));
lastOutputSeconds = false;
} else if (value == M) {
buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(months), count, '0') : Integer
.toString(months));
lastOutputSeconds = false;
} else if (value == d) {
buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(days), count, '0') : Integer
.toString(days));
lastOutputSeconds = false;
} else if (value == H) {
buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(hours), count, '0') : Integer
.toString(hours));
lastOutputSeconds = false;
} else if (value == m) {
buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(minutes), count, '0') : Integer
.toString(minutes));
lastOutputSeconds = false;
} else if (value == s) {
buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(seconds), count, '0') : Integer
.toString(seconds));
lastOutputSeconds = true;
} else if (value == S) {
if (lastOutputSeconds) {
milliseconds += 1000;
String str = padWithZeros
? StringUtils.leftPad(Integer.toString(milliseconds), count, '0')
: Integer.toString(milliseconds);
buffer.append(str.substring(1));
} else {
buffer.append(padWithZeros
? StringUtils.leftPad(Integer.toString(milliseconds), count, '0')
: Integer.toString(milliseconds));
}
lastOutputSeconds = false;
}
}
}
return buffer.toString();
}
static final Object y = "y";
static final Object M = "M";
static final Object d = "d";
static final Object H = "H";
static final Object m = "m";
static final Object s = "s";
static final Object S = "S";
/**
* Parses a classic date format string into Tokens
*
* @param format to parse
* @return array of Token[]
*/
static Token[] lexx(String format) {
char[] array = format.toCharArray();
ArrayList list = new ArrayList(array.length);
boolean inLiteral = false;
StringBuffer buffer = null;
Token previous = null;
int sz = array.length;
for(int i=0; itrue
if contained
*/
static boolean containsTokenWithValue(Token[] tokens, Object value) {
int sz = tokens.length;
for (int i = 0; i < sz; i++) {
if (tokens[i].getValue() == value) {
return true;
}
}
return false;
}
private Object value;
private int count;
/**
* Wraps a token around a value. A value would be something like a 'Y'.
*
* @param value to wrap
*/
Token(Object value) {
this.value = value;
this.count = 1;
}
/**
* Wraps a token around a repeated number of a value, for example it would
* store 'yyyy' as a value for y and a count of 4.
*
* @param value to wrap
* @param count to wrap
*/
Token(Object value, int count) {
this.value = value;
this.count = count;
}
/**
* Adds another one of the value
*/
void increment() {
count++;
}
/**
* Gets the current number of values represented
*
* @return int number of values represented
*/
int getCount() {
return count;
}
/**
* Gets the particular value this token represents.
*
* @return Object value
*/
Object getValue() {
return value;
}
/**
* Supports equality of this Token to another Token.
*
* @param obj2 Object to consider equality of
* @return boolean true
if equal
*/
public boolean equals(Object obj2) {
if (obj2 instanceof Token) {
Token tok2 = (Token) obj2;
if (this.value.getClass() != tok2.value.getClass()) {
return false;
}
if (this.count != tok2.count) {
return false;
}
if (this.value instanceof StringBuffer) {
return this.value.toString().equals(tok2.value.toString());
} else if (this.value instanceof Number) {
return this.value.equals(tok2.value);
} else {
return this.value == tok2.value;
}
}
return false;
}
/**
* Returns a hashcode for the token equal to the
* hashcode for the token's value. Thus 'TT' and 'TTTT'
* will have the same hashcode.
*
* @return The hashcode for the token
*/
public int hashCode() {
return this.value.hashCode();
}
/**
* Represents this token as a String.
*
* @return String representation of the token
*/
public String toString() {
return StringUtils.repeat(this.value.toString(), this.count);
}
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/time/FastDateFormat.java 100644 0 0 162132 11513702443 25441 0 ustar 0 0 /*
* 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.lang.time;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.text.DateFormat;
import java.text.DateFormatSymbols;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang.text.StrBuilder;
/**
* FastDateFormat is a fast and thread-safe version of
* {@link java.text.SimpleDateFormat}.
*
* This class can be used as a direct replacement to
* SimpleDateFormat
in most formatting situations.
* This class is especially useful in multi-threaded server environments.
* SimpleDateFormat
is not thread-safe in any JDK version,
* nor will it be as Sun have closed the bug/RFE.
*
*
* Only formatting is supported, but all patterns are compatible with
* SimpleDateFormat (except time zones - see below).
*
* Java 1.4 introduced a new pattern letter, 'Z'
, to represent
* time zones in RFC822 format (eg. +0800
or -1100
).
* This pattern letter can be used here (on all JDK versions).
*
* In addition, the pattern 'ZZ'
has been made to represent
* ISO8601 full format time zones (eg. +08:00
or -11:00
).
* This introduces a minor incompatibility with Java 1.4, but at a gain of
* useful functionality.
*
* @author Apache Software Foundation
* @author TeaTrove project
* @author Brian S O'Neill
* @author Sean Schofield
* @author Gary Gregory
* @author Nikolay Metchev
* @since 2.0
* @version $Id: FastDateFormat.java 1057072 2011-01-10 01:55:57Z niallp $
*/
public class FastDateFormat extends Format {
// A lot of the speed in this class comes from caching, but some comes
// from the special int to StringBuffer conversion.
//
// The following produces a padded 2 digit number:
// buffer.append((char)(value / 10 + '0'));
// buffer.append((char)(value % 10 + '0'));
//
// Note that the fastest append to StringBuffer is a single char (used here).
// Note that Integer.toString() is not called, the conversion is simply
// taking the value and adding (mathematically) the ASCII value for '0'.
// So, don't change this code! It works and is very fast.
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 1L;
/**
* FULL locale dependent date or time style.
*/
public static final int FULL = DateFormat.FULL;
/**
* LONG locale dependent date or time style.
*/
public static final int LONG = DateFormat.LONG;
/**
* MEDIUM locale dependent date or time style.
*/
public static final int MEDIUM = DateFormat.MEDIUM;
/**
* SHORT locale dependent date or time style.
*/
public static final int SHORT = DateFormat.SHORT;
private static String cDefaultPattern; // lazily initialised by getInstance()
private static final Map cInstanceCache = new HashMap(7);
private static final Map cDateInstanceCache = new HashMap(7);
private static final Map cTimeInstanceCache = new HashMap(7);
private static final Map cDateTimeInstanceCache = new HashMap(7);
private static final Map cTimeZoneDisplayCache = new HashMap(7);
/**
* The pattern.
*/
private final String mPattern;
/**
* The time zone.
*/
private final TimeZone mTimeZone;
/**
* Whether the time zone overrides any on Calendars.
*/
private final boolean mTimeZoneForced;
/**
* The locale.
*/
private final Locale mLocale;
/**
* Whether the locale overrides the default.
*/
private final boolean mLocaleForced;
/**
* The parsed rules.
*/
private transient Rule[] mRules;
/**
* The estimated maximum length.
*/
private transient int mMaxLengthEstimate;
//-----------------------------------------------------------------------
/**
* Gets a formatter instance using the default pattern in the
* default locale.
*
* @return a date/time formatter
*/
public static FastDateFormat getInstance() {
return getInstance(getDefaultPattern(), null, null);
}
/**
* Gets a formatter instance using the specified pattern in the
* default locale.
*
* @param pattern {@link java.text.SimpleDateFormat} compatible
* pattern
* @return a pattern based date/time formatter
* @throws IllegalArgumentException if pattern is invalid
*/
public static FastDateFormat getInstance(String pattern) {
return getInstance(pattern, null, null);
}
/**
* Gets a formatter instance using the specified pattern and
* time zone.
*
* @param pattern {@link java.text.SimpleDateFormat} compatible
* pattern
* @param timeZone optional time zone, overrides time zone of
* formatted date
* @return a pattern based date/time formatter
* @throws IllegalArgumentException if pattern is invalid
*/
public static FastDateFormat getInstance(String pattern, TimeZone timeZone) {
return getInstance(pattern, timeZone, null);
}
/**
* Gets a formatter instance using the specified pattern and
* locale.
*
* @param pattern {@link java.text.SimpleDateFormat} compatible
* pattern
* @param locale optional locale, overrides system locale
* @return a pattern based date/time formatter
* @throws IllegalArgumentException if pattern is invalid
*/
public static FastDateFormat getInstance(String pattern, Locale locale) {
return getInstance(pattern, null, locale);
}
/**
* Gets a formatter instance using the specified pattern, time zone
* and locale.
*
* @param pattern {@link java.text.SimpleDateFormat} compatible
* pattern
* @param timeZone optional time zone, overrides time zone of
* formatted date
* @param locale optional locale, overrides system locale
* @return a pattern based date/time formatter
* @throws IllegalArgumentException if pattern is invalid
* or null
*/
public static synchronized FastDateFormat getInstance(String pattern, TimeZone timeZone, Locale locale) {
FastDateFormat emptyFormat = new FastDateFormat(pattern, timeZone, locale);
FastDateFormat format = (FastDateFormat) cInstanceCache.get(emptyFormat);
if (format == null) {
format = emptyFormat;
format.init(); // convert shell format into usable one
cInstanceCache.put(format, format); // this is OK!
}
return format;
}
//-----------------------------------------------------------------------
/**
* Gets a date formatter instance using the specified style in the
* default time zone and locale.
*
* @param style date style: FULL, LONG, MEDIUM, or SHORT
* @return a localized standard date formatter
* @throws IllegalArgumentException if the Locale has no date
* pattern defined
* @since 2.1
*/
public static FastDateFormat getDateInstance(int style) {
return getDateInstance(style, null, null);
}
/**
* Gets a date formatter instance using the specified style and
* locale in the default time zone.
*
* @param style date style: FULL, LONG, MEDIUM, or SHORT
* @param locale optional locale, overrides system locale
* @return a localized standard date formatter
* @throws IllegalArgumentException if the Locale has no date
* pattern defined
* @since 2.1
*/
public static FastDateFormat getDateInstance(int style, Locale locale) {
return getDateInstance(style, null, locale);
}
/**
* Gets a date formatter instance using the specified style and
* time zone in the default locale.
*
* @param style date style: FULL, LONG, MEDIUM, or SHORT
* @param timeZone optional time zone, overrides time zone of
* formatted date
* @return a localized standard date formatter
* @throws IllegalArgumentException if the Locale has no date
* pattern defined
* @since 2.1
*/
public static FastDateFormat getDateInstance(int style, TimeZone timeZone) {
return getDateInstance(style, timeZone, null);
}
/**
* Gets a date formatter instance using the specified style, time
* zone and locale.
*
* @param style date style: FULL, LONG, MEDIUM, or SHORT
* @param timeZone optional time zone, overrides time zone of
* formatted date
* @param locale optional locale, overrides system locale
* @return a localized standard date formatter
* @throws IllegalArgumentException if the Locale has no date
* pattern defined
*/
public static synchronized FastDateFormat getDateInstance(int style, TimeZone timeZone, Locale locale) {
Object key = new Integer(style);
if (timeZone != null) {
key = new Pair(key, timeZone);
}
if (locale == null) {
locale = Locale.getDefault();
}
key = new Pair(key, locale);
FastDateFormat format = (FastDateFormat) cDateInstanceCache.get(key);
if (format == null) {
try {
SimpleDateFormat formatter = (SimpleDateFormat) DateFormat.getDateInstance(style, locale);
String pattern = formatter.toPattern();
format = getInstance(pattern, timeZone, locale);
cDateInstanceCache.put(key, format);
} catch (ClassCastException ex) {
throw new IllegalArgumentException("No date pattern for locale: " + locale);
}
}
return format;
}
//-----------------------------------------------------------------------
/**
* Gets a time formatter instance using the specified style in the
* default time zone and locale.
*
* @param style time style: FULL, LONG, MEDIUM, or SHORT
* @return a localized standard time formatter
* @throws IllegalArgumentException if the Locale has no time
* pattern defined
* @since 2.1
*/
public static FastDateFormat getTimeInstance(int style) {
return getTimeInstance(style, null, null);
}
/**
* Gets a time formatter instance using the specified style and
* locale in the default time zone.
*
* @param style time style: FULL, LONG, MEDIUM, or SHORT
* @param locale optional locale, overrides system locale
* @return a localized standard time formatter
* @throws IllegalArgumentException if the Locale has no time
* pattern defined
* @since 2.1
*/
public static FastDateFormat getTimeInstance(int style, Locale locale) {
return getTimeInstance(style, null, locale);
}
/**
* Gets a time formatter instance using the specified style and
* time zone in the default locale.
*
* @param style time style: FULL, LONG, MEDIUM, or SHORT
* @param timeZone optional time zone, overrides time zone of
* formatted time
* @return a localized standard time formatter
* @throws IllegalArgumentException if the Locale has no time
* pattern defined
* @since 2.1
*/
public static FastDateFormat getTimeInstance(int style, TimeZone timeZone) {
return getTimeInstance(style, timeZone, null);
}
/**
* Gets a time formatter instance using the specified style, time
* zone and locale.
*
* @param style time style: FULL, LONG, MEDIUM, or SHORT
* @param timeZone optional time zone, overrides time zone of
* formatted time
* @param locale optional locale, overrides system locale
* @return a localized standard time formatter
* @throws IllegalArgumentException if the Locale has no time
* pattern defined
*/
public static synchronized FastDateFormat getTimeInstance(int style, TimeZone timeZone, Locale locale) {
Object key = new Integer(style);
if (timeZone != null) {
key = new Pair(key, timeZone);
}
if (locale != null) {
key = new Pair(key, locale);
}
FastDateFormat format = (FastDateFormat) cTimeInstanceCache.get(key);
if (format == null) {
if (locale == null) {
locale = Locale.getDefault();
}
try {
SimpleDateFormat formatter = (SimpleDateFormat) DateFormat.getTimeInstance(style, locale);
String pattern = formatter.toPattern();
format = getInstance(pattern, timeZone, locale);
cTimeInstanceCache.put(key, format);
} catch (ClassCastException ex) {
throw new IllegalArgumentException("No date pattern for locale: " + locale);
}
}
return format;
}
//-----------------------------------------------------------------------
/**
* Gets a date/time formatter instance using the specified style
* in the default time zone and locale.
*
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
* @return a localized standard date/time formatter
* @throws IllegalArgumentException if the Locale has no date/time
* pattern defined
* @since 2.1
*/
public static FastDateFormat getDateTimeInstance(
int dateStyle, int timeStyle) {
return getDateTimeInstance(dateStyle, timeStyle, null, null);
}
/**
* Gets a date/time formatter instance using the specified style and
* locale in the default time zone.
*
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
* @param locale optional locale, overrides system locale
* @return a localized standard date/time formatter
* @throws IllegalArgumentException if the Locale has no date/time
* pattern defined
* @since 2.1
*/
public static FastDateFormat getDateTimeInstance(
int dateStyle, int timeStyle, Locale locale) {
return getDateTimeInstance(dateStyle, timeStyle, null, locale);
}
/**
* Gets a date/time formatter instance using the specified style and
* time zone in the default locale.
*
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
* @param timeZone optional time zone, overrides time zone of
* formatted date
* @return a localized standard date/time formatter
* @throws IllegalArgumentException if the Locale has no date/time
* pattern defined
* @since 2.1
*/
public static FastDateFormat getDateTimeInstance(
int dateStyle, int timeStyle, TimeZone timeZone) {
return getDateTimeInstance(dateStyle, timeStyle, timeZone, null);
}
/**
* Gets a date/time formatter instance using the specified style,
* time zone and locale.
*
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
* @param timeZone optional time zone, overrides time zone of
* formatted date
* @param locale optional locale, overrides system locale
* @return a localized standard date/time formatter
* @throws IllegalArgumentException if the Locale has no date/time
* pattern defined
*/
public static synchronized FastDateFormat getDateTimeInstance(int dateStyle, int timeStyle, TimeZone timeZone,
Locale locale) {
Object key = new Pair(new Integer(dateStyle), new Integer(timeStyle));
if (timeZone != null) {
key = new Pair(key, timeZone);
}
if (locale == null) {
locale = Locale.getDefault();
}
key = new Pair(key, locale);
FastDateFormat format = (FastDateFormat) cDateTimeInstanceCache.get(key);
if (format == null) {
try {
SimpleDateFormat formatter = (SimpleDateFormat) DateFormat.getDateTimeInstance(dateStyle, timeStyle,
locale);
String pattern = formatter.toPattern();
format = getInstance(pattern, timeZone, locale);
cDateTimeInstanceCache.put(key, format);
} catch (ClassCastException ex) {
throw new IllegalArgumentException("No date time pattern for locale: " + locale);
}
}
return format;
}
//-----------------------------------------------------------------------
/**
* Gets the time zone display name, using a cache for performance.
*
* @param tz the zone to query
* @param daylight true if daylight savings
* @param style the style to use TimeZone.LONG
* or TimeZone.SHORT
* @param locale the locale to use
* @return the textual name of the time zone
*/
static synchronized String getTimeZoneDisplay(TimeZone tz, boolean daylight, int style, Locale locale) {
Object key = new TimeZoneDisplayKey(tz, daylight, style, locale);
String value = (String) cTimeZoneDisplayCache.get(key);
if (value == null) {
// This is a very slow call, so cache the results.
value = tz.getDisplayName(daylight, style, locale);
cTimeZoneDisplayCache.put(key, value);
}
return value;
}
/**
* Gets the default pattern.
*
* @return the default pattern
*/
private static synchronized String getDefaultPattern() {
if (cDefaultPattern == null) {
cDefaultPattern = new SimpleDateFormat().toPattern();
}
return cDefaultPattern;
}
// Constructor
//-----------------------------------------------------------------------
/**
* Constructs a new FastDateFormat.
*
* @param pattern {@link java.text.SimpleDateFormat} compatible
* pattern
* @param timeZone time zone to use, null
means use
* default for Date
and value within for
* Calendar
* @param locale locale, null
means use system
* default
* @throws IllegalArgumentException if pattern is invalid or
* null
*/
protected FastDateFormat(String pattern, TimeZone timeZone, Locale locale) {
super();
if (pattern == null) {
throw new IllegalArgumentException("The pattern must not be null");
}
mPattern = pattern;
mTimeZoneForced = (timeZone != null);
if (timeZone == null) {
timeZone = TimeZone.getDefault();
}
mTimeZone = timeZone;
mLocaleForced = (locale != null);
if (locale == null) {
locale = Locale.getDefault();
}
mLocale = locale;
}
/**
* Initializes the instance for first use.
*/
protected void init() {
List rulesList = parsePattern();
mRules = (Rule[]) rulesList.toArray(new Rule[rulesList.size()]);
int len = 0;
for (int i=mRules.length; --i >= 0; ) {
len += mRules[i].estimateLength();
}
mMaxLengthEstimate = len;
}
// Parse the pattern
//-----------------------------------------------------------------------
/**
* Returns a list of Rules given a pattern.
*
* @return a List
of Rule objects
* @throws IllegalArgumentException if pattern is invalid
*/
protected List parsePattern() {
DateFormatSymbols symbols = new DateFormatSymbols(mLocale);
List rules = new ArrayList();
String[] ERAs = symbols.getEras();
String[] months = symbols.getMonths();
String[] shortMonths = symbols.getShortMonths();
String[] weekdays = symbols.getWeekdays();
String[] shortWeekdays = symbols.getShortWeekdays();
String[] AmPmStrings = symbols.getAmPmStrings();
int length = mPattern.length();
int[] indexRef = new int[1];
for (int i = 0; i < length; i++) {
indexRef[0] = i;
String token = parseToken(mPattern, indexRef);
i = indexRef[0];
int tokenLen = token.length();
if (tokenLen == 0) {
break;
}
Rule rule;
char c = token.charAt(0);
switch (c) {
case 'G': // era designator (text)
rule = new TextField(Calendar.ERA, ERAs);
break;
case 'y': // year (number)
if (tokenLen >= 4) {
rule = selectNumberRule(Calendar.YEAR, tokenLen);
} else {
rule = TwoDigitYearField.INSTANCE;
}
break;
case 'M': // month in year (text and number)
if (tokenLen >= 4) {
rule = new TextField(Calendar.MONTH, months);
} else if (tokenLen == 3) {
rule = new TextField(Calendar.MONTH, shortMonths);
} else if (tokenLen == 2) {
rule = TwoDigitMonthField.INSTANCE;
} else {
rule = UnpaddedMonthField.INSTANCE;
}
break;
case 'd': // day in month (number)
rule = selectNumberRule(Calendar.DAY_OF_MONTH, tokenLen);
break;
case 'h': // hour in am/pm (number, 1..12)
rule = new TwelveHourField(selectNumberRule(Calendar.HOUR, tokenLen));
break;
case 'H': // hour in day (number, 0..23)
rule = selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen);
break;
case 'm': // minute in hour (number)
rule = selectNumberRule(Calendar.MINUTE, tokenLen);
break;
case 's': // second in minute (number)
rule = selectNumberRule(Calendar.SECOND, tokenLen);
break;
case 'S': // millisecond (number)
rule = selectNumberRule(Calendar.MILLISECOND, tokenLen);
break;
case 'E': // day in week (text)
rule = new TextField(Calendar.DAY_OF_WEEK, tokenLen < 4 ? shortWeekdays : weekdays);
break;
case 'D': // day in year (number)
rule = selectNumberRule(Calendar.DAY_OF_YEAR, tokenLen);
break;
case 'F': // day of week in month (number)
rule = selectNumberRule(Calendar.DAY_OF_WEEK_IN_MONTH, tokenLen);
break;
case 'w': // week in year (number)
rule = selectNumberRule(Calendar.WEEK_OF_YEAR, tokenLen);
break;
case 'W': // week in month (number)
rule = selectNumberRule(Calendar.WEEK_OF_MONTH, tokenLen);
break;
case 'a': // am/pm marker (text)
rule = new TextField(Calendar.AM_PM, AmPmStrings);
break;
case 'k': // hour in day (1..24)
rule = new TwentyFourHourField(selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen));
break;
case 'K': // hour in am/pm (0..11)
rule = selectNumberRule(Calendar.HOUR, tokenLen);
break;
case 'z': // time zone (text)
if (tokenLen >= 4) {
rule = new TimeZoneNameRule(mTimeZone, mTimeZoneForced, mLocale, TimeZone.LONG);
} else {
rule = new TimeZoneNameRule(mTimeZone, mTimeZoneForced, mLocale, TimeZone.SHORT);
}
break;
case 'Z': // time zone (value)
if (tokenLen == 1) {
rule = TimeZoneNumberRule.INSTANCE_NO_COLON;
} else {
rule = TimeZoneNumberRule.INSTANCE_COLON;
}
break;
case '\'': // literal text
String sub = token.substring(1);
if (sub.length() == 1) {
rule = new CharacterLiteral(sub.charAt(0));
} else {
rule = new StringLiteral(sub);
}
break;
default:
throw new IllegalArgumentException("Illegal pattern component: " + token);
}
rules.add(rule);
}
return rules;
}
/**
* Performs the parsing of tokens.
*
* @param pattern the pattern
* @param indexRef index references
* @return parsed token
*/
protected String parseToken(String pattern, int[] indexRef) {
StrBuilder buf = new StrBuilder();
int i = indexRef[0];
int length = pattern.length();
char c = pattern.charAt(i);
if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') {
// Scan a run of the same character, which indicates a time
// pattern.
buf.append(c);
while (i + 1 < length) {
char peek = pattern.charAt(i + 1);
if (peek == c) {
buf.append(c);
i++;
} else {
break;
}
}
} else {
// This will identify token as text.
buf.append('\'');
boolean inLiteral = false;
for (; i < length; i++) {
c = pattern.charAt(i);
if (c == '\'') {
if (i + 1 < length && pattern.charAt(i + 1) == '\'') {
// '' is treated as escaped '
i++;
buf.append(c);
} else {
inLiteral = !inLiteral;
}
} else if (!inLiteral &&
(c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')) {
i--;
break;
} else {
buf.append(c);
}
}
}
indexRef[0] = i;
return buf.toString();
}
/**
* Gets an appropriate rule for the padding required.
*
* @param field the field to get a rule for
* @param padding the padding required
* @return a new rule with the correct padding
*/
protected NumberRule selectNumberRule(int field, int padding) {
switch (padding) {
case 1:
return new UnpaddedNumberField(field);
case 2:
return new TwoDigitNumberField(field);
default:
return new PaddedNumberField(field, padding);
}
}
// Format methods
//-----------------------------------------------------------------------
/**
* Formats a Date
, Calendar
or
* Long
(milliseconds) object.
*
* @param obj the object to format
* @param toAppendTo the buffer to append to
* @param pos the position - ignored
* @return the buffer passed in
*/
public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
if (obj instanceof Date) {
return format((Date) obj, toAppendTo);
} else if (obj instanceof Calendar) {
return format((Calendar) obj, toAppendTo);
} else if (obj instanceof Long) {
return format(((Long) obj).longValue(), toAppendTo);
} else {
throw new IllegalArgumentException("Unknown class: " +
(obj == null ? "" : obj.getClass().getName()));
}
}
/**
* Formats a millisecond long
value.
*
* @param millis the millisecond value to format
* @return the formatted string
* @since 2.1
*/
public String format(long millis) {
return format(new Date(millis));
}
/**
* Formats a Date
object.
*
* @param date the date to format
* @return the formatted string
*/
public String format(Date date) {
Calendar c = new GregorianCalendar(mTimeZone, mLocale);
c.setTime(date);
return applyRules(c, new StringBuffer(mMaxLengthEstimate)).toString();
}
/**
* Formats a Calendar
object.
*
* @param calendar the calendar to format
* @return the formatted string
*/
public String format(Calendar calendar) {
return format(calendar, new StringBuffer(mMaxLengthEstimate)).toString();
}
/**
* Formats a milliseond long
value into the
* supplied StringBuffer
.
*
* @param millis the millisecond value to format
* @param buf the buffer to format into
* @return the specified string buffer
* @since 2.1
*/
public StringBuffer format(long millis, StringBuffer buf) {
return format(new Date(millis), buf);
}
/**
* Formats a Date
object into the
* supplied StringBuffer
.
*
* @param date the date to format
* @param buf the buffer to format into
* @return the specified string buffer
*/
public StringBuffer format(Date date, StringBuffer buf) {
Calendar c = new GregorianCalendar(mTimeZone);
c.setTime(date);
return applyRules(c, buf);
}
/**
* Formats a Calendar
object into the
* supplied StringBuffer
.
*
* @param calendar the calendar to format
* @param buf the buffer to format into
* @return the specified string buffer
*/
public StringBuffer format(Calendar calendar, StringBuffer buf) {
if (mTimeZoneForced) {
calendar.getTime(); /// LANG-538
calendar = (Calendar) calendar.clone();
calendar.setTimeZone(mTimeZone);
}
return applyRules(calendar, buf);
}
/**
* Performs the formatting by applying the rules to the
* specified calendar.
*
* @param calendar the calendar to format
* @param buf the buffer to format into
* @return the specified string buffer
*/
protected StringBuffer applyRules(Calendar calendar, StringBuffer buf) {
Rule[] rules = mRules;
int len = mRules.length;
for (int i = 0; i < len; i++) {
rules[i].appendTo(buf, calendar);
}
return buf;
}
// Parsing
//-----------------------------------------------------------------------
/**
* Parsing is not supported.
*
* @param source the string to parse
* @param pos the parsing position
* @return null
as not supported
*/
public Object parseObject(String source, ParsePosition pos) {
pos.setIndex(0);
pos.setErrorIndex(0);
return null;
}
// Accessors
//-----------------------------------------------------------------------
/**
* Gets the pattern used by this formatter.
*
* @return the pattern, {@link java.text.SimpleDateFormat} compatible
*/
public String getPattern() {
return mPattern;
}
/**
* Gets the time zone used by this formatter.
*
* This zone is always used for Date
formatting.
* If a Calendar
is passed in to be formatted, the
* time zone on that may be used depending on
* {@link #getTimeZoneOverridesCalendar()}.
*
* @return the time zone
*/
public TimeZone getTimeZone() {
return mTimeZone;
}
/**
* Returns true
if the time zone of the
* calendar overrides the time zone of the formatter.
*
* @return true
if time zone of formatter
* overridden for calendars
*/
public boolean getTimeZoneOverridesCalendar() {
return mTimeZoneForced;
}
/**
* Gets the locale used by this formatter.
*
* @return the locale
*/
public Locale getLocale() {
return mLocale;
}
/**
* Gets an estimate for the maximum string length that the
* formatter will produce.
*
* The actual formatted length will almost always be less than or
* equal to this amount.
*
* @return the maximum formatted length
*/
public int getMaxLengthEstimate() {
return mMaxLengthEstimate;
}
// Basics
//-----------------------------------------------------------------------
/**
* Compares two objects for equality.
*
* @param obj the object to compare to
* @return true
if equal
*/
public boolean equals(Object obj) {
if (obj instanceof FastDateFormat == false) {
return false;
}
FastDateFormat other = (FastDateFormat) obj;
if (
(mPattern == other.mPattern || mPattern.equals(other.mPattern)) &&
(mTimeZone == other.mTimeZone || mTimeZone.equals(other.mTimeZone)) &&
(mLocale == other.mLocale || mLocale.equals(other.mLocale)) &&
(mTimeZoneForced == other.mTimeZoneForced) &&
(mLocaleForced == other.mLocaleForced)
) {
return true;
}
return false;
}
/**
* Returns a hashcode compatible with equals.
*
* @return a hashcode compatible with equals
*/
public int hashCode() {
int total = 0;
total += mPattern.hashCode();
total += mTimeZone.hashCode();
total += (mTimeZoneForced ? 1 : 0);
total += mLocale.hashCode();
total += (mLocaleForced ? 1 : 0);
return total;
}
/**
* Gets a debugging string version of this formatter.
*
* @return a debugging string
*/
public String toString() {
return "FastDateFormat[" + mPattern + "]";
}
// Serializing
//-----------------------------------------------------------------------
/**
* Create the object after serialization. This implementation reinitializes the
* transient properties.
*
* @param in ObjectInputStream from which the object is being deserialized.
* @throws IOException if there is an IO issue.
* @throws ClassNotFoundException if a class cannot be found.
*/
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
init();
}
// Rules
//-----------------------------------------------------------------------
/**
* Inner class defining a rule.
*/
private interface Rule {
/**
* Returns the estimated lentgh of the result.
*
* @return the estimated length
*/
int estimateLength();
/**
* Appends the value of the specified calendar to the output buffer based on the rule implementation.
*
* @param buffer the output buffer
* @param calendar calendar to be appended
*/
void appendTo(StringBuffer buffer, Calendar calendar);
}
/**
* Inner class defining a numeric rule.
*/
private interface NumberRule extends Rule {
/**
* Appends the specified value to the output buffer based on the rule implementation.
*
* @param buffer the output buffer
* @param value the value to be appended
*/
void appendTo(StringBuffer buffer, int value);
}
/**
* Inner class to output a constant single character.
*/
private static class CharacterLiteral implements Rule {
private final char mValue;
/**
* Constructs a new instance of CharacterLiteral
* to hold the specified value.
*
* @param value the character literal
*/
CharacterLiteral(char value) {
mValue = value;
}
/**
* {@inheritDoc}
*/
public int estimateLength() {
return 1;
}
/**
* {@inheritDoc}
*/
public void appendTo(StringBuffer buffer, Calendar calendar) {
buffer.append(mValue);
}
}
/**
* Inner class to output a constant string.
*/
private static class StringLiteral implements Rule {
private final String mValue;
/**
* Constructs a new instance of StringLiteral
* to hold the specified value.
*
* @param value the string literal
*/
StringLiteral(String value) {
mValue = value;
}
/**
* {@inheritDoc}
*/
public int estimateLength() {
return mValue.length();
}
/**
* {@inheritDoc}
*/
public void appendTo(StringBuffer buffer, Calendar calendar) {
buffer.append(mValue);
}
}
/**
* Inner class to output one of a set of values.
*/
private static class TextField implements Rule {
private final int mField;
private final String[] mValues;
/**
* Constructs an instance of TextField
* with the specified field and values.
*
* @param field the field
* @param values the field values
*/
TextField(int field, String[] values) {
mField = field;
mValues = values;
}
/**
* {@inheritDoc}
*/
public int estimateLength() {
int max = 0;
for (int i=mValues.length; --i >= 0; ) {
int len = mValues[i].length();
if (len > max) {
max = len;
}
}
return max;
}
/**
* {@inheritDoc}
*/
public void appendTo(StringBuffer buffer, Calendar calendar) {
buffer.append(mValues[calendar.get(mField)]);
}
}
/**
* Inner class to output an unpadded number.
*/
private static class UnpaddedNumberField implements NumberRule {
private final int mField;
/**
* Constructs an instance of UnpadedNumberField
with the specified field.
*
* @param field the field
*/
UnpaddedNumberField(int field) {
mField = field;
}
/**
* {@inheritDoc}
*/
public int estimateLength() {
return 4;
}
/**
* {@inheritDoc}
*/
public void appendTo(StringBuffer buffer, Calendar calendar) {
appendTo(buffer, calendar.get(mField));
}
/**
* {@inheritDoc}
*/
public final void appendTo(StringBuffer buffer, int value) {
if (value < 10) {
buffer.append((char)(value + '0'));
} else if (value < 100) {
buffer.append((char)(value / 10 + '0'));
buffer.append((char)(value % 10 + '0'));
} else {
buffer.append(Integer.toString(value));
}
}
}
/**
* Inner class to output an unpadded month.
*/
private static class UnpaddedMonthField implements NumberRule {
static final UnpaddedMonthField INSTANCE = new UnpaddedMonthField();
/**
* Constructs an instance of UnpaddedMonthField
.
*
*/
UnpaddedMonthField() {
super();
}
/**
* {@inheritDoc}
*/
public int estimateLength() {
return 2;
}
/**
* {@inheritDoc}
*/
public void appendTo(StringBuffer buffer, Calendar calendar) {
appendTo(buffer, calendar.get(Calendar.MONTH) + 1);
}
/**
* {@inheritDoc}
*/
public final void appendTo(StringBuffer buffer, int value) {
if (value < 10) {
buffer.append((char)(value + '0'));
} else {
buffer.append((char)(value / 10 + '0'));
buffer.append((char)(value % 10 + '0'));
}
}
}
/**
* Inner class to output a padded number.
*/
private static class PaddedNumberField implements NumberRule {
private final int mField;
private final int mSize;
/**
* Constructs an instance of PaddedNumberField
.
*
* @param field the field
* @param size size of the output field
*/
PaddedNumberField(int field, int size) {
if (size < 3) {
// Should use UnpaddedNumberField or TwoDigitNumberField.
throw new IllegalArgumentException();
}
mField = field;
mSize = size;
}
/**
* {@inheritDoc}
*/
public int estimateLength() {
return 4;
}
/**
* {@inheritDoc}
*/
public void appendTo(StringBuffer buffer, Calendar calendar) {
appendTo(buffer, calendar.get(mField));
}
/**
* {@inheritDoc}
*/
public final void appendTo(StringBuffer buffer, int value) {
if (value < 100) {
for (int i = mSize; --i >= 2; ) {
buffer.append('0');
}
buffer.append((char)(value / 10 + '0'));
buffer.append((char)(value % 10 + '0'));
} else {
int digits;
if (value < 1000) {
digits = 3;
} else {
Validate.isTrue(value > -1, "Negative values should not be possible", value);
digits = Integer.toString(value).length();
}
for (int i = mSize; --i >= digits; ) {
buffer.append('0');
}
buffer.append(Integer.toString(value));
}
}
}
/**
* Inner class to output a two digit number.
*/
private static class TwoDigitNumberField implements NumberRule {
private final int mField;
/**
* Constructs an instance of TwoDigitNumberField
with the specified field.
*
* @param field the field
*/
TwoDigitNumberField(int field) {
mField = field;
}
/**
* {@inheritDoc}
*/
public int estimateLength() {
return 2;
}
/**
* {@inheritDoc}
*/
public void appendTo(StringBuffer buffer, Calendar calendar) {
appendTo(buffer, calendar.get(mField));
}
/**
* {@inheritDoc}
*/
public final void appendTo(StringBuffer buffer, int value) {
if (value < 100) {
buffer.append((char)(value / 10 + '0'));
buffer.append((char)(value % 10 + '0'));
} else {
buffer.append(Integer.toString(value));
}
}
}
/**
* Inner class to output a two digit year.
*/
private static class TwoDigitYearField implements NumberRule {
static final TwoDigitYearField INSTANCE = new TwoDigitYearField();
/**
* Constructs an instance of TwoDigitYearField
.
*/
TwoDigitYearField() {
super();
}
/**
* {@inheritDoc}
*/
public int estimateLength() {
return 2;
}
/**
* {@inheritDoc}
*/
public void appendTo(StringBuffer buffer, Calendar calendar) {
appendTo(buffer, calendar.get(Calendar.YEAR) % 100);
}
/**
* {@inheritDoc}
*/
public final void appendTo(StringBuffer buffer, int value) {
buffer.append((char)(value / 10 + '0'));
buffer.append((char)(value % 10 + '0'));
}
}
/**
* Inner class to output a two digit month.
*/
private static class TwoDigitMonthField implements NumberRule {
static final TwoDigitMonthField INSTANCE = new TwoDigitMonthField();
/**
* Constructs an instance of TwoDigitMonthField
.
*/
TwoDigitMonthField() {
super();
}
/**
* {@inheritDoc}
*/
public int estimateLength() {
return 2;
}
/**
* {@inheritDoc}
*/
public void appendTo(StringBuffer buffer, Calendar calendar) {
appendTo(buffer, calendar.get(Calendar.MONTH) + 1);
}
/**
* {@inheritDoc}
*/
public final void appendTo(StringBuffer buffer, int value) {
buffer.append((char)(value / 10 + '0'));
buffer.append((char)(value % 10 + '0'));
}
}
/**
* Inner class to output the twelve hour field.
*/
private static class TwelveHourField implements NumberRule {
private final NumberRule mRule;
/**
* Constructs an instance of TwelveHourField
with the specified
* NumberRule
.
*
* @param rule the rule
*/
TwelveHourField(NumberRule rule) {
mRule = rule;
}
/**
* {@inheritDoc}
*/
public int estimateLength() {
return mRule.estimateLength();
}
/**
* {@inheritDoc}
*/
public void appendTo(StringBuffer buffer, Calendar calendar) {
int value = calendar.get(Calendar.HOUR);
if (value == 0) {
value = calendar.getLeastMaximum(Calendar.HOUR) + 1;
}
mRule.appendTo(buffer, value);
}
/**
* {@inheritDoc}
*/
public void appendTo(StringBuffer buffer, int value) {
mRule.appendTo(buffer, value);
}
}
/**
* Inner class to output the twenty four hour field.
*/
private static class TwentyFourHourField implements NumberRule {
private final NumberRule mRule;
/**
* Constructs an instance of TwentyFourHourField
with the specified
* NumberRule
.
*
* @param rule the rule
*/
TwentyFourHourField(NumberRule rule) {
mRule = rule;
}
/**
* {@inheritDoc}
*/
public int estimateLength() {
return mRule.estimateLength();
}
/**
* {@inheritDoc}
*/
public void appendTo(StringBuffer buffer, Calendar calendar) {
int value = calendar.get(Calendar.HOUR_OF_DAY);
if (value == 0) {
value = calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1;
}
mRule.appendTo(buffer, value);
}
/**
* {@inheritDoc}
*/
public void appendTo(StringBuffer buffer, int value) {
mRule.appendTo(buffer, value);
}
}
/**
* Inner class to output a time zone name.
*/
private static class TimeZoneNameRule implements Rule {
private final TimeZone mTimeZone;
private final boolean mTimeZoneForced;
private final Locale mLocale;
private final int mStyle;
private final String mStandard;
private final String mDaylight;
/**
* Constructs an instance of TimeZoneNameRule
with the specified properties.
*
* @param timeZone the time zone
* @param timeZoneForced if true
the time zone is forced into standard and daylight
* @param locale the locale
* @param style the style
*/
TimeZoneNameRule(TimeZone timeZone, boolean timeZoneForced, Locale locale, int style) {
mTimeZone = timeZone;
mTimeZoneForced = timeZoneForced;
mLocale = locale;
mStyle = style;
if (timeZoneForced) {
mStandard = getTimeZoneDisplay(timeZone, false, style, locale);
mDaylight = getTimeZoneDisplay(timeZone, true, style, locale);
} else {
mStandard = null;
mDaylight = null;
}
}
/**
* {@inheritDoc}
*/
public int estimateLength() {
if (mTimeZoneForced) {
return Math.max(mStandard.length(), mDaylight.length());
} else if (mStyle == TimeZone.SHORT) {
return 4;
} else {
return 40;
}
}
/**
* {@inheritDoc}
*/
public void appendTo(StringBuffer buffer, Calendar calendar) {
if (mTimeZoneForced) {
if (mTimeZone.useDaylightTime() && calendar.get(Calendar.DST_OFFSET) != 0) {
buffer.append(mDaylight);
} else {
buffer.append(mStandard);
}
} else {
TimeZone timeZone = calendar.getTimeZone();
if (timeZone.useDaylightTime() && calendar.get(Calendar.DST_OFFSET) != 0) {
buffer.append(getTimeZoneDisplay(timeZone, true, mStyle, mLocale));
} else {
buffer.append(getTimeZoneDisplay(timeZone, false, mStyle, mLocale));
}
}
}
}
/**
* Inner class to output a time zone as a number +/-HHMM
* or +/-HH:MM
.
*/
private static class TimeZoneNumberRule implements Rule {
static final TimeZoneNumberRule INSTANCE_COLON = new TimeZoneNumberRule(true);
static final TimeZoneNumberRule INSTANCE_NO_COLON = new TimeZoneNumberRule(false);
final boolean mColon;
/**
* Constructs an instance of TimeZoneNumberRule
with the specified properties.
*
* @param colon add colon between HH and MM in the output if true
*/
TimeZoneNumberRule(boolean colon) {
mColon = colon;
}
/**
* {@inheritDoc}
*/
public int estimateLength() {
return 5;
}
/**
* {@inheritDoc}
*/
public void appendTo(StringBuffer buffer, Calendar calendar) {
int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
if (offset < 0) {
buffer.append('-');
offset = -offset;
} else {
buffer.append('+');
}
int hours = offset / (60 * 60 * 1000);
buffer.append((char)(hours / 10 + '0'));
buffer.append((char)(hours % 10 + '0'));
if (mColon) {
buffer.append(':');
}
int minutes = offset / (60 * 1000) - 60 * hours;
buffer.append((char)(minutes / 10 + '0'));
buffer.append((char)(minutes % 10 + '0'));
}
}
// ----------------------------------------------------------------------
/**
* Inner class that acts as a compound key for time zone names.
*/
private static class TimeZoneDisplayKey {
private final TimeZone mTimeZone;
private final int mStyle;
private final Locale mLocale;
/**
* Constructs an instance of TimeZoneDisplayKey
with the specified properties.
*
* @param timeZone the time zone
* @param daylight adjust the style for daylight saving time if true
* @param style the timezone style
* @param locale the timezone locale
*/
TimeZoneDisplayKey(TimeZone timeZone,
boolean daylight, int style, Locale locale) {
mTimeZone = timeZone;
if (daylight) {
style |= 0x80000000;
}
mStyle = style;
mLocale = locale;
}
/**
* {@inheritDoc}
*/
public int hashCode() {
return mStyle * 31 + mLocale.hashCode();
}
/**
* {@inheritDoc}
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof TimeZoneDisplayKey) {
TimeZoneDisplayKey other = (TimeZoneDisplayKey)obj;
return
mTimeZone.equals(other.mTimeZone) &&
mStyle == other.mStyle &&
mLocale.equals(other.mLocale);
}
return false;
}
}
// ----------------------------------------------------------------------
/**
* Helper class for creating compound objects.
*
* One use for this class is to create a hashtable key
* out of multiple objects.
*/
private static class Pair {
private final Object mObj1;
private final Object mObj2;
/**
* Constructs an instance of Pair
to hold the specified objects.
* @param obj1 one object in the pair
* @param obj2 second object in the pair
*/
public Pair(Object obj1, Object obj2) {
mObj1 = obj1;
mObj2 = obj2;
}
/**
* {@inheritDoc}
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Pair)) {
return false;
}
Pair key = (Pair)obj;
return
(mObj1 == null ?
key.mObj1 == null : mObj1.equals(key.mObj1)) &&
(mObj2 == null ?
key.mObj2 == null : mObj2.equals(key.mObj2));
}
/**
* {@inheritDoc}
*/
public int hashCode() {
return
(mObj1 == null ? 0 : mObj1.hashCode()) +
(mObj2 == null ? 0 : mObj2.hashCode());
}
/**
* {@inheritDoc}
*/
public String toString() {
return "[" + mObj1 + ':' + mObj2 + ']';
}
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/time/package.html 100644 0 0 2465 11513702443 24155 0 ustar 0 0
Provides classes and methods to work with dates and durations.
This includes:
DateUtils
- a set of static utility methods for working with dates
FastDateFormat
- a replacement for SimpleDateFormat
that is fast and thread-safe
DateFormatUtils
- a formatting class for dates
StopWatch
- a duration timer
@since 2.0
These classes are immutable (and therefore thread-safe) apart from {@link StopWatch}.
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/time/StopWatch.java 100644 0 0 24521 11513702443 24470 0 ustar 0 0 /*
* 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.lang.time;
/**
*
* StopWatch
provides a convenient API for timings.
*
*
*
* To start the watch, call {@link #start()}. At this point you can:
*
*
* - {@link #split()} the watch to get the time whilst the watch continues in the background. {@link #unsplit()} will
* remove the effect of the split. At this point, these three options are available again.
* - {@link #suspend()} the watch to pause it. {@link #resume()} allows the watch to continue. Any time between the
* suspend and resume will not be counted in the total. At this point, these three options are available again.
* - {@link #stop()} the watch to complete the timing session.
*
*
*
* It is intended that the output methods {@link #toString()} and {@link #getTime()} should only be called after stop,
* split or suspend, however a suitable result will be returned at other points.
*
*
*
* NOTE: As from v2.1, the methods protect against inappropriate calls. Thus you cannot now call stop before start,
* resume before suspend or unsplit before split.
*
*
*
* 1. split(), suspend(), or stop() cannot be invoked twice
* 2. unsplit() may only be called if the watch has been split()
* 3. resume() may only be called if the watch has been suspend()
* 4. start() cannot be called twice without calling reset()
*
*
* This class is not thread-safe
*
* @author Apache Software Foundation
* @since 2.0
* @version $Id: StopWatch.java 1056988 2011-01-09 17:58:53Z niallp $
*/
public class StopWatch {
// running states
private static final int STATE_UNSTARTED = 0;
private static final int STATE_RUNNING = 1;
private static final int STATE_STOPPED = 2;
private static final int STATE_SUSPENDED = 3;
// split state
private static final int STATE_UNSPLIT = 10;
private static final int STATE_SPLIT = 11;
/**
* The current running state of the StopWatch.
*/
private int runningState = STATE_UNSTARTED;
/**
* Whether the stopwatch has a split time recorded.
*/
private int splitState = STATE_UNSPLIT;
/**
* The start time.
*/
private long startTime = -1;
/**
* The stop time.
*/
private long stopTime = -1;
/**
*
* Constructor.
*
*/
public StopWatch() {
super();
}
/**
*
* Start the stopwatch.
*
*
*
* This method starts a new timing session, clearing any previous values.
*
*
* @throws IllegalStateException
* if the StopWatch is already running.
*/
public void start() {
if (this.runningState == STATE_STOPPED) {
throw new IllegalStateException("Stopwatch must be reset before being restarted. ");
}
if (this.runningState != STATE_UNSTARTED) {
throw new IllegalStateException("Stopwatch already started. ");
}
this.stopTime = -1;
this.startTime = System.currentTimeMillis();
this.runningState = STATE_RUNNING;
}
/**
*
* Stop the stopwatch.
*
*
*
* This method ends a new timing session, allowing the time to be retrieved.
*
*
* @throws IllegalStateException
* if the StopWatch is not running.
*/
public void stop() {
if (this.runningState != STATE_RUNNING && this.runningState != STATE_SUSPENDED) {
throw new IllegalStateException("Stopwatch is not running. ");
}
if (this.runningState == STATE_RUNNING) {
this.stopTime = System.currentTimeMillis();
}
this.runningState = STATE_STOPPED;
}
/**
*
* Resets the stopwatch. Stops it if need be.
*
*
*
* This method clears the internal values to allow the object to be reused.
*
*/
public void reset() {
this.runningState = STATE_UNSTARTED;
this.splitState = STATE_UNSPLIT;
this.startTime = -1;
this.stopTime = -1;
}
/**
*
* Split the time.
*
*
*
* This method sets the stop time of the watch to allow a time to be extracted. The start time is unaffected,
* enabling {@link #unsplit()} to continue the timing from the original start point.
*
*
* @throws IllegalStateException
* if the StopWatch is not running.
*/
public void split() {
if (this.runningState != STATE_RUNNING) {
throw new IllegalStateException("Stopwatch is not running. ");
}
this.stopTime = System.currentTimeMillis();
this.splitState = STATE_SPLIT;
}
/**
*
* Remove a split.
*
*
*
* This method clears the stop time. The start time is unaffected, enabling timing from the original start point to
* continue.
*
*
* @throws IllegalStateException
* if the StopWatch has not been split.
*/
public void unsplit() {
if (this.splitState != STATE_SPLIT) {
throw new IllegalStateException("Stopwatch has not been split. ");
}
this.stopTime = -1;
this.splitState = STATE_UNSPLIT;
}
/**
*
* Suspend the stopwatch for later resumption.
*
*
*
* This method suspends the watch until it is resumed. The watch will not include time between the suspend and
* resume calls in the total time.
*
*
* @throws IllegalStateException
* if the StopWatch is not currently running.
*/
public void suspend() {
if (this.runningState != STATE_RUNNING) {
throw new IllegalStateException("Stopwatch must be running to suspend. ");
}
this.stopTime = System.currentTimeMillis();
this.runningState = STATE_SUSPENDED;
}
/**
*
* Resume the stopwatch after a suspend.
*
*
*
* This method resumes the watch after it was suspended. The watch will not include time between the suspend and
* resume calls in the total time.
*
*
* @throws IllegalStateException
* if the StopWatch has not been suspended.
*/
public void resume() {
if (this.runningState != STATE_SUSPENDED) {
throw new IllegalStateException("Stopwatch must be suspended to resume. ");
}
this.startTime += (System.currentTimeMillis() - this.stopTime);
this.stopTime = -1;
this.runningState = STATE_RUNNING;
}
/**
*
* Get the time on the stopwatch.
*
*
*
* This is either the time between the start and the moment this method is called, or the amount of time between
* start and stop.
*
*
* @return the time in milliseconds
*/
public long getTime() {
if (this.runningState == STATE_STOPPED || this.runningState == STATE_SUSPENDED) {
return this.stopTime - this.startTime;
} else if (this.runningState == STATE_UNSTARTED) {
return 0;
} else if (this.runningState == STATE_RUNNING) {
return System.currentTimeMillis() - this.startTime;
}
throw new RuntimeException("Illegal running state has occured. ");
}
/**
*
* Get the split time on the stopwatch.
*
*
*
* This is the time between start and latest split.
*
*
* @return the split time in milliseconds
*
* @throws IllegalStateException
* if the StopWatch has not yet been split.
* @since 2.1
*/
public long getSplitTime() {
if (this.splitState != STATE_SPLIT) {
throw new IllegalStateException("Stopwatch must be split to get the split time. ");
}
return this.stopTime - this.startTime;
}
/**
* Returns the time this stopwatch was started.
*
* @return the time this stopwatch was started
* @throws IllegalStateException
* if this StopWatch has not been started
* @since 2.4
*/
public long getStartTime() {
if (this.runningState == STATE_UNSTARTED) {
throw new IllegalStateException("Stopwatch has not been started");
}
return this.startTime;
}
/**
*
* Gets a summary of the time that the stopwatch recorded as a string.
*
*
*
* The format used is ISO8601-like, hours:minutes:seconds.milliseconds.
*
*
* @return the time as a String
*/
public String toString() {
return DurationFormatUtils.formatDurationHMS(getTime());
}
/**
*
* Gets a summary of the split time that the stopwatch recorded as a string.
*
*
*
* The format used is ISO8601-like, hours:minutes:seconds.milliseconds.
*
*
* @return the split time as a String
* @since 2.1
*/
public String toSplitString() {
return DurationFormatUtils.formatDurationHMS(getSplitTime());
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/UnhandledException.java 100644 0 0 4715 11513702446 25365 0 ustar 0 0 /*
* 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.lang;
import org.apache.commons.lang.exception.NestableRuntimeException;
/**
* Thrown when it is impossible or undesirable to consume or throw a checked exception.
* This exception supplements the standard exception classes by providing a more
* semantically rich description of the problem.
*
* UnhandledException
represents the case where a method has to deal
* with a checked exception but does not wish to.
* Instead, the checked exception is rethrown in this unchecked wrapper.
*
*
* public void foo() {
* try {
* // do something that throws IOException
* } catch (IOException ex) {
* // don't want to or can't throw IOException from foo()
* throw new UnhandledException(ex);
* }
* }
*
*
* @author Matthew Hawthorne
* @since 2.0
* @version $Id: UnhandledException.java 437554 2006-08-28 06:21:41Z bayard $
*/
public class UnhandledException extends NestableRuntimeException {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 1832101364842773720L;
/**
* Constructs the exception using a cause.
*
* @param cause the underlying cause
*/
public UnhandledException(Throwable cause) {
super(cause);
}
/**
* Constructs the exception using a message and cause.
*
* @param message the message to use
* @param cause the underlying cause
*/
public UnhandledException(String message, Throwable cause) {
super(message, cause);
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/Validate.java 100644 0 0 50355 11513702446 23356 0 ustar 0 0 /*
* 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.lang;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
/**
* This class assists in validating arguments.
*
* The class is based along the lines of JUnit. If an argument value is
* deemed invalid, an IllegalArgumentException is thrown. For example:
*
*
* Validate.isTrue( i > 0, "The value must be greater than zero: ", i);
* Validate.notNull( surname, "The surname must not be null");
*
*
* @author Apache Software Foundation
* @author Ola Berg
* @author Gary Gregory
* @author Norm Deane
* @since 2.0
* @version $Id: Validate.java 1057051 2011-01-09 23:15:51Z sebb $
*/
public class Validate {
// Validate has no dependencies on other classes in Commons Lang at present
/**
* Constructor. This class should not normally be instantiated.
*/
public Validate() {
super();
}
// isTrue
//---------------------------------------------------------------------------------
/**
* Validate that the argument condition is true
; otherwise
* throwing an exception with the specified message. This method is useful when
* validating according to an arbitrary boolean expression, such as validating an
* object or using your own custom validation expression.
*
* Validate.isTrue( myObject.isOk(), "The object is not OK: ", myObject);
*
* For performance reasons, the object 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 exception message if invalid
* @param value the value to append to the message when invalid
* @throws IllegalArgumentException if expression is false
*/
public static void isTrue(boolean expression, String message, Object value) {
if (expression == false) {
throw new IllegalArgumentException(message + value);
}
}
/**
* Validate that the argument condition is 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: ", 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 exception message if invalid
* @param value the value to append to the message when invalid
* @throws IllegalArgumentException if expression is false
*/
public static void isTrue(boolean expression, String message, long value) {
if (expression == false) {
throw new IllegalArgumentException(message + value);
}
}
/**
* Validate that the argument condition is 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: ", 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 exception message if invalid
* @param value the value to append to the message when invalid
* @throws IllegalArgumentException if expression is false
*/
public static void isTrue(boolean expression, String message, double value) {
if (expression == false) {
throw new IllegalArgumentException(message + value);
}
}
/**
* Validate that the argument condition is 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), "The value must be greater than zero");
* Validate.isTrue( myObject.isOk(), "The object is not OK");
*
*
* @param expression the boolean expression to check
* @param message the exception message if invalid
* @throws IllegalArgumentException if expression is false
*/
public static void isTrue(boolean expression, String message) {
if (expression == false) {
throw new IllegalArgumentException(message);
}
}
/**
* Validate that the argument condition is 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 false
*/
public static void isTrue(boolean expression) {
if (expression == false) {
throw new IllegalArgumentException("The validated expression is false");
}
}
// notNull
//---------------------------------------------------------------------------------
/**
* Validate that the specified argument is not null
;
* otherwise throwing an exception.
*
*
Validate.notNull(myObject);
*
* The message of the exception is "The validated object is
* null".
*
* @param object the object to check
* @throws IllegalArgumentException if the object is null
*/
public static void notNull(Object object) {
notNull(object, "The validated object is null");
}
/**
* Validate that the specified argument is not null
;
* otherwise throwing an exception with the specified message.
*
*
Validate.notNull(myObject, "The object must not be null");
*
* @param object the object to check
* @param message the exception message if invalid
*/
public static void notNull(Object object, String message) {
if (object == null) {
throw new IllegalArgumentException(message);
}
}
// notEmpty array
//---------------------------------------------------------------------------------
/**
* Validate that the specified argument array is neither 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 array the array to check
* @param message the exception message if invalid
* @throws IllegalArgumentException if the array is empty
*/
public static void notEmpty(Object[] array, String message) {
if (array == null || array.length == 0) {
throw new IllegalArgumentException(message);
}
}
/**
* Validate that the specified argument array is neither 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 array the array to check
* @throws IllegalArgumentException if the array is empty
*/
public static void notEmpty(Object[] array) {
notEmpty(array, "The validated array is empty");
}
// notEmpty collection
//---------------------------------------------------------------------------------
/**
*
Validate that the specified argument collection is neither null
* nor a size of zero (no elements); otherwise throwing an exception
* with the specified message.
*
*
Validate.notEmpty(myCollection, "The collection must not be empty");
*
* @param collection the collection to check
* @param message the exception message if invalid
* @throws IllegalArgumentException if the collection is empty
*/
public static void notEmpty(Collection collection, String message) {
if (collection == null || collection.size() == 0) {
throw new IllegalArgumentException(message);
}
}
/**
* Validate that the specified argument collection is neither null
* nor a size of zero (no elements); otherwise throwing an exception.
*
*
Validate.notEmpty(myCollection);
*
* The message in the exception is "The validated collection is
* empty".
*
* @param collection the collection to check
* @throws IllegalArgumentException if the collection is empty
*/
public static void notEmpty(Collection collection) {
notEmpty(collection, "The validated collection is empty");
}
// notEmpty map
//---------------------------------------------------------------------------------
/**
* Validate that the specified argument map is neither null
* nor a size of zero (no elements); otherwise throwing an exception
* with the specified message.
*
*
Validate.notEmpty(myMap, "The map must not be empty");
*
* @param map the map to check
* @param message the exception message if invalid
* @throws IllegalArgumentException if the map is empty
*/
public static void notEmpty(Map map, String message) {
if (map == null || map.size() == 0) {
throw new IllegalArgumentException(message);
}
}
/**
* Validate that the specified argument map is neither null
* nor a size of zero (no elements); otherwise throwing an exception.
*
*
Validate.notEmpty(myMap);
*
* The message in the exception is "The validated map is
* empty".
*
* @param map the map to check
* @throws IllegalArgumentException if the map is empty
* @see #notEmpty(Map, String)
*/
public static void notEmpty(Map map) {
notEmpty(map, "The validated map is empty");
}
// notEmpty string
//---------------------------------------------------------------------------------
/**
* Validate that the specified argument string is
* neither null
nor a length of zero (no characters);
* otherwise throwing an exception with the specified message.
*
*
Validate.notEmpty(myString, "The string must not be empty");
*
* @param string the string to check
* @param message the exception message if invalid
* @throws IllegalArgumentException if the string is empty
*/
public static void notEmpty(String string, String message) {
if (string == null || string.length() == 0) {
throw new IllegalArgumentException(message);
}
}
/**
* Validate that the specified argument string is
* neither null
nor a length of zero (no characters);
* otherwise throwing an exception with the specified message.
*
*
Validate.notEmpty(myString);
*
* The message in the exception is "The validated
* string is empty".
*
* @param string the string to check
* @throws IllegalArgumentException if the string is empty
*/
public static void notEmpty(String string) {
notEmpty(string, "The validated string is empty");
}
// notNullElements array
//---------------------------------------------------------------------------------
/**
* Validate that the specified argument array is neither
* null
nor contains any elements that are null
;
* otherwise throwing an exception with the specified message.
*
*
Validate.noNullElements(myArray, "The array contain null at position %d");
*
* If the array is null
, then the message in the exception
* is "The validated object is null".
*
* @param array the array to check
* @param message the exception message if the collection has null
elements
* @throws IllegalArgumentException if the array is null
or
* an element in the array is null
*/
public static void noNullElements(Object[] array, String message) {
Validate.notNull(array);
for (int i = 0; i < array.length; i++) {
if (array[i] == null) {
throw new IllegalArgumentException(message);
}
}
}
/**
* Validate that the specified argument array is neither
* null
nor contains any elements that are null
;
* otherwise throwing an exception.
*
*
Validate.noNullElements(myArray);
*
* If the array is null
, then the message in the exception
* is "The validated object is null".
*
* If the array has a null
element, then the message in the
* exception is "The validated array contains null element at index:
* " followed by the index.
*
* @param array the array to check
* @throws IllegalArgumentException if the array is null
or
* an element in the array is null
*/
public static void noNullElements(Object[] array) {
Validate.notNull(array);
for (int i = 0; i < array.length; i++) {
if (array[i] == null) {
throw new IllegalArgumentException("The validated array contains null element at index: " + i);
}
}
}
// notNullElements collection
//---------------------------------------------------------------------------------
/**
* Validate that the specified argument collection is neither
* null
nor contains any elements that are null
;
* otherwise throwing an exception with the specified message.
*
*
Validate.noNullElements(myCollection, "The collection contains null elements");
*
* If the collection is null
, then the message in the exception
* is "The validated object is null".
*
*
* @param collection the collection to check
* @param message the exception message if the collection has
* @throws IllegalArgumentException if the collection is null
or
* an element in the collection is null
*/
public static void noNullElements(Collection collection, String message) {
Validate.notNull(collection);
for (Iterator it = collection.iterator(); it.hasNext();) {
if (it.next() == null) {
throw new IllegalArgumentException(message);
}
}
}
/**
* Validate that the specified argument collection is neither
* null
nor contains any elements that are null
;
* otherwise throwing an exception.
*
*
Validate.noNullElements(myCollection);
*
* If the collection is null
, then the message in the exception
* is "The validated object is null".
*
* If the collection has a null
element, then the message in the
* exception is "The validated collection contains null element at index:
* " followed by the index.
*
* @param collection the collection to check
* @throws IllegalArgumentException if the collection is null
or
* an element in the collection is null
*/
public static void noNullElements(Collection collection) {
Validate.notNull(collection);
int i = 0;
for (Iterator it = collection.iterator(); it.hasNext(); i++) {
if (it.next() == null) {
throw new IllegalArgumentException("The validated collection contains null element at index: " + i);
}
}
}
/**
* Validate an argument, throwing IllegalArgumentException
* if the argument collection is null
or has elements that
* are not of type clazz
or a subclass.
*
*
* Validate.allElementsOfType(collection, String.class, "Collection has invalid elements");
*
*
* @param collection the collection to check, not null
* @param clazz the Class
which the collection's elements are expected to be, not null
* @param message the exception message if the Collection
has elements not of type clazz
* @since 2.1
*/
public static void allElementsOfType(Collection collection, Class clazz, String message) {
Validate.notNull(collection);
Validate.notNull(clazz);
for (Iterator it = collection.iterator(); it.hasNext(); ) {
if (clazz.isInstance(it.next()) == false) {
throw new IllegalArgumentException(message);
}
}
}
/**
*
* Validate an argument, throwing IllegalArgumentException
if the argument collection is
* null
or has elements that are not of type clazz
or a subclass.
*
*
*
* Validate.allElementsOfType(collection, String.class);
*
*
*
* The message in the exception is 'The validated collection contains an element not of type clazz at index: '.
*
*
* @param collection the collection to check, not null
* @param clazz the Class
which the collection's elements are expected to be, not null
* @since 2.1
*/
public static void allElementsOfType(Collection collection, Class clazz) {
Validate.notNull(collection);
Validate.notNull(clazz);
int i = 0;
for (Iterator it = collection.iterator(); it.hasNext(); i++) {
if (clazz.isInstance(it.next()) == false) {
throw new IllegalArgumentException("The validated collection contains an element not of type "
+ clazz.getName() + " at index: " + i);
}
}
}
}
commons-lang-2.6-src/src/main/java/org/apache/commons/lang/WordUtils.java 100644 0 0 63167 11513702446 23566 0 ustar 0 0 /*
* 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.lang;
/**
* Operations on Strings that contain words.
*
* This class tries to handle null
input gracefully.
* An exception will not be thrown for a null
input.
* Each method documents its behaviour in more detail.
*
* @author Apache Jakarta Velocity
* @author Apache Software Foundation
* @author Henning P. Schmiedehausen
* @author Gary Gregory
* @since 2.0
* @version $Id: WordUtils.java 905636 2010-02-02 14:03:32Z niallp $
*/
public class WordUtils {
/**
* WordUtils
instances should NOT be constructed in
* standard programming. Instead, the class should be used as
* WordUtils.wrap("foo bar", 20);
.
*
* This constructor is public to permit tools that require a JavaBean
* instance to operate.
*/
public WordUtils() {
super();
}
// Wrapping
//--------------------------------------------------------------------------
// /**
// * Wraps a block of text to a specified line length using '\n' as
// * a newline.
// *
// * This method takes a block of text, which might have long lines in it
// * and wraps the long lines based on the supplied lineLength parameter.
// *
// * If a single word is longer than the line length (eg. a URL), it will
// * not be broken, and will display beyond the expected width.
// *
// * If there are tabs in inString, you are going to get results that are
// * a bit strange. Tabs are a single character but are displayed as 4 or 8
// * spaces. Remove the tabs.
// *
// * @param str text which is in need of word-wrapping, may be null
// * @param lineLength the column to wrap the words at
// * @return the text with all the long lines word-wrapped
// * null
if null string input
// */
// public static String wrapText(String str, int lineLength) {
// return wrap(str, null, lineLength);
// }
// /**
// * Wraps a block of text to a specified line length.
// *
// * This method takes a block of text, which might have long lines in it
// * and wraps the long lines based on the supplied lineLength parameter.
// *
// * If a single word is longer than the wrapColumn (eg. a URL), it will
// * not be broken, and will display beyond the expected width.
// *
// * If there are tabs in inString, you are going to get results that are
// * a bit strange. Tabs are a single character but are displayed as 4 or 8
// * spaces. Remove the tabs.
// *
// * @param str text which is in need of word-wrapping, may be null
// * @param newLineChars the characters that define a newline, null treated as \n
// * @param lineLength the column to wrap the words at
// * @return the text with all the long lines word-wrapped
// * null
if null string input
// */
// public static String wrapText(String str, String newLineChars, int lineLength) {
// if (str == null) {
// return null;
// }
// if (newLineChars == null) {
// newLineChars = "\n";
// }
// StringTokenizer lineTokenizer = new StringTokenizer(str, newLineChars, true);
// StringBuffer stringBuffer = new StringBuffer();
//
// while (lineTokenizer.hasMoreTokens()) {
// try {
// String nextLine = lineTokenizer.nextToken();
//
// if (nextLine.length() > lineLength) {
// // This line is long enough to be wrapped.
// nextLine = wrapLine(nextLine, null, lineLength, false);
// }
//
// stringBuffer.append(nextLine);
//
// } catch (NoSuchElementException nsee) {
// // thrown by nextToken(), but I don't know why it would
// break;
// }
// }
//
// return stringBuffer.toString();
// }
// Wrapping
//-----------------------------------------------------------------------
/**
* Wraps a single line of text, identifying words by ' '
.
*
* New lines will be separated by the system property line separator.
* Very long words, such as URLs will not be wrapped.
*
* Leading spaces on a new line are stripped.
* Trailing spaces are not stripped.
*
*
* WordUtils.wrap(null, *) = null
* WordUtils.wrap("", *) = ""
*
*
* @param str the String to be word wrapped, may be null
* @param wrapLength the column to wrap the words at, less than 1 is treated as 1
* @return a line with newlines inserted, null
if null input
*/
public static String wrap(String str, int wrapLength) {
return wrap(str, wrapLength, null, false);
}
/**
* Wraps a single line of text, identifying words by ' '
.
*
* Leading spaces on a new line are stripped.
* Trailing spaces are not stripped.
*
*
* WordUtils.wrap(null, *, *, *) = null
* WordUtils.wrap("", *, *, *) = ""
*
*
* @param str the String to be word wrapped, may be null
* @param wrapLength the column to wrap the words at, less than 1 is treated as 1
* @param newLineStr the string to insert for a new line,
* null
uses the system property line separator
* @param wrapLongWords true if long words (such as URLs) should be wrapped
* @return a line with newlines inserted, null
if null input
*/
public static String wrap(String str, int wrapLength, String newLineStr, boolean wrapLongWords) {
if (str == null) {
return null;
}
if (newLineStr == null) {
newLineStr = SystemUtils.LINE_SEPARATOR;
}
if (wrapLength < 1) {
wrapLength = 1;
}
int inputLineLength = str.length();
int offset = 0;
StringBuffer wrappedLine = new StringBuffer(inputLineLength + 32);
while ((inputLineLength - offset) > wrapLength) {
if (str.charAt(offset) == ' ') {
offset++;
continue;
}
int spaceToWrapAt = str.lastIndexOf(' ', wrapLength + offset);
if (spaceToWrapAt >= offset) {
// normal case
wrappedLine.append(str.substring(offset, spaceToWrapAt));
wrappedLine.append(newLineStr);
offset = spaceToWrapAt + 1;
} else {
// really long word or URL
if (wrapLongWords) {
// wrap really long word one line at a time
wrappedLine.append(str.substring(offset, wrapLength + offset));
wrappedLine.append(newLineStr);
offset += wrapLength;
} else {
// do not wrap really long word, just extend beyond limit
spaceToWrapAt = str.indexOf(' ', wrapLength + offset);
if (spaceToWrapAt >= 0) {
wrappedLine.append(str.substring(offset, spaceToWrapAt));
wrappedLine.append(newLineStr);
offset = spaceToWrapAt + 1;
} else {
wrappedLine.append(str.substring(offset));
offset = inputLineLength;
}
}
}
}
// Whatever is left in line is short enough to just pass through
wrappedLine.append(str.substring(offset));
return wrappedLine.toString();
}
// Capitalizing
//-----------------------------------------------------------------------
/**
* Capitalizes all the whitespace separated words in a String.
* Only the first letter of each word is changed. To convert the
* rest of each word to lowercase at the same time,
* use {@link #capitalizeFully(String)}.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
* A null
input String returns null
.
* Capitalization uses the unicode title case, normally equivalent to
* upper case.
*
*
* WordUtils.capitalize(null) = null
* WordUtils.capitalize("") = ""
* WordUtils.capitalize("i am FINE") = "I Am FINE"
*
*
* @param str the String to capitalize, may be null
* @return capitalized String, null
if null String input
* @see #uncapitalize(String)
* @see #capitalizeFully(String)
*/
public static String capitalize(String str) {
return capitalize(str, null);
}
/**
* Capitalizes all the delimiter separated words in a String.
* Only the first letter of each word is changed. To convert the
* rest of each word to lowercase at the same time,
* use {@link #capitalizeFully(String, char[])}.
*
* The delimiters represent a set of characters understood to separate words.
* The first string character and the first non-delimiter character after a
* delimiter will be capitalized.
*
* A null
input String returns null
.
* Capitalization uses the unicode title case, normally equivalent to
* upper case.
*
*
* WordUtils.capitalize(null, *) = null
* WordUtils.capitalize("", *) = ""
* WordUtils.capitalize(*, new char[0]) = *
* WordUtils.capitalize("i am fine", null) = "I Am Fine"
* WordUtils.capitalize("i aM.fine", {'.'}) = "I aM.Fine"
*
*
* @param str the String to capitalize, may be null
* @param delimiters set of characters to determine capitalization, null means whitespace
* @return capitalized String, null
if null String input
* @see #uncapitalize(String)
* @see #capitalizeFully(String)
* @since 2.1
*/
public static String capitalize(String str, char[] delimiters) {
int delimLen = (delimiters == null ? -1 : delimiters.length);
if (str == null || str.length() == 0 || delimLen == 0) {
return str;
}
int strLen = str.length();
StringBuffer buffer = new StringBuffer(strLen);
boolean capitalizeNext = true;
for (int i = 0; i < strLen; i++) {
char ch = str.charAt(i);
if (isDelimiter(ch, delimiters)) {
buffer.append(ch);
capitalizeNext = true;
} else if (capitalizeNext) {
buffer.append(Character.toTitleCase(ch));
capitalizeNext = false;
} else {
buffer.append(ch);
}
}
return buffer.toString();
}
//-----------------------------------------------------------------------
/**
* Converts all the whitespace separated words in a String into capitalized words,
* that is each word is made up of a titlecase character and then a series of
* lowercase characters.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
* A null
input String returns null
.
* Capitalization uses the unicode title case, normally equivalent to
* upper case.
*
*
* WordUtils.capitalizeFully(null) = null
* WordUtils.capitalizeFully("") = ""
* WordUtils.capitalizeFully("i am FINE") = "I Am Fine"
*
*
* @param str the String to capitalize, may be null
* @return capitalized String, null
if null String input
*/
public static String capitalizeFully(String str) {
return capitalizeFully(str, null);
}
/**
* Converts all the delimiter separated words in a String into capitalized words,
* that is each word is made up of a titlecase character and then a series of
* lowercase characters.
*
* The delimiters represent a set of characters understood to separate words.
* The first string character and the first non-delimiter character after a
* delimiter will be capitalized.
*
* A null
input String returns null
.
* Capitalization uses the unicode title case, normally equivalent to
* upper case.
*
*
* WordUtils.capitalizeFully(null, *) = null
* WordUtils.capitalizeFully("", *) = ""
* WordUtils.capitalizeFully(*, null) = *
* WordUtils.capitalizeFully(*, new char[0]) = *
* WordUtils.capitalizeFully("i aM.fine", {'.'}) = "I am.Fine"
*
*
* @param str the String to capitalize, may be null
* @param delimiters set of characters to determine capitalization, null means whitespace
* @return capitalized String, null
if null String input
* @since 2.1
*/
public static String capitalizeFully(String str, char[] delimiters) {
int delimLen = (delimiters == null ? -1 : delimiters.length);
if (str == null || str.length() == 0 || delimLen == 0) {
return str;
}
str = str.toLowerCase();
return capitalize(str, delimiters);
}
//-----------------------------------------------------------------------
/**
* Uncapitalizes all the whitespace separated words in a String.
* Only the first letter of each word is changed.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
* A null
input String returns null
.
*
*
* WordUtils.uncapitalize(null) = null
* WordUtils.uncapitalize("") = ""
* WordUtils.uncapitalize("I Am FINE") = "i am fINE"
*
*
* @param str the String to uncapitalize, may be null
* @return uncapitalized String, null
if null String input
* @see #capitalize(String)
*/
public static String uncapitalize(String str) {
return uncapitalize(str, null);
}
/**
* Uncapitalizes all the whitespace separated words in a String.
* Only the first letter of each word is changed.
*
* The delimiters represent a set of characters understood to separate words.
* The first string character and the first non-delimiter character after a
* delimiter will be uncapitalized.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
* A null
input String returns null
.
*
*
* WordUtils.uncapitalize(null, *) = null
* WordUtils.uncapitalize("", *) = ""
* WordUtils.uncapitalize(*, null) = *
* WordUtils.uncapitalize(*, new char[0]) = *
* WordUtils.uncapitalize("I AM.FINE", {'.'}) = "i AM.fINE"
*
*
* @param str the String to uncapitalize, may be null
* @param delimiters set of characters to determine uncapitalization, null means whitespace
* @return uncapitalized String, null
if null String input
* @see #capitalize(String)
* @since 2.1
*/
public static String uncapitalize(String str, char[] delimiters) {
int delimLen = (delimiters == null ? -1 : delimiters.length);
if (str == null || str.length() == 0 || delimLen == 0) {
return str;
}
int strLen = str.length();
StringBuffer buffer = new StringBuffer(strLen);
boolean uncapitalizeNext = true;
for (int i = 0; i < strLen; i++) {
char ch = str.charAt(i);
if (isDelimiter(ch, delimiters)) {
buffer.append(ch);
uncapitalizeNext = true;
} else if (uncapitalizeNext) {
buffer.append(Character.toLowerCase(ch));
uncapitalizeNext = false;
} else {
buffer.append(ch);
}
}
return buffer.toString();
}
//-----------------------------------------------------------------------
/**
* Swaps the case of a String using a word based algorithm.
*
*
* - Upper case character converts to Lower case
* - Title case character converts to Lower case
* - Lower case character after Whitespace or at start converts to Title case
* - Other Lower case character converts to Upper case
*
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
* A null
input String returns null
.
*
*
* StringUtils.swapCase(null) = null
* StringUtils.swapCase("") = ""
* StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
*
*
* @param str the String to swap case, may be null
* @return the changed String, null
if null String input
*/
public static String swapCase(String str) {
int strLen;
if (str == null || (strLen = str.length()) == 0) {
return str;
}
StringBuffer buffer = new StringBuffer(strLen);
boolean whitespace = true;
char ch = 0;
char tmp = 0;
for (int i = 0; i < strLen; i++) {
ch = str.charAt(i);
if (Character.isUpperCase(ch)) {
tmp = Character.toLowerCase(ch);
} else if (Character.isTitleCase(ch)) {
tmp = Character.toLowerCase(ch);
} else if (Character.isLowerCase(ch)) {
if (whitespace) {
tmp = Character.toTitleCase(ch);
} else {
tmp = Character.toUpperCase(ch);
}
} else {
tmp = ch;
}
buffer.append(tmp);
whitespace = Character.isWhitespace(ch);
}
return buffer.toString();
}
//-----------------------------------------------------------------------
/**
* Extracts the initial letters from each word in the String.
*
* The first letter of the string and all first letters after
* whitespace are returned as a new string.
* Their case is not changed.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
* A null
input String returns null
.
*
*
* WordUtils.initials(null) = null
* WordUtils.initials("") = ""
* WordUtils.initials("Ben John Lee") = "BJL"
* WordUtils.initials("Ben J.Lee") = "BJ"
*
*
* @param str the String to get initials from, may be null
* @return String of initial letters, null
if null String input
* @see #initials(String,char[])
* @since 2.2
*/
public static String initials(String str) {
return initials(str, null);
}
/**
* Extracts the initial letters from each word in the String.
*
* The first letter of the string and all first letters after the
* defined delimiters are returned as a new string.
* Their case is not changed.
*
* If the delimiters array is null, then Whitespace is used.
* Whitespace is defined by {@link Character#isWhitespace(char)}.
* A null
input String returns null
.
* An empty delimiter array returns an empty String.
*
*
* WordUtils.initials(null, *) = null
* WordUtils.initials("", *) = ""
* WordUtils.initials("Ben John Lee", null) = "BJL"
* WordUtils.initials("Ben J.Lee", null) = "BJ"
* WordUtils.initials("Ben J.Lee", [' ','.']) = "BJL"
* WordUtils.initials(*, new char[0]) = ""
*
*
* @param str the String to get initials from, may be null
* @param delimiters set of characters to determine words, null means whitespace
* @return String of initial letters, null
if null String input
* @see #initials(String)
* @since 2.2
*/
public static String initials(String str, char[] delimiters) {
if (str == null || str.length() == 0) {
return str;
}
if (delimiters != null && delimiters.length == 0) {
return "";
}
int strLen = str.length();
char[] buf = new char[strLen / 2 + 1];
int count = 0;
boolean lastWasGap = true;
for (int i = 0; i < strLen; i++) {
char ch = str.charAt(i);
if (isDelimiter(ch, delimiters)) {
lastWasGap = true;
} else if (lastWasGap) {
buf[count++] = ch;
lastWasGap = false;
} else {
// ignore ch
}
}
return new String(buf, 0, count);
}
//-----------------------------------------------------------------------
/**
* Is the character a delimiter.
*
* @param ch the character to check
* @param delimiters the delimiters
* @return true if it is a delimiter
*/
private static boolean isDelimiter(char ch, char[] delimiters) {
if (delimiters == null) {
return Character.isWhitespace(ch);
}
for (int i = 0, isize = delimiters.length; i < isize; i++) {
if (ch == delimiters[i]) {
return true;
}
}
return false;
}
//-----------------------------------------------------------------------
/**
* Abbreviates a string nicely.
*
* This method searches for the first space after the lower limit and abbreviates
* the String there. It will also append any String passed as a parameter
* to the end of the String. The upper limit can be specified to forcibly
* abbreviate a String.
*
* @param str the string to be abbreviated. If null is passed, null is returned.
* If the empty String is passed, the empty string is returned.
* @param lower the lower limit.
* @param upper the upper limit; specify -1 if no limit is desired.
* If the upper limit is lower than the lower limit, it will be
* adjusted to be the same as the lower limit.
* @param appendToEnd String to be appended to the end of the abbreviated string.
* This is appended ONLY if the string was indeed abbreviated.
* The append does not count towards the lower or upper limits.
* @return the abbreviated String.
* @since 2.4
*/
public static String abbreviate(String str, int lower, int upper, String appendToEnd) {
// initial parameter checks
if (str == null) {
return null;
}
if (str.length() == 0) {
return StringUtils.EMPTY;
}
// if the lower value is greater than the length of the string,
// set to the length of the string
if (lower > str.length()) {
lower = str.length();
}
// if the upper value is -1 (i.e. no limit) or is greater
// than the length of the string, set to the length of the string
if (upper == -1 || upper > str.length()) {
upper = str.length();
}
// if upper is less than lower, raise it to lower
if (upper < lower) {
upper = lower;
}
StringBuffer result = new StringBuffer();
int index = StringUtils.indexOf(str, " ", lower);
if (index == -1) {
result.append(str.substring(0, upper));
// only if abbreviation has occured do we append the appendToEnd value
if (upper != str.length()) {
result.append(StringUtils.defaultString(appendToEnd));
}
} else if (index > upper) {
result.append(str.substring(0, upper));
result.append(StringUtils.defaultString(appendToEnd));
} else {
result.append(str.substring(0, index));
result.append(StringUtils.defaultString(appendToEnd));
}
return result.toString();
}
}
commons-lang-2.6-src/src/media/logo.xcf 100644 0 0 45226 11513702433 15227 0 ustar 0 0 gimp xcf file , d B B ) /
gimp-comment Created with The GIMP ¦ . á + Hÿ _ 3
Text Layer#2 ÿ
¬ . &