Sort main members
This commit is contained in:
parent
972b3f218e
commit
dc83c2820b
|
@ -64,6 +64,17 @@ public class AnnotationUtils {
|
|||
setArrayEnd("]");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected void appendDetail(final StringBuffer buffer, final String fieldName, Object value) {
|
||||
if (value instanceof Annotation) {
|
||||
value = AnnotationUtils.toString((Annotation) value);
|
||||
}
|
||||
super.appendDetail(buffer, fieldName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
@ -76,27 +87,99 @@ public class AnnotationUtils {
|
|||
// formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected void appendDetail(final StringBuffer buffer, final String fieldName, Object value) {
|
||||
if (value instanceof Annotation) {
|
||||
value = AnnotationUtils.toString((Annotation) value);
|
||||
}
|
||||
super.appendDetail(buffer, fieldName, value);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* {@link AnnotationUtils} instances should NOT be constructed in
|
||||
* standard programming. Instead, the class should be used statically.
|
||||
* Helper method for comparing two arrays of annotations.
|
||||
*
|
||||
* <p>This constructor is public to permit tools that require a JavaBean
|
||||
* instance to operate.</p>
|
||||
* @param a1 the first array
|
||||
* @param a2 the second array
|
||||
* @return a flag whether these arrays are equal
|
||||
*/
|
||||
public AnnotationUtils() {
|
||||
private static boolean annotationArrayMemberEquals(final Annotation[] a1, final Annotation[] a2) {
|
||||
if (a1.length != a2.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < a1.length; i++) {
|
||||
if (!equals(a1[i], a2[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for comparing two objects of an array type.
|
||||
*
|
||||
* @param componentType the component type of the array
|
||||
* @param o1 the first object
|
||||
* @param o2 the second object
|
||||
* @return a flag whether these objects are equal
|
||||
*/
|
||||
private static boolean arrayMemberEquals(final Class<?> componentType, final Object o1, final Object o2) {
|
||||
if (componentType.isAnnotation()) {
|
||||
return annotationArrayMemberEquals((Annotation[]) o1, (Annotation[]) o2);
|
||||
}
|
||||
if (componentType.equals(Byte.TYPE)) {
|
||||
return Arrays.equals((byte[]) o1, (byte[]) o2);
|
||||
}
|
||||
if (componentType.equals(Short.TYPE)) {
|
||||
return Arrays.equals((short[]) o1, (short[]) o2);
|
||||
}
|
||||
if (componentType.equals(Integer.TYPE)) {
|
||||
return Arrays.equals((int[]) o1, (int[]) o2);
|
||||
}
|
||||
if (componentType.equals(Character.TYPE)) {
|
||||
return Arrays.equals((char[]) o1, (char[]) o2);
|
||||
}
|
||||
if (componentType.equals(Long.TYPE)) {
|
||||
return Arrays.equals((long[]) o1, (long[]) o2);
|
||||
}
|
||||
if (componentType.equals(Float.TYPE)) {
|
||||
return Arrays.equals((float[]) o1, (float[]) o2);
|
||||
}
|
||||
if (componentType.equals(Double.TYPE)) {
|
||||
return Arrays.equals((double[]) o1, (double[]) o2);
|
||||
}
|
||||
if (componentType.equals(Boolean.TYPE)) {
|
||||
return Arrays.equals((boolean[]) o1, (boolean[]) o2);
|
||||
}
|
||||
return Arrays.equals((Object[]) o1, (Object[]) o2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for generating a hash code for an array.
|
||||
*
|
||||
* @param componentType the component type of the array
|
||||
* @param o the array
|
||||
* @return a hash code for the specified array
|
||||
*/
|
||||
private static int arrayMemberHash(final Class<?> componentType, final Object o) {
|
||||
if (componentType.equals(Byte.TYPE)) {
|
||||
return Arrays.hashCode((byte[]) o);
|
||||
}
|
||||
if (componentType.equals(Short.TYPE)) {
|
||||
return Arrays.hashCode((short[]) o);
|
||||
}
|
||||
if (componentType.equals(Integer.TYPE)) {
|
||||
return Arrays.hashCode((int[]) o);
|
||||
}
|
||||
if (componentType.equals(Character.TYPE)) {
|
||||
return Arrays.hashCode((char[]) o);
|
||||
}
|
||||
if (componentType.equals(Long.TYPE)) {
|
||||
return Arrays.hashCode((long[]) o);
|
||||
}
|
||||
if (componentType.equals(Float.TYPE)) {
|
||||
return Arrays.hashCode((float[]) o);
|
||||
}
|
||||
if (componentType.equals(Double.TYPE)) {
|
||||
return Arrays.hashCode((double[]) o);
|
||||
}
|
||||
if (componentType.equals(Boolean.TYPE)) {
|
||||
return Arrays.hashCode((boolean[]) o);
|
||||
}
|
||||
return Arrays.hashCode((Object[]) o);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,27 +253,23 @@ public class AnnotationUtils {
|
|||
return result;
|
||||
}
|
||||
|
||||
//besides modularity, this has the advantage of autoboxing primitives:
|
||||
/**
|
||||
* Generate a string representation of an Annotation, as suggested by
|
||||
* {@link Annotation#toString()}.
|
||||
* Helper method for generating a hash code for a member of an annotation.
|
||||
*
|
||||
* @param a the annotation of which a string representation is desired
|
||||
* @return the standard string representation of an annotation, not
|
||||
* {@code null}
|
||||
* @param name the name of the member
|
||||
* @param value the value of the member
|
||||
* @return a hash code for this member
|
||||
*/
|
||||
public static String toString(final Annotation a) {
|
||||
final ToStringBuilder builder = new ToStringBuilder(a, TO_STRING_STYLE);
|
||||
for (final Method m : a.annotationType().getDeclaredMethods()) {
|
||||
if (m.getParameterTypes().length > 0) {
|
||||
continue; // wtf?
|
||||
}
|
||||
try {
|
||||
builder.append(m.getName(), m.invoke(a));
|
||||
} catch (final ReflectiveOperationException ex) {
|
||||
throw new UncheckedException(ex);
|
||||
}
|
||||
private static int hashMember(final String name, final Object value) {
|
||||
final int part1 = name.hashCode() * 127;
|
||||
if (ObjectUtils.isArray(value)) {
|
||||
return part1 ^ arrayMemberHash(value.getClass().getComponentType(), value);
|
||||
}
|
||||
return builder.build();
|
||||
if (value instanceof Annotation) {
|
||||
return part1 ^ hashCode((Annotation) value);
|
||||
}
|
||||
return part1 ^ value.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -215,25 +294,6 @@ public class AnnotationUtils {
|
|||
|| String.class.equals(type) || Class.class.equals(type);
|
||||
}
|
||||
|
||||
//besides modularity, this has the advantage of autoboxing primitives:
|
||||
/**
|
||||
* Helper method for generating a hash code for a member of an annotation.
|
||||
*
|
||||
* @param name the name of the member
|
||||
* @param value the value of the member
|
||||
* @return a hash code for this member
|
||||
*/
|
||||
private static int hashMember(final String name, final Object value) {
|
||||
final int part1 = name.hashCode() * 127;
|
||||
if (ObjectUtils.isArray(value)) {
|
||||
return part1 ^ arrayMemberHash(value.getClass().getComponentType(), value);
|
||||
}
|
||||
if (value instanceof Annotation) {
|
||||
return part1 ^ hashCode((Annotation) value);
|
||||
}
|
||||
return part1 ^ value.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for checking whether two objects of the given type are
|
||||
* equal. This method is used to compare the parameters of two annotation
|
||||
|
@ -261,95 +321,35 @@ public class AnnotationUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Helper method for comparing two objects of an array type.
|
||||
* Generate a string representation of an Annotation, as suggested by
|
||||
* {@link Annotation#toString()}.
|
||||
*
|
||||
* @param componentType the component type of the array
|
||||
* @param o1 the first object
|
||||
* @param o2 the second object
|
||||
* @return a flag whether these objects are equal
|
||||
* @param a the annotation of which a string representation is desired
|
||||
* @return the standard string representation of an annotation, not
|
||||
* {@code null}
|
||||
*/
|
||||
private static boolean arrayMemberEquals(final Class<?> componentType, final Object o1, final Object o2) {
|
||||
if (componentType.isAnnotation()) {
|
||||
return annotationArrayMemberEquals((Annotation[]) o1, (Annotation[]) o2);
|
||||
}
|
||||
if (componentType.equals(Byte.TYPE)) {
|
||||
return Arrays.equals((byte[]) o1, (byte[]) o2);
|
||||
}
|
||||
if (componentType.equals(Short.TYPE)) {
|
||||
return Arrays.equals((short[]) o1, (short[]) o2);
|
||||
}
|
||||
if (componentType.equals(Integer.TYPE)) {
|
||||
return Arrays.equals((int[]) o1, (int[]) o2);
|
||||
}
|
||||
if (componentType.equals(Character.TYPE)) {
|
||||
return Arrays.equals((char[]) o1, (char[]) o2);
|
||||
}
|
||||
if (componentType.equals(Long.TYPE)) {
|
||||
return Arrays.equals((long[]) o1, (long[]) o2);
|
||||
}
|
||||
if (componentType.equals(Float.TYPE)) {
|
||||
return Arrays.equals((float[]) o1, (float[]) o2);
|
||||
}
|
||||
if (componentType.equals(Double.TYPE)) {
|
||||
return Arrays.equals((double[]) o1, (double[]) o2);
|
||||
}
|
||||
if (componentType.equals(Boolean.TYPE)) {
|
||||
return Arrays.equals((boolean[]) o1, (boolean[]) o2);
|
||||
}
|
||||
return Arrays.equals((Object[]) o1, (Object[]) o2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for comparing two arrays of annotations.
|
||||
*
|
||||
* @param a1 the first array
|
||||
* @param a2 the second array
|
||||
* @return a flag whether these arrays are equal
|
||||
*/
|
||||
private static boolean annotationArrayMemberEquals(final Annotation[] a1, final Annotation[] a2) {
|
||||
if (a1.length != a2.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < a1.length; i++) {
|
||||
if (!equals(a1[i], a2[i])) {
|
||||
return false;
|
||||
public static String toString(final Annotation a) {
|
||||
final ToStringBuilder builder = new ToStringBuilder(a, TO_STRING_STYLE);
|
||||
for (final Method m : a.annotationType().getDeclaredMethods()) {
|
||||
if (m.getParameterTypes().length > 0) {
|
||||
continue; // wtf?
|
||||
}
|
||||
try {
|
||||
builder.append(m.getName(), m.invoke(a));
|
||||
} catch (final ReflectiveOperationException ex) {
|
||||
throw new UncheckedException(ex);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for generating a hash code for an array.
|
||||
* {@link AnnotationUtils} instances should NOT be constructed in
|
||||
* standard programming. Instead, the class should be used statically.
|
||||
*
|
||||
* @param componentType the component type of the array
|
||||
* @param o the array
|
||||
* @return a hash code for the specified array
|
||||
* <p>This constructor is public to permit tools that require a JavaBean
|
||||
* instance to operate.</p>
|
||||
*/
|
||||
private static int arrayMemberHash(final Class<?> componentType, final Object o) {
|
||||
if (componentType.equals(Byte.TYPE)) {
|
||||
return Arrays.hashCode((byte[]) o);
|
||||
}
|
||||
if (componentType.equals(Short.TYPE)) {
|
||||
return Arrays.hashCode((short[]) o);
|
||||
}
|
||||
if (componentType.equals(Integer.TYPE)) {
|
||||
return Arrays.hashCode((int[]) o);
|
||||
}
|
||||
if (componentType.equals(Character.TYPE)) {
|
||||
return Arrays.hashCode((char[]) o);
|
||||
}
|
||||
if (componentType.equals(Long.TYPE)) {
|
||||
return Arrays.hashCode((long[]) o);
|
||||
}
|
||||
if (componentType.equals(Float.TYPE)) {
|
||||
return Arrays.hashCode((float[]) o);
|
||||
}
|
||||
if (componentType.equals(Double.TYPE)) {
|
||||
return Arrays.hashCode((double[]) o);
|
||||
}
|
||||
if (componentType.equals(Boolean.TYPE)) {
|
||||
return Arrays.hashCode((boolean[]) o);
|
||||
}
|
||||
return Arrays.hashCode((Object[]) o);
|
||||
public AnnotationUtils() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,44 +39,6 @@ public class ArchUtils {
|
|||
init();
|
||||
}
|
||||
|
||||
private static void init() {
|
||||
init_X86_32Bit();
|
||||
init_X86_64Bit();
|
||||
init_IA64_32Bit();
|
||||
init_IA64_64Bit();
|
||||
init_PPC_32Bit();
|
||||
init_PPC_64Bit();
|
||||
init_Aarch_64Bit();
|
||||
}
|
||||
|
||||
private static void init_Aarch_64Bit() {
|
||||
addProcessors(new Processor(Processor.Arch.BIT_64, Processor.Type.AARCH_64), "aarch64");
|
||||
}
|
||||
|
||||
private static void init_X86_32Bit() {
|
||||
addProcessors(new Processor(Processor.Arch.BIT_32, Processor.Type.X86), "x86", "i386", "i486", "i586", "i686", "pentium");
|
||||
}
|
||||
|
||||
private static void init_X86_64Bit() {
|
||||
addProcessors(new Processor(Processor.Arch.BIT_64, Processor.Type.X86), "x86_64", "amd64", "em64t", "universal");
|
||||
}
|
||||
|
||||
private static void init_IA64_32Bit() {
|
||||
addProcessors(new Processor(Processor.Arch.BIT_32, Processor.Type.IA_64), "ia64_32", "ia64n");
|
||||
}
|
||||
|
||||
private static void init_IA64_64Bit() {
|
||||
addProcessors(new Processor(Processor.Arch.BIT_64, Processor.Type.IA_64), "ia64", "ia64w");
|
||||
}
|
||||
|
||||
private static void init_PPC_32Bit() {
|
||||
addProcessors(new Processor(Processor.Arch.BIT_32, Processor.Type.PPC), "ppc", "power", "powerpc", "power_pc", "power_rs");
|
||||
}
|
||||
|
||||
private static void init_PPC_64Bit() {
|
||||
addProcessors(new Processor(Processor.Arch.BIT_64, Processor.Type.PPC), "ppc64", "power64", "powerpc64", "power_pc64", "power_rs64");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given {@link Processor} with the given key {@link String} to the map.
|
||||
*
|
||||
|
@ -126,4 +88,42 @@ public class ArchUtils {
|
|||
return ARCH_TO_PROCESSOR.get(value);
|
||||
}
|
||||
|
||||
private static void init() {
|
||||
init_X86_32Bit();
|
||||
init_X86_64Bit();
|
||||
init_IA64_32Bit();
|
||||
init_IA64_64Bit();
|
||||
init_PPC_32Bit();
|
||||
init_PPC_64Bit();
|
||||
init_Aarch_64Bit();
|
||||
}
|
||||
|
||||
private static void init_Aarch_64Bit() {
|
||||
addProcessors(new Processor(Processor.Arch.BIT_64, Processor.Type.AARCH_64), "aarch64");
|
||||
}
|
||||
|
||||
private static void init_IA64_32Bit() {
|
||||
addProcessors(new Processor(Processor.Arch.BIT_32, Processor.Type.IA_64), "ia64_32", "ia64n");
|
||||
}
|
||||
|
||||
private static void init_IA64_64Bit() {
|
||||
addProcessors(new Processor(Processor.Arch.BIT_64, Processor.Type.IA_64), "ia64", "ia64w");
|
||||
}
|
||||
|
||||
private static void init_PPC_32Bit() {
|
||||
addProcessors(new Processor(Processor.Arch.BIT_32, Processor.Type.PPC), "ppc", "power", "powerpc", "power_pc", "power_rs");
|
||||
}
|
||||
|
||||
private static void init_PPC_64Bit() {
|
||||
addProcessors(new Processor(Processor.Arch.BIT_64, Processor.Type.PPC), "ppc64", "power64", "powerpc64", "power_pc64", "power_rs64");
|
||||
}
|
||||
|
||||
private static void init_X86_32Bit() {
|
||||
addProcessors(new Processor(Processor.Arch.BIT_32, Processor.Type.X86), "x86", "i386", "i486", "i586", "i686", "pentium");
|
||||
}
|
||||
|
||||
private static void init_X86_64Bit() {
|
||||
addProcessors(new Processor(Processor.Arch.BIT_64, Processor.Type.X86), "x86_64", "amd64", "em64t", "universal");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -88,39 +88,40 @@ public class BitField {
|
|||
}
|
||||
|
||||
/**
|
||||
* Obtains the value for the specified BitField, appropriately
|
||||
* shifted right.
|
||||
* Clears the bits.
|
||||
*
|
||||
* <p>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).</p>
|
||||
*
|
||||
* @see #setValue(int,int)
|
||||
* @param holder the int data containing the bits we're interested
|
||||
* in
|
||||
* @return the selected bits, shifted right appropriately
|
||||
* @param holder the int data containing the bits we're
|
||||
* interested in
|
||||
* @return the value of holder with the specified bits cleared
|
||||
* (set to {@code 0})
|
||||
*/
|
||||
public int getValue(final int holder) {
|
||||
return getRawValue(holder) >> shiftCount;
|
||||
public int clear(final int holder) {
|
||||
return holder & ~mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the value for the specified BitField, appropriately
|
||||
* shifted right, as a short.
|
||||
* Clears the bits.
|
||||
*
|
||||
* <p>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).</p>
|
||||
* @param holder the byte data containing the bits we're
|
||||
* interested in
|
||||
*
|
||||
* @return the value of holder with the specified bits cleared
|
||||
* (set to {@code 0})
|
||||
*/
|
||||
public byte clearByte(final byte holder) {
|
||||
return (byte) clear(holder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the bits.
|
||||
*
|
||||
* @see #setShortValue(short,short)
|
||||
* @param holder the short data containing the bits we're
|
||||
* interested in
|
||||
* @return the selected bits, shifted right appropriately
|
||||
* @return the value of holder with the specified bits cleared
|
||||
* (set to {@code 0})
|
||||
*/
|
||||
public short getShortValue(final short holder) {
|
||||
return (short) getValue(holder);
|
||||
public short clearShort(final short holder) {
|
||||
return (short) clear(holder);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,20 +147,39 @@ public class BitField {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns whether the field is set or not.
|
||||
* Obtains the value for the specified BitField, appropriately
|
||||
* shifted right, as a short.
|
||||
*
|
||||
* <p>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.</p>
|
||||
* <p>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).</p>
|
||||
*
|
||||
* @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(final short holder) {
|
||||
return (short) getValue(holder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the value for the specified BitField, appropriately
|
||||
* shifted right.
|
||||
*
|
||||
* <p>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).</p>
|
||||
*
|
||||
* @see #setValue(int,int)
|
||||
* @param holder the int data containing the bits we're interested
|
||||
* in
|
||||
* @return {@code true} if any of the bits are set,
|
||||
* else {@code false}
|
||||
* @return the selected bits, shifted right appropriately
|
||||
*/
|
||||
public boolean isSet(final int holder) {
|
||||
return (holder & mask) != 0;
|
||||
public int getValue(final int holder) {
|
||||
return getRawValue(holder) >> shiftCount;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,68 +199,20 @@ public class BitField {
|
|||
}
|
||||
|
||||
/**
|
||||
* Replaces the bits with new values.
|
||||
* Returns whether the field is set or not.
|
||||
*
|
||||
* @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
|
||||
* <p>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.</p>
|
||||
*
|
||||
* @param holder the int data containing the bits we're interested
|
||||
* in
|
||||
* @return {@code true} if any of the bits are set,
|
||||
* else {@code false}
|
||||
*/
|
||||
public int setValue(final int holder, final int value) {
|
||||
return (holder & ~mask) | ((value << shiftCount) & 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(final short holder, final 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 to {@code 0})
|
||||
*/
|
||||
public int clear(final 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 to {@code 0})
|
||||
*/
|
||||
public short clearShort(final 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 to {@code 0})
|
||||
*/
|
||||
public byte clearByte(final byte holder) {
|
||||
return (byte) clear(holder);
|
||||
public boolean isSet(final int holder) {
|
||||
return (holder & mask) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -256,15 +228,16 @@ public class BitField {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the bits.
|
||||
* Sets a boolean BitField.
|
||||
*
|
||||
* @param holder the short data containing the bits we're
|
||||
* @param holder the int data containing the bits we're
|
||||
* interested in
|
||||
* @return the value of holder with the specified bits set
|
||||
* to {@code 1}
|
||||
* @param flag indicating whether to set or clear the bits
|
||||
* @return the value of holder with the specified bits set or
|
||||
* cleared
|
||||
*/
|
||||
public short setShort(final short holder) {
|
||||
return (short) set(holder);
|
||||
public int setBoolean(final int holder, final boolean flag) {
|
||||
return flag ? set(holder) : clear(holder);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -283,14 +256,26 @@ public class BitField {
|
|||
/**
|
||||
* Sets a boolean BitField.
|
||||
*
|
||||
* @param holder the int data containing the bits we're
|
||||
* @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
|
||||
* cleared
|
||||
*/
|
||||
public int setBoolean(final int holder, final boolean flag) {
|
||||
return flag ? set(holder) : clear(holder);
|
||||
public byte setByteBoolean(final byte holder, final boolean flag) {
|
||||
return flag ? setByte(holder) : clearByte(holder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* to {@code 1}
|
||||
*/
|
||||
public short setShort(final short holder) {
|
||||
return (short) set(holder);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -307,16 +292,31 @@ public class BitField {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets a boolean BitField.
|
||||
* Replaces the bits with new values.
|
||||
*
|
||||
* @param holder the byte data containing the bits we're
|
||||
* @see #getShortValue(short)
|
||||
* @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
|
||||
* @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 byte setByteBoolean(final byte holder, final boolean flag) {
|
||||
return flag ? setByte(holder) : clearByte(holder);
|
||||
public short setShortValue(final short holder, final short value) {
|
||||
return (short) setValue(holder, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(final int holder, final int value) {
|
||||
return (holder & ~mask) | ((value << shiftCount) & mask);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,6 +33,102 @@ import java.util.Objects;
|
|||
// to depend on Range.
|
||||
final class CharRange implements Iterable<Character>, Serializable {
|
||||
|
||||
/**
|
||||
* Character {@link Iterator}.
|
||||
* <p>#NotThreadSafe#</p>
|
||||
*/
|
||||
private static final class CharacterIterator implements Iterator<Character> {
|
||||
/** The current character */
|
||||
private char current;
|
||||
|
||||
private final CharRange range;
|
||||
private boolean hasNext;
|
||||
|
||||
/**
|
||||
* Constructs a new iterator for the character range.
|
||||
*
|
||||
* @param r The character range
|
||||
*/
|
||||
private CharacterIterator(final 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the iterator not reached the end character yet?
|
||||
*
|
||||
* @return {@code true} if the iterator has yet to reach the character date
|
||||
*/
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next character in the iteration
|
||||
*
|
||||
* @return {@link Character} for the next character
|
||||
*/
|
||||
@Override
|
||||
public Character next() {
|
||||
if (!hasNext) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
final char cur = current;
|
||||
prepareNext();
|
||||
return Character.valueOf(cur);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always throws UnsupportedOperationException.
|
||||
*
|
||||
* @throws UnsupportedOperationException Always thrown.
|
||||
* @see java.util.Iterator#remove()
|
||||
*/
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Required for serialization support. Lang version 2.0.
|
||||
*
|
||||
|
@ -40,6 +136,67 @@ final class CharRange implements Iterable<Character>, Serializable {
|
|||
*/
|
||||
private static final long serialVersionUID = 8270183163158333422L;
|
||||
|
||||
/** Empty array. */
|
||||
static final CharRange[] EMPTY_ARRAY = {};
|
||||
|
||||
/**
|
||||
* Constructs a {@link CharRange} over a single character.
|
||||
*
|
||||
* @param ch only character in this range
|
||||
* @return the new CharRange object
|
||||
* @since 2.5
|
||||
*/
|
||||
public static CharRange is(final char ch) {
|
||||
return new CharRange(ch, ch, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link CharRange} over a set of characters.
|
||||
*
|
||||
* <p>If start and end are in the wrong order, they are reversed.
|
||||
* Thus {@code a-e} is the same as {@code e-a}.</p>
|
||||
*
|
||||
* @param start first character, inclusive, in this range
|
||||
* @param end last character, inclusive, in this range
|
||||
* @return the new CharRange object
|
||||
* @since 2.5
|
||||
*/
|
||||
public static CharRange isIn(final char start, final char end) {
|
||||
return new CharRange(start, end, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a negated {@link CharRange} over a single character.
|
||||
*
|
||||
* <p>A negated range includes everything except that defined by the
|
||||
* single character.</p>
|
||||
*
|
||||
* @param ch only character in this range
|
||||
* @return the new CharRange object
|
||||
* @since 2.5
|
||||
*/
|
||||
public static CharRange isNot(final char ch) {
|
||||
return new CharRange(ch, ch, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a negated {@link CharRange} over a set of characters.
|
||||
*
|
||||
* <p>A negated range includes everything except that defined by the
|
||||
* start and end characters.</p>
|
||||
*
|
||||
* <p>If start and end are in the wrong order, they are reversed.
|
||||
* Thus {@code a-e} is the same as {@code e-a}.</p>
|
||||
*
|
||||
* @param start first character, inclusive, in this range
|
||||
* @param end last character, inclusive, in this range
|
||||
* @return the new CharRange object
|
||||
* @since 2.5
|
||||
*/
|
||||
public static CharRange isNotIn(final char start, final char end) {
|
||||
return new CharRange(start, end, true);
|
||||
}
|
||||
|
||||
/** The first character, inclusive, in the range. */
|
||||
private final char start;
|
||||
|
||||
|
@ -52,9 +209,6 @@ final class CharRange implements Iterable<Character>, Serializable {
|
|||
/** Cached toString. */
|
||||
private transient String iToString;
|
||||
|
||||
/** Empty array. */
|
||||
static final CharRange[] EMPTY_ARRAY = {};
|
||||
|
||||
/**
|
||||
* Constructs a {@link CharRange} over a set of characters,
|
||||
* optionally negating the range.
|
||||
|
@ -81,95 +235,6 @@ final class CharRange implements Iterable<Character>, Serializable {
|
|||
this.negated = negated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link CharRange} over a single character.
|
||||
*
|
||||
* @param ch only character in this range
|
||||
* @return the new CharRange object
|
||||
* @since 2.5
|
||||
*/
|
||||
public static CharRange is(final char ch) {
|
||||
return new CharRange(ch, ch, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a negated {@link CharRange} over a single character.
|
||||
*
|
||||
* <p>A negated range includes everything except that defined by the
|
||||
* single character.</p>
|
||||
*
|
||||
* @param ch only character in this range
|
||||
* @return the new CharRange object
|
||||
* @since 2.5
|
||||
*/
|
||||
public static CharRange isNot(final char ch) {
|
||||
return new CharRange(ch, ch, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link CharRange} over a set of characters.
|
||||
*
|
||||
* <p>If start and end are in the wrong order, they are reversed.
|
||||
* Thus {@code a-e} is the same as {@code e-a}.</p>
|
||||
*
|
||||
* @param start first character, inclusive, in this range
|
||||
* @param end last character, inclusive, in this range
|
||||
* @return the new CharRange object
|
||||
* @since 2.5
|
||||
*/
|
||||
public static CharRange isIn(final char start, final char end) {
|
||||
return new CharRange(start, end, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a negated {@link CharRange} over a set of characters.
|
||||
*
|
||||
* <p>A negated range includes everything except that defined by the
|
||||
* start and end characters.</p>
|
||||
*
|
||||
* <p>If start and end are in the wrong order, they are reversed.
|
||||
* Thus {@code a-e} is the same as {@code e-a}.</p>
|
||||
*
|
||||
* @param start first character, inclusive, in this range
|
||||
* @param end last character, inclusive, in this range
|
||||
* @return the new CharRange object
|
||||
* @since 2.5
|
||||
*/
|
||||
public static CharRange isNotIn(final char start, final char end) {
|
||||
return new CharRange(start, end, true);
|
||||
}
|
||||
|
||||
// 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 {@link CharRange} negated.
|
||||
*
|
||||
* <p>A negated range includes everything except that defined by the
|
||||
* start and end characters.</p>
|
||||
*
|
||||
* @return {@code true} if negated
|
||||
*/
|
||||
public boolean isNegated() {
|
||||
return negated;
|
||||
}
|
||||
|
||||
// Contains
|
||||
/**
|
||||
* Is the character specified contained in this range.
|
||||
|
@ -223,6 +288,25 @@ final class CharRange implements Iterable<Character>, Serializable {
|
|||
return start == other.start && end == other.end && negated == other.negated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the end character for this character range.
|
||||
*
|
||||
* @return the end char (inclusive)
|
||||
*/
|
||||
public char getEnd() {
|
||||
return this.end;
|
||||
}
|
||||
|
||||
// Accessors
|
||||
/**
|
||||
* Gets the start character for this character range.
|
||||
*
|
||||
* @return the start char (inclusive)
|
||||
*/
|
||||
public char getStart() {
|
||||
return this.start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a hashCode compatible with the equals method.
|
||||
*
|
||||
|
@ -233,6 +317,30 @@ final class CharRange implements Iterable<Character>, Serializable {
|
|||
return 83 + start + 7 * end + (negated ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this {@link CharRange} negated.
|
||||
*
|
||||
* <p>A negated range includes everything except that defined by the
|
||||
* start and end characters.</p>
|
||||
*
|
||||
* @return {@code true} if negated
|
||||
*/
|
||||
public boolean isNegated() {
|
||||
return negated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator which can be used to walk through the characters described by this range.
|
||||
*
|
||||
* <p>#NotThreadSafe# the iterator is not thread-safe</p>
|
||||
* @return an iterator to the chars represented by this range
|
||||
* @since 2.5
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Character> iterator() {
|
||||
return new CharacterIterator(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string representation of the character range.
|
||||
*
|
||||
|
@ -254,112 +362,4 @@ final class CharRange implements Iterable<Character>, Serializable {
|
|||
}
|
||||
return iToString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator which can be used to walk through the characters described by this range.
|
||||
*
|
||||
* <p>#NotThreadSafe# the iterator is not thread-safe</p>
|
||||
* @return an iterator to the chars represented by this range
|
||||
* @since 2.5
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Character> iterator() {
|
||||
return new CharacterIterator(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Character {@link Iterator}.
|
||||
* <p>#NotThreadSafe#</p>
|
||||
*/
|
||||
private static final class CharacterIterator implements Iterator<Character> {
|
||||
/** The current character */
|
||||
private char current;
|
||||
|
||||
private final CharRange range;
|
||||
private boolean hasNext;
|
||||
|
||||
/**
|
||||
* Constructs a new iterator for the character range.
|
||||
*
|
||||
* @param r The character range
|
||||
*/
|
||||
private CharacterIterator(final 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares 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 {@code true} if the iterator has yet to reach the character date
|
||||
*/
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next character in the iteration
|
||||
*
|
||||
* @return {@link Character} for the next character
|
||||
*/
|
||||
@Override
|
||||
public Character next() {
|
||||
if (!hasNext) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
final char cur = current;
|
||||
prepareNext();
|
||||
return Character.valueOf(cur);
|
||||
}
|
||||
|
||||
/**
|
||||
* Always throws UnsupportedOperationException.
|
||||
*
|
||||
* @throws UnsupportedOperationException Always thrown.
|
||||
* @see java.util.Iterator#remove()
|
||||
*/
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,9 +88,6 @@ public class CharSet implements Serializable {
|
|||
COMMON.put("0-9", ASCII_NUMERIC);
|
||||
}
|
||||
|
||||
/** The set of CharRange objects. */
|
||||
private final Set<CharRange> set = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
/**
|
||||
* Factory method to create a new CharSet using a special syntax.
|
||||
*
|
||||
|
@ -165,6 +162,9 @@ public class CharSet implements Serializable {
|
|||
return new CharSet(setStrs);
|
||||
}
|
||||
|
||||
/** The set of CharRange objects. */
|
||||
private final Set<CharRange> set = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
/**
|
||||
* Constructs a new CharSet using the set syntax.
|
||||
* Each string is merged in with the set.
|
||||
|
@ -210,18 +210,6 @@ public class CharSet implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the internal set as an array of CharRange objects.
|
||||
*
|
||||
* @return an array of immutable CharRange objects
|
||||
* @since 2.0
|
||||
*/
|
||||
// NOTE: This is no longer public as CharRange is no longer a public class.
|
||||
// It may be replaced when CharSet moves to Range.
|
||||
/*public*/ CharRange[] getCharRanges() {
|
||||
return set.toArray(CharRange.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the {@link CharSet} contain the specified
|
||||
* character {@code ch}.
|
||||
|
@ -259,6 +247,18 @@ public class CharSet implements Serializable {
|
|||
return set.equals(other.set);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the internal set as an array of CharRange objects.
|
||||
*
|
||||
* @return an array of immutable CharRange objects
|
||||
* @since 2.0
|
||||
*/
|
||||
// NOTE: This is no longer public as CharRange is no longer a public class.
|
||||
// It may be replaced when CharSet moves to Range.
|
||||
/*public*/ CharRange[] getCharRanges() {
|
||||
return set.toArray(CharRange.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a hash code compatible with the equals method.
|
||||
*
|
||||
|
|
|
@ -64,54 +64,169 @@ public class CharUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* {@link CharUtils} instances should NOT be constructed in standard programming.
|
||||
* Instead, the class should be used as {@code CharUtils.toString('c');}.
|
||||
* Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.
|
||||
*
|
||||
* <p>This constructor is public to permit tools that require a JavaBean instance
|
||||
* to operate.</p>
|
||||
* @param x the first {@code char} to compare
|
||||
* @param y the second {@code char} to compare
|
||||
* @return the value {@code 0} if {@code x == y};
|
||||
* a value less than {@code 0} if {@code x < y}; and
|
||||
* a value greater than {@code 0} if {@code x > y}
|
||||
* @since 3.4
|
||||
*/
|
||||
public CharUtils() {
|
||||
public static int compare(final char x, final char y) {
|
||||
return x - y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the character to a Character.
|
||||
*
|
||||
* <p>For ASCII 7 bit characters, this uses a cache that will return the
|
||||
* same Character object each time.</p>
|
||||
* Checks whether the character is ASCII 7 bit.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.toCharacterObject(' ') = ' '
|
||||
* CharUtils.toCharacterObject('A') = 'A'
|
||||
* CharUtils.isAscii('a') = true
|
||||
* CharUtils.isAscii('A') = true
|
||||
* CharUtils.isAscii('3') = true
|
||||
* CharUtils.isAscii('-') = true
|
||||
* CharUtils.isAscii('\n') = true
|
||||
* CharUtils.isAscii('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127.
|
||||
* @param ch the character to convert
|
||||
* @return a Character of the specified character
|
||||
* @param ch the character to check
|
||||
* @return true if less than 128
|
||||
*/
|
||||
@Deprecated
|
||||
public static Character toCharacterObject(final char ch) {
|
||||
return Character.valueOf(ch);
|
||||
public static boolean isAscii(final char ch) {
|
||||
return ch < 128;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the String to a Character using the first character, returning
|
||||
* null for empty Strings.
|
||||
*
|
||||
* <p>For ASCII 7 bit characters, this uses a cache that will return the
|
||||
* same Character object each time.</p>
|
||||
* Checks whether the character is ASCII 7 bit alphabetic.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.toCharacterObject(null) = null
|
||||
* CharUtils.toCharacterObject("") = null
|
||||
* CharUtils.toCharacterObject("A") = 'A'
|
||||
* CharUtils.toCharacterObject("BA") = 'B'
|
||||
* CharUtils.isAsciiAlpha('a') = true
|
||||
* CharUtils.isAsciiAlpha('A') = true
|
||||
* CharUtils.isAsciiAlpha('3') = false
|
||||
* CharUtils.isAsciiAlpha('-') = false
|
||||
* CharUtils.isAsciiAlpha('\n') = false
|
||||
* CharUtils.isAsciiAlpha('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @param str the character to convert
|
||||
* @return the Character value of the first letter of the String
|
||||
* @param ch the character to check
|
||||
* @return true if between 65 and 90 or 97 and 122 inclusive
|
||||
*/
|
||||
public static Character toCharacterObject(final String str) {
|
||||
return StringUtils.isEmpty(str) ? null : Character.valueOf(str.charAt(0));
|
||||
public static boolean isAsciiAlpha(final char ch) {
|
||||
return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the character is ASCII 7 bit alphabetic lower case.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.isAsciiAlphaLower('a') = true
|
||||
* CharUtils.isAsciiAlphaLower('A') = false
|
||||
* CharUtils.isAsciiAlphaLower('3') = false
|
||||
* CharUtils.isAsciiAlphaLower('-') = false
|
||||
* CharUtils.isAsciiAlphaLower('\n') = false
|
||||
* CharUtils.isAsciiAlphaLower('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @return true if between 97 and 122 inclusive
|
||||
*/
|
||||
public static boolean isAsciiAlphaLower(final char ch) {
|
||||
return ch >= 'a' && ch <= 'z';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the character is ASCII 7 bit numeric.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.isAsciiAlphanumeric('a') = true
|
||||
* CharUtils.isAsciiAlphanumeric('A') = true
|
||||
* CharUtils.isAsciiAlphanumeric('3') = true
|
||||
* CharUtils.isAsciiAlphanumeric('-') = false
|
||||
* CharUtils.isAsciiAlphanumeric('\n') = false
|
||||
* CharUtils.isAsciiAlphanumeric('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @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(final char ch) {
|
||||
return isAsciiAlpha(ch) || isAsciiNumeric(ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the character is ASCII 7 bit alphabetic upper case.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.isAsciiAlphaUpper('a') = false
|
||||
* CharUtils.isAsciiAlphaUpper('A') = true
|
||||
* CharUtils.isAsciiAlphaUpper('3') = false
|
||||
* CharUtils.isAsciiAlphaUpper('-') = false
|
||||
* CharUtils.isAsciiAlphaUpper('\n') = false
|
||||
* CharUtils.isAsciiAlphaUpper('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @return true if between 65 and 90 inclusive
|
||||
*/
|
||||
public static boolean isAsciiAlphaUpper(final char ch) {
|
||||
return ch >= 'A' && ch <= 'Z';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the character is ASCII 7 bit control.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.isAsciiControl('a') = false
|
||||
* CharUtils.isAsciiControl('A') = false
|
||||
* CharUtils.isAsciiControl('3') = false
|
||||
* CharUtils.isAsciiControl('-') = false
|
||||
* CharUtils.isAsciiControl('\n') = true
|
||||
* CharUtils.isAsciiControl('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @return true if less than 32 or equals 127
|
||||
*/
|
||||
public static boolean isAsciiControl(final char ch) {
|
||||
return ch < 32 || ch == 127;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the character is ASCII 7 bit numeric.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.isAsciiNumeric('a') = false
|
||||
* CharUtils.isAsciiNumeric('A') = false
|
||||
* CharUtils.isAsciiNumeric('3') = true
|
||||
* CharUtils.isAsciiNumeric('-') = false
|
||||
* CharUtils.isAsciiNumeric('\n') = false
|
||||
* CharUtils.isAsciiNumeric('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @return true if between 48 and 57 inclusive
|
||||
*/
|
||||
public static boolean isAsciiNumeric(final char ch) {
|
||||
return ch >= '0' && ch <= '9';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the character is ASCII 7 bit printable.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.isAsciiPrintable('a') = true
|
||||
* CharUtils.isAsciiPrintable('A') = true
|
||||
* CharUtils.isAsciiPrintable('3') = true
|
||||
* CharUtils.isAsciiPrintable('-') = true
|
||||
* CharUtils.isAsciiPrintable('\n') = false
|
||||
* CharUtils.isAsciiPrintable('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @return true if between 32 and 126 inclusive
|
||||
*/
|
||||
public static boolean isAsciiPrintable(final char ch) {
|
||||
return ch >= 32 && ch < 127;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -188,6 +303,47 @@ public class CharUtils {
|
|||
return StringUtils.isEmpty(str) ? defaultValue : str.charAt(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the character to a Character.
|
||||
*
|
||||
* <p>For ASCII 7 bit characters, this uses a cache that will return the
|
||||
* same Character object each time.</p>
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.toCharacterObject(' ') = ' '
|
||||
* CharUtils.toCharacterObject('A') = 'A'
|
||||
* </pre>
|
||||
*
|
||||
* @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127.
|
||||
* @param ch the character to convert
|
||||
* @return a Character of the specified character
|
||||
*/
|
||||
@Deprecated
|
||||
public static Character toCharacterObject(final char ch) {
|
||||
return Character.valueOf(ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the String to a Character using the first character, returning
|
||||
* null for empty Strings.
|
||||
*
|
||||
* <p>For ASCII 7 bit characters, this uses a cache that will return the
|
||||
* same Character object each time.</p>
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.toCharacterObject(null) = null
|
||||
* CharUtils.toCharacterObject("") = null
|
||||
* CharUtils.toCharacterObject("A") = 'A'
|
||||
* CharUtils.toCharacterObject("BA") = 'B'
|
||||
* </pre>
|
||||
*
|
||||
* @param str the character to convert
|
||||
* @return the Character value of the first letter of the String
|
||||
*/
|
||||
public static Character toCharacterObject(final String str) {
|
||||
return StringUtils.isEmpty(str) ? null : Character.valueOf(str.charAt(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the character to the Integer it represents, throwing an
|
||||
* exception if the character is not numeric.
|
||||
|
@ -354,168 +510,12 @@ public class CharUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks whether the character is ASCII 7 bit.
|
||||
* {@link CharUtils} instances should NOT be constructed in standard programming.
|
||||
* Instead, the class should be used as {@code CharUtils.toString('c');}.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.isAscii('a') = true
|
||||
* CharUtils.isAscii('A') = true
|
||||
* CharUtils.isAscii('3') = true
|
||||
* CharUtils.isAscii('-') = true
|
||||
* CharUtils.isAscii('\n') = true
|
||||
* CharUtils.isAscii('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @return true if less than 128
|
||||
* <p>This constructor is public to permit tools that require a JavaBean instance
|
||||
* to operate.</p>
|
||||
*/
|
||||
public static boolean isAscii(final char ch) {
|
||||
return ch < 128;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the character is ASCII 7 bit printable.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.isAsciiPrintable('a') = true
|
||||
* CharUtils.isAsciiPrintable('A') = true
|
||||
* CharUtils.isAsciiPrintable('3') = true
|
||||
* CharUtils.isAsciiPrintable('-') = true
|
||||
* CharUtils.isAsciiPrintable('\n') = false
|
||||
* CharUtils.isAsciiPrintable('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @return true if between 32 and 126 inclusive
|
||||
*/
|
||||
public static boolean isAsciiPrintable(final char ch) {
|
||||
return ch >= 32 && ch < 127;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the character is ASCII 7 bit control.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.isAsciiControl('a') = false
|
||||
* CharUtils.isAsciiControl('A') = false
|
||||
* CharUtils.isAsciiControl('3') = false
|
||||
* CharUtils.isAsciiControl('-') = false
|
||||
* CharUtils.isAsciiControl('\n') = true
|
||||
* CharUtils.isAsciiControl('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @return true if less than 32 or equals 127
|
||||
*/
|
||||
public static boolean isAsciiControl(final char ch) {
|
||||
return ch < 32 || ch == 127;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the character is ASCII 7 bit alphabetic.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.isAsciiAlpha('a') = true
|
||||
* CharUtils.isAsciiAlpha('A') = true
|
||||
* CharUtils.isAsciiAlpha('3') = false
|
||||
* CharUtils.isAsciiAlpha('-') = false
|
||||
* CharUtils.isAsciiAlpha('\n') = false
|
||||
* CharUtils.isAsciiAlpha('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @return true if between 65 and 90 or 97 and 122 inclusive
|
||||
*/
|
||||
public static boolean isAsciiAlpha(final char ch) {
|
||||
return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the character is ASCII 7 bit alphabetic upper case.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.isAsciiAlphaUpper('a') = false
|
||||
* CharUtils.isAsciiAlphaUpper('A') = true
|
||||
* CharUtils.isAsciiAlphaUpper('3') = false
|
||||
* CharUtils.isAsciiAlphaUpper('-') = false
|
||||
* CharUtils.isAsciiAlphaUpper('\n') = false
|
||||
* CharUtils.isAsciiAlphaUpper('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @return true if between 65 and 90 inclusive
|
||||
*/
|
||||
public static boolean isAsciiAlphaUpper(final char ch) {
|
||||
return ch >= 'A' && ch <= 'Z';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the character is ASCII 7 bit alphabetic lower case.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.isAsciiAlphaLower('a') = true
|
||||
* CharUtils.isAsciiAlphaLower('A') = false
|
||||
* CharUtils.isAsciiAlphaLower('3') = false
|
||||
* CharUtils.isAsciiAlphaLower('-') = false
|
||||
* CharUtils.isAsciiAlphaLower('\n') = false
|
||||
* CharUtils.isAsciiAlphaLower('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @return true if between 97 and 122 inclusive
|
||||
*/
|
||||
public static boolean isAsciiAlphaLower(final char ch) {
|
||||
return ch >= 'a' && ch <= 'z';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the character is ASCII 7 bit numeric.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.isAsciiNumeric('a') = false
|
||||
* CharUtils.isAsciiNumeric('A') = false
|
||||
* CharUtils.isAsciiNumeric('3') = true
|
||||
* CharUtils.isAsciiNumeric('-') = false
|
||||
* CharUtils.isAsciiNumeric('\n') = false
|
||||
* CharUtils.isAsciiNumeric('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @return true if between 48 and 57 inclusive
|
||||
*/
|
||||
public static boolean isAsciiNumeric(final char ch) {
|
||||
return ch >= '0' && ch <= '9';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the character is ASCII 7 bit numeric.
|
||||
*
|
||||
* <pre>
|
||||
* CharUtils.isAsciiAlphanumeric('a') = true
|
||||
* CharUtils.isAsciiAlphanumeric('A') = true
|
||||
* CharUtils.isAsciiAlphanumeric('3') = true
|
||||
* CharUtils.isAsciiAlphanumeric('-') = false
|
||||
* CharUtils.isAsciiAlphanumeric('\n') = false
|
||||
* CharUtils.isAsciiAlphanumeric('©') = false
|
||||
* </pre>
|
||||
*
|
||||
* @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(final char ch) {
|
||||
return isAsciiAlpha(ch) || isAsciiNumeric(ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.
|
||||
*
|
||||
* @param x the first {@code char} to compare
|
||||
* @param y the second {@code char} to compare
|
||||
* @return the value {@code 0} if {@code x == y};
|
||||
* a value less than {@code 0} if {@code x < y}; and
|
||||
* a value greater than {@code 0} if {@code x > y}
|
||||
* @since 3.4
|
||||
*/
|
||||
public static int compare(final char x, final char y) {
|
||||
return x - y;
|
||||
public CharUtils() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1408,15 +1408,6 @@ public class ClassUtils {
|
|||
return cls != null && cls.getEnclosingClass() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a {@link Class} is public.
|
||||
* @param cls Class to test.
|
||||
* @return {@code true} if {@code cls} is public.
|
||||
* @since 3.13.0
|
||||
*/
|
||||
public static boolean isPublic(final Class<?> cls) {
|
||||
return Modifier.isPublic(cls.getModifiers());
|
||||
}
|
||||
/**
|
||||
* Returns whether the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte},
|
||||
* {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
|
||||
|
@ -1432,7 +1423,6 @@ public class ClassUtils {
|
|||
}
|
||||
return type.isPrimitive() || isPrimitiveWrapper(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
|
||||
* {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
|
||||
|
@ -1446,6 +1436,16 @@ public class ClassUtils {
|
|||
return wrapperPrimitiveMap.containsKey(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a {@link Class} is public.
|
||||
* @param cls Class to test.
|
||||
* @return {@code true} if {@code cls} is public.
|
||||
* @since 3.13.0
|
||||
*/
|
||||
public static boolean isPublic(final Class<?> cls) {
|
||||
return Modifier.isPublic(cls.getModifiers());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the specified array of primitive Class objects to an array of its corresponding wrapper Class objects.
|
||||
*
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -176,68 +176,6 @@ public enum JavaVersion {
|
|||
*/
|
||||
JAVA_RECENT(maxVersion(), Float.toString(maxVersion()));
|
||||
|
||||
/**
|
||||
* The float value.
|
||||
*/
|
||||
private final float value;
|
||||
|
||||
/**
|
||||
* The standard name.
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param value the float value
|
||||
* @param name the standard name, not null
|
||||
*/
|
||||
JavaVersion(final float value, final String name) {
|
||||
this.value = value;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this version of Java is at least the version of Java passed in.
|
||||
*
|
||||
* <p>For example:<br>
|
||||
* {@code myVersion.atLeast(JavaVersion.JAVA_1_4)}</p>
|
||||
*
|
||||
* @param requiredVersion the version to check against, not null
|
||||
* @return true if this version is equal to or greater than the specified version
|
||||
*/
|
||||
public boolean atLeast(final JavaVersion requiredVersion) {
|
||||
return this.value >= requiredVersion.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this version of Java is at most the version of Java passed in.
|
||||
*
|
||||
* <p>For example:<br>
|
||||
* {@code myVersion.atMost(JavaVersion.JAVA_1_4)}</p>
|
||||
*
|
||||
* @param requiredVersion the version to check against, not null
|
||||
* @return true if this version is equal to or greater than the specified version
|
||||
* @since 3.9
|
||||
*/
|
||||
public boolean atMost(final JavaVersion requiredVersion) {
|
||||
return this.value <= requiredVersion.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the given string with a Java version number to the
|
||||
* corresponding constant of this enumeration class. This method is used
|
||||
* internally.
|
||||
*
|
||||
* @param versionStr the Java version as string
|
||||
* @return the corresponding enumeration constant or <b>null</b> if the
|
||||
* version is unknown
|
||||
*/
|
||||
// helper for static importing
|
||||
static JavaVersion getJavaVersion(final String versionStr) {
|
||||
return get(versionStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the given string with a Java version number to the
|
||||
* corresponding constant of this enumeration class. This method is used
|
||||
|
@ -312,15 +250,17 @@ public enum JavaVersion {
|
|||
}
|
||||
|
||||
/**
|
||||
* The string value is overridden to return the standard name.
|
||||
* Transforms the given string with a Java version number to the
|
||||
* corresponding constant of this enumeration class. This method is used
|
||||
* internally.
|
||||
*
|
||||
* <p>For example, {@code "1.5"}.</p>
|
||||
*
|
||||
* @return the name, not null
|
||||
* @param versionStr the Java version as string
|
||||
* @return the corresponding enumeration constant or <b>null</b> if the
|
||||
* version is unknown
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
// helper for static importing
|
||||
static JavaVersion getJavaVersion(final String versionStr) {
|
||||
return get(versionStr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -350,4 +290,64 @@ public enum JavaVersion {
|
|||
}
|
||||
return defaultReturnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* The float value.
|
||||
*/
|
||||
private final float value;
|
||||
|
||||
/**
|
||||
* The standard name.
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param value the float value
|
||||
* @param name the standard name, not null
|
||||
*/
|
||||
JavaVersion(final float value, final String name) {
|
||||
this.value = value;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this version of Java is at least the version of Java passed in.
|
||||
*
|
||||
* <p>For example:<br>
|
||||
* {@code myVersion.atLeast(JavaVersion.JAVA_1_4)}</p>
|
||||
*
|
||||
* @param requiredVersion the version to check against, not null
|
||||
* @return true if this version is equal to or greater than the specified version
|
||||
*/
|
||||
public boolean atLeast(final JavaVersion requiredVersion) {
|
||||
return this.value >= requiredVersion.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this version of Java is at most the version of Java passed in.
|
||||
*
|
||||
* <p>For example:<br>
|
||||
* {@code myVersion.atMost(JavaVersion.JAVA_1_4)}</p>
|
||||
*
|
||||
* @param requiredVersion the version to check against, not null
|
||||
* @return true if this version is equal to or greater than the specified version
|
||||
* @since 3.9
|
||||
*/
|
||||
public boolean atMost(final JavaVersion requiredVersion) {
|
||||
return this.value <= requiredVersion.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The string value is overridden to return the standard name.
|
||||
*
|
||||
* <p>For example, {@code "1.5"}.</p>
|
||||
*
|
||||
* @return the name, not null
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,10 +39,6 @@ import java.util.stream.Collectors;
|
|||
*/
|
||||
public class LocaleUtils {
|
||||
|
||||
private static final char UNDERSCORE = '_';
|
||||
private static final String UNDETERMINED = "und";
|
||||
private static final char DASH = '-';
|
||||
|
||||
// class to avoid synchronization (Init on demand)
|
||||
static class SyncAvoid {
|
||||
/** Unmodifiable list of available locales. */
|
||||
|
@ -56,6 +52,10 @@ public class LocaleUtils {
|
|||
AVAILABLE_LOCALE_SET = Collections.unmodifiableSet(new HashSet<>(list));
|
||||
}
|
||||
}
|
||||
private static final char UNDERSCORE = '_';
|
||||
private static final String UNDETERMINED = "und";
|
||||
|
||||
private static final char DASH = '-';
|
||||
|
||||
/** Concurrent map of language locales by country. */
|
||||
private static final ConcurrentMap<String, List<Locale>> cLanguagesByCountry =
|
||||
|
|
|
@ -69,11 +69,13 @@ public class NotImplementedException extends UnsupportedOperationException {
|
|||
/**
|
||||
* Constructs a NotImplementedException.
|
||||
*
|
||||
* @param cause cause of the exception
|
||||
* @param message description of the exception
|
||||
* @param code code indicating a resource for more information regarding the lack of implementation
|
||||
* @since 3.2
|
||||
*/
|
||||
public NotImplementedException(final Throwable cause) {
|
||||
this(cause, null);
|
||||
public NotImplementedException(final String message, final String code) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,14 +93,25 @@ public class NotImplementedException extends UnsupportedOperationException {
|
|||
* Constructs a NotImplementedException.
|
||||
*
|
||||
* @param message description of the exception
|
||||
* @param cause cause of the exception
|
||||
* @param code code indicating a resource for more information regarding the lack of implementation
|
||||
* @since 3.2
|
||||
*/
|
||||
public NotImplementedException(final String message, final String code) {
|
||||
super(message);
|
||||
public NotImplementedException(final String message, final Throwable cause, final String code) {
|
||||
super(message, cause);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a NotImplementedException.
|
||||
*
|
||||
* @param cause cause of the exception
|
||||
* @since 3.2
|
||||
*/
|
||||
public NotImplementedException(final Throwable cause) {
|
||||
this(cause, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a NotImplementedException.
|
||||
*
|
||||
|
@ -111,19 +124,6 @@ public class NotImplementedException extends UnsupportedOperationException {
|
|||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a NotImplementedException.
|
||||
*
|
||||
* @param message description of the exception
|
||||
* @param cause cause of the exception
|
||||
* @param code code indicating a resource for more information regarding the lack of implementation
|
||||
* @since 3.2
|
||||
*/
|
||||
public NotImplementedException(final String message, final Throwable cause, final String code) {
|
||||
super(message, cause);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the not implemented code. This is an unformatted piece of text intended to point to
|
||||
* further information regarding the lack of implementation. It might, for example, be an issue
|
||||
|
|
|
@ -1333,6 +1333,30 @@ public class ObjectUtils {
|
|||
return obj == null ? nullStr : obj.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@code toString} of an {@link Supplier}'s {@link Supplier#get()} returning
|
||||
* a specified text if {@code null} input.
|
||||
*
|
||||
* <pre>
|
||||
* ObjectUtils.toString(() -> obj, () -> expensive())
|
||||
* </pre>
|
||||
* <pre>
|
||||
* ObjectUtils.toString(() -> null, () -> expensive()) = result of expensive()
|
||||
* ObjectUtils.toString(() -> null, () -> expensive()) = result of expensive()
|
||||
* ObjectUtils.toString(() -> "", () -> expensive()) = ""
|
||||
* ObjectUtils.toString(() -> "bat", () -> expensive()) = "bat"
|
||||
* ObjectUtils.toString(() -> Boolean.TRUE, () -> expensive()) = "true"
|
||||
* </pre>
|
||||
*
|
||||
* @param obj the Object to {@code toString}, may be null
|
||||
* @param supplier the Supplier of String used on {@code null} input, may be null
|
||||
* @return the passed in Object's toString, or {@code nullStr} if {@code null} input
|
||||
* @since 3.14.0
|
||||
*/
|
||||
public static String toString(final Supplier<Object> obj, final Supplier<String> supplier) {
|
||||
return obj == null ? Suppliers.get(supplier) : toString(obj.get(), supplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@code toString} of an {@link Object} returning
|
||||
* a specified text if {@code null} input.
|
||||
|
@ -1358,30 +1382,6 @@ public class ObjectUtils {
|
|||
return obj == null ? Suppliers.get(supplier) : obj.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@code toString} of an {@link Supplier}'s {@link Supplier#get()} returning
|
||||
* a specified text if {@code null} input.
|
||||
*
|
||||
* <pre>
|
||||
* ObjectUtils.toString(() -> obj, () -> expensive())
|
||||
* </pre>
|
||||
* <pre>
|
||||
* ObjectUtils.toString(() -> null, () -> expensive()) = result of expensive()
|
||||
* ObjectUtils.toString(() -> null, () -> expensive()) = result of expensive()
|
||||
* ObjectUtils.toString(() -> "", () -> expensive()) = ""
|
||||
* ObjectUtils.toString(() -> "bat", () -> expensive()) = "bat"
|
||||
* ObjectUtils.toString(() -> Boolean.TRUE, () -> expensive()) = "true"
|
||||
* </pre>
|
||||
*
|
||||
* @param obj the Object to {@code toString}, may be null
|
||||
* @param supplier the Supplier of String used on {@code null} input, may be null
|
||||
* @return the passed in Object's toString, or {@code nullStr} if {@code null} input
|
||||
* @since 3.14.0
|
||||
*/
|
||||
public static String toString(final Supplier<Object> obj, final Supplier<String> supplier) {
|
||||
return obj == null ? Suppliers.get(supplier) : toString(obj.get(), supplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link Object#wait(long, int)} for the given Duration.
|
||||
*
|
||||
|
|
|
@ -50,17 +50,6 @@ public class SerializationException extends RuntimeException {
|
|||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link SerializationException} with specified
|
||||
* nested {@link Throwable}.
|
||||
*
|
||||
* @param cause The {@link Exception} or {@link Error}
|
||||
* that caused this exception to be thrown.
|
||||
*/
|
||||
public SerializationException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link SerializationException} with specified
|
||||
* detail message and nested {@link Throwable}.
|
||||
|
@ -73,4 +62,15 @@ public class SerializationException extends RuntimeException {
|
|||
super(msg, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link SerializationException} with specified
|
||||
* nested {@link Throwable}.
|
||||
*
|
||||
* @param cause The {@link Exception} or {@link Error}
|
||||
* that caused this exception to be thrown.
|
||||
*/
|
||||
public SerializationException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -66,6 +66,55 @@ import org.apache.commons.lang3.Functions.FailablePredicate;
|
|||
@Deprecated
|
||||
public class Streams {
|
||||
|
||||
/**
|
||||
* A Collector type for arrays.
|
||||
*
|
||||
* @param <O> The array type.
|
||||
* @deprecated Use {@link org.apache.commons.lang3.stream.Streams.ArrayCollector}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static class ArrayCollector<O> implements Collector<O, List<O>, O[]> {
|
||||
private static final Set<Characteristics> characteristics = Collections.emptySet();
|
||||
private final Class<O> elementType;
|
||||
|
||||
/**
|
||||
* Constructs a new instance for the given element type.
|
||||
*
|
||||
* @param elementType The element type.
|
||||
*/
|
||||
public ArrayCollector(final Class<O> elementType) {
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiConsumer<List<O>, O> accumulator() {
|
||||
return List::add;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Characteristics> characteristics() {
|
||||
return characteristics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryOperator<List<O>> combiner() {
|
||||
return (left, right) -> {
|
||||
left.addAll(right);
|
||||
return left;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<List<O>, O[]> finisher() {
|
||||
return list -> list.toArray(ArrayUtils.newInstance(elementType, list.size()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<List<O>> supplier() {
|
||||
return ArrayList::new;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A reduced, and simplified version of a {@link Stream} with
|
||||
* failable method signatures.
|
||||
|
@ -86,6 +135,58 @@ public class Streams {
|
|||
this.stream = stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether all elements of this stream match the provided predicate.
|
||||
* May not evaluate the predicate on all elements if not necessary for
|
||||
* determining the result. If the stream is empty then {@code true} is
|
||||
* returned and the predicate is not evaluated.
|
||||
*
|
||||
* <p>
|
||||
* This is a short-circuiting terminal operation.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Note
|
||||
* This method evaluates the <em>universal quantification</em> of the
|
||||
* predicate over the elements of the stream (for all x P(x)). If the
|
||||
* stream is empty, the quantification is said to be <em>vacuously
|
||||
* satisfied</em> and is always {@code true} (regardless of P(x)).
|
||||
* </p>
|
||||
*
|
||||
* @param predicate A non-interfering, stateless predicate to apply to
|
||||
* elements of this stream
|
||||
* @return {@code true} If either all elements of the stream match the
|
||||
* provided predicate or the stream is empty, otherwise {@code false}.
|
||||
*/
|
||||
public boolean allMatch(final FailablePredicate<O, ?> predicate) {
|
||||
assertNotTerminated();
|
||||
return stream().allMatch(Functions.asPredicate(predicate));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether any elements of this stream match the provided
|
||||
* predicate. May not evaluate the predicate on all elements if not
|
||||
* necessary for determining the result. If the stream is empty then
|
||||
* {@code false} is returned and the predicate is not evaluated.
|
||||
*
|
||||
* <p>
|
||||
* This is a short-circuiting terminal operation.
|
||||
* </p>
|
||||
*
|
||||
* Note
|
||||
* This method evaluates the <em>existential quantification</em> of the
|
||||
* predicate over the elements of the stream (for some x P(x)).
|
||||
*
|
||||
* @param predicate A non-interfering, stateless predicate to apply to
|
||||
* elements of this stream
|
||||
* @return {@code true} if any elements of the stream match the provided
|
||||
* predicate, otherwise {@code false}
|
||||
*/
|
||||
public boolean anyMatch(final FailablePredicate<O, ?> predicate) {
|
||||
assertNotTerminated();
|
||||
return stream().anyMatch(Functions.asPredicate(predicate));
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws IllegalStateException if this stream is already terminated.
|
||||
*
|
||||
|
@ -97,58 +198,6 @@ public class Streams {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this stream as terminated.
|
||||
*
|
||||
* @throws IllegalStateException if this stream is already terminated.
|
||||
*/
|
||||
protected void makeTerminated() {
|
||||
assertNotTerminated();
|
||||
terminated = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a FailableStream consisting of the elements of this stream that match
|
||||
* the given FailablePredicate.
|
||||
*
|
||||
* <p>
|
||||
* This is an intermediate operation.
|
||||
* </p>
|
||||
*
|
||||
* @param predicate a non-interfering, stateless predicate to apply to each
|
||||
* element to determine if it should be included.
|
||||
* @return the new stream
|
||||
*/
|
||||
public FailableStream<O> filter(final FailablePredicate<O, ?> predicate){
|
||||
assertNotTerminated();
|
||||
stream = stream.filter(Functions.asPredicate(predicate));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an action for each element of this stream.
|
||||
*
|
||||
* <p>
|
||||
* This is an intermediate operation.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The behavior of this operation is explicitly nondeterministic.
|
||||
* For parallel stream pipelines, this operation does <em>not</em>
|
||||
* guarantee to respect the encounter order of the stream, as doing so
|
||||
* would sacrifice the benefit of parallelism. For any given element, the
|
||||
* action may be performed at whatever time and in whatever thread the
|
||||
* library chooses. If the action accesses shared state, it is
|
||||
* responsible for providing the required synchronization.
|
||||
* </p>
|
||||
*
|
||||
* @param action a non-interfering action to perform on the elements
|
||||
*/
|
||||
public void forEach(final FailableConsumer<O, ?> action) {
|
||||
makeTerminated();
|
||||
stream().forEach(Functions.asConsumer(action));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a mutable reduction operation on the elements of this stream using a
|
||||
* {@link Collector}. A {@link Collector}
|
||||
|
@ -271,6 +320,75 @@ public class Streams {
|
|||
return stream().collect(supplier, accumulator, combiner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a FailableStream consisting of the elements of this stream that match
|
||||
* the given FailablePredicate.
|
||||
*
|
||||
* <p>
|
||||
* This is an intermediate operation.
|
||||
* </p>
|
||||
*
|
||||
* @param predicate a non-interfering, stateless predicate to apply to each
|
||||
* element to determine if it should be included.
|
||||
* @return the new stream
|
||||
*/
|
||||
public FailableStream<O> filter(final FailablePredicate<O, ?> predicate){
|
||||
assertNotTerminated();
|
||||
stream = stream.filter(Functions.asPredicate(predicate));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an action for each element of this stream.
|
||||
*
|
||||
* <p>
|
||||
* This is an intermediate operation.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The behavior of this operation is explicitly nondeterministic.
|
||||
* For parallel stream pipelines, this operation does <em>not</em>
|
||||
* guarantee to respect the encounter order of the stream, as doing so
|
||||
* would sacrifice the benefit of parallelism. For any given element, the
|
||||
* action may be performed at whatever time and in whatever thread the
|
||||
* library chooses. If the action accesses shared state, it is
|
||||
* responsible for providing the required synchronization.
|
||||
* </p>
|
||||
*
|
||||
* @param action a non-interfering action to perform on the elements
|
||||
*/
|
||||
public void forEach(final FailableConsumer<O, ?> action) {
|
||||
makeTerminated();
|
||||
stream().forEach(Functions.asConsumer(action));
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this stream as terminated.
|
||||
*
|
||||
* @throws IllegalStateException if this stream is already terminated.
|
||||
*/
|
||||
protected void makeTerminated() {
|
||||
assertNotTerminated();
|
||||
terminated = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stream consisting of the results of applying the given
|
||||
* function to the elements of this stream.
|
||||
*
|
||||
* <p>
|
||||
* This is an intermediate operation.
|
||||
* </p>
|
||||
*
|
||||
* @param <R> The element type of the new stream
|
||||
* @param mapper A non-interfering, stateless function to apply to each element
|
||||
* @return the new stream
|
||||
*/
|
||||
public <R> FailableStream<R> map(final FailableFunction<O, R, ?> mapper) {
|
||||
assertNotTerminated();
|
||||
return new FailableStream<>(stream.map(Functions.asFunction(mapper)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a reduction on the elements of this stream, using the provided
|
||||
* identity value and an associative accumulation function, and returns
|
||||
|
@ -325,23 +443,6 @@ public class Streams {
|
|||
return stream().reduce(identity, accumulator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stream consisting of the results of applying the given
|
||||
* function to the elements of this stream.
|
||||
*
|
||||
* <p>
|
||||
* This is an intermediate operation.
|
||||
* </p>
|
||||
*
|
||||
* @param <R> The element type of the new stream
|
||||
* @param mapper A non-interfering, stateless function to apply to each element
|
||||
* @return the new stream
|
||||
*/
|
||||
public <R> FailableStream<R> map(final FailableFunction<O, R, ?> mapper) {
|
||||
assertNotTerminated();
|
||||
return new FailableStream<>(stream.map(Functions.asFunction(mapper)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the FailableStream into an equivalent stream.
|
||||
* @return A stream, which will return the same elements, which this FailableStream would return.
|
||||
|
@ -349,100 +450,6 @@ public class Streams {
|
|||
public Stream<O> stream() {
|
||||
return stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether all elements of this stream match the provided predicate.
|
||||
* May not evaluate the predicate on all elements if not necessary for
|
||||
* determining the result. If the stream is empty then {@code true} is
|
||||
* returned and the predicate is not evaluated.
|
||||
*
|
||||
* <p>
|
||||
* This is a short-circuiting terminal operation.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Note
|
||||
* This method evaluates the <em>universal quantification</em> of the
|
||||
* predicate over the elements of the stream (for all x P(x)). If the
|
||||
* stream is empty, the quantification is said to be <em>vacuously
|
||||
* satisfied</em> and is always {@code true} (regardless of P(x)).
|
||||
* </p>
|
||||
*
|
||||
* @param predicate A non-interfering, stateless predicate to apply to
|
||||
* elements of this stream
|
||||
* @return {@code true} If either all elements of the stream match the
|
||||
* provided predicate or the stream is empty, otherwise {@code false}.
|
||||
*/
|
||||
public boolean allMatch(final FailablePredicate<O, ?> predicate) {
|
||||
assertNotTerminated();
|
||||
return stream().allMatch(Functions.asPredicate(predicate));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether any elements of this stream match the provided
|
||||
* predicate. May not evaluate the predicate on all elements if not
|
||||
* necessary for determining the result. If the stream is empty then
|
||||
* {@code false} is returned and the predicate is not evaluated.
|
||||
*
|
||||
* <p>
|
||||
* This is a short-circuiting terminal operation.
|
||||
* </p>
|
||||
*
|
||||
* Note
|
||||
* This method evaluates the <em>existential quantification</em> of the
|
||||
* predicate over the elements of the stream (for some x P(x)).
|
||||
*
|
||||
* @param predicate A non-interfering, stateless predicate to apply to
|
||||
* elements of this stream
|
||||
* @return {@code true} if any elements of the stream match the provided
|
||||
* predicate, otherwise {@code false}
|
||||
*/
|
||||
public boolean anyMatch(final FailablePredicate<O, ?> predicate) {
|
||||
assertNotTerminated();
|
||||
return stream().anyMatch(Functions.asPredicate(predicate));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given {@link Stream stream} into a {@link FailableStream}.
|
||||
* This is basically a simplified, reduced version of the {@link Stream}
|
||||
* class, with the same underlying element stream, except that failable
|
||||
* objects, like {@link FailablePredicate}, {@link FailableFunction}, or
|
||||
* {@link FailableConsumer} may be applied, instead of
|
||||
* {@link Predicate}, {@link Function}, or {@link Consumer}. The idea is
|
||||
* to rewrite a code snippet like this:
|
||||
* <pre>
|
||||
* final List<O> list;
|
||||
* final Method m;
|
||||
* final Function<O,String> mapper = (o) -> {
|
||||
* try {
|
||||
* return (String) m.invoke(o);
|
||||
* } catch (Throwable t) {
|
||||
* throw Functions.rethrow(t);
|
||||
* }
|
||||
* };
|
||||
* final List<String> strList = list.stream()
|
||||
* .map(mapper).collect(Collectors.toList());
|
||||
* </pre>
|
||||
* as follows:
|
||||
* <pre>
|
||||
* final List<O> list;
|
||||
* final Method m;
|
||||
* final List<String> strList = Functions.stream(list.stream())
|
||||
* .map((o) -> (String) m.invoke(o)).collect(Collectors.toList());
|
||||
* </pre>
|
||||
* While the second version may not be <em>quite</em> as
|
||||
* efficient (because it depends on the creation of additional,
|
||||
* intermediate objects, of type FailableStream), it is much more
|
||||
* concise, and readable, and meets the spirit of Lambdas better
|
||||
* than the first version.
|
||||
* @param <O> The streams element type.
|
||||
* @param stream The stream, which is being converted.
|
||||
* @return The {@link FailableStream}, which has been created by
|
||||
* converting the stream.
|
||||
*/
|
||||
public static <O> FailableStream<O> stream(final Stream<O> stream) {
|
||||
return new FailableStream<>(stream);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -488,52 +495,45 @@ public class Streams {
|
|||
}
|
||||
|
||||
/**
|
||||
* A Collector type for arrays.
|
||||
*
|
||||
* @param <O> The array type.
|
||||
* @deprecated Use {@link org.apache.commons.lang3.stream.Streams.ArrayCollector}.
|
||||
* Converts the given {@link Stream stream} into a {@link FailableStream}.
|
||||
* This is basically a simplified, reduced version of the {@link Stream}
|
||||
* class, with the same underlying element stream, except that failable
|
||||
* objects, like {@link FailablePredicate}, {@link FailableFunction}, or
|
||||
* {@link FailableConsumer} may be applied, instead of
|
||||
* {@link Predicate}, {@link Function}, or {@link Consumer}. The idea is
|
||||
* to rewrite a code snippet like this:
|
||||
* <pre>
|
||||
* final List<O> list;
|
||||
* final Method m;
|
||||
* final Function<O,String> mapper = (o) -> {
|
||||
* try {
|
||||
* return (String) m.invoke(o);
|
||||
* } catch (Throwable t) {
|
||||
* throw Functions.rethrow(t);
|
||||
* }
|
||||
* };
|
||||
* final List<String> strList = list.stream()
|
||||
* .map(mapper).collect(Collectors.toList());
|
||||
* </pre>
|
||||
* as follows:
|
||||
* <pre>
|
||||
* final List<O> list;
|
||||
* final Method m;
|
||||
* final List<String> strList = Functions.stream(list.stream())
|
||||
* .map((o) -> (String) m.invoke(o)).collect(Collectors.toList());
|
||||
* </pre>
|
||||
* While the second version may not be <em>quite</em> as
|
||||
* efficient (because it depends on the creation of additional,
|
||||
* intermediate objects, of type FailableStream), it is much more
|
||||
* concise, and readable, and meets the spirit of Lambdas better
|
||||
* than the first version.
|
||||
* @param <O> The streams element type.
|
||||
* @param stream The stream, which is being converted.
|
||||
* @return The {@link FailableStream}, which has been created by
|
||||
* converting the stream.
|
||||
*/
|
||||
@Deprecated
|
||||
public static class ArrayCollector<O> implements Collector<O, List<O>, O[]> {
|
||||
private static final Set<Characteristics> characteristics = Collections.emptySet();
|
||||
private final Class<O> elementType;
|
||||
|
||||
/**
|
||||
* Constructs a new instance for the given element type.
|
||||
*
|
||||
* @param elementType The element type.
|
||||
*/
|
||||
public ArrayCollector(final Class<O> elementType) {
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<List<O>> supplier() {
|
||||
return ArrayList::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiConsumer<List<O>, O> accumulator() {
|
||||
return List::add;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryOperator<List<O>> combiner() {
|
||||
return (left, right) -> {
|
||||
left.addAll(right);
|
||||
return left;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<List<O>, O[]> finisher() {
|
||||
return list -> list.toArray(ArrayUtils.newInstance(elementType, list.size()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Characteristics> characteristics() {
|
||||
return characteristics;
|
||||
}
|
||||
public static <O> FailableStream<O> stream(final Stream<O> stream) {
|
||||
return new FailableStream<>(stream);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -45,6 +45,66 @@ public class StringEscapeUtils {
|
|||
|
||||
/* ESCAPE TRANSLATORS */
|
||||
|
||||
// TODO: Create a parent class - 'SinglePassTranslator' ?
|
||||
// It would handle the index checking + length returning,
|
||||
// and could also have an optimization check method.
|
||||
static class CsvEscaper extends CharSequenceTranslator {
|
||||
|
||||
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 = { CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, CharUtils.LF };
|
||||
|
||||
@Override
|
||||
public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
|
||||
|
||||
if (index != 0) {
|
||||
throw new IllegalStateException("CsvEscaper should never reach the [1] index");
|
||||
}
|
||||
|
||||
if (StringUtils.containsNone(input.toString(), CSV_SEARCH_CHARS)) {
|
||||
out.write(input.toString());
|
||||
} else {
|
||||
out.write(CSV_QUOTE);
|
||||
out.write(StringUtils.replace(input.toString(), CSV_QUOTE_STR, CSV_QUOTE_STR + CSV_QUOTE_STR));
|
||||
out.write(CSV_QUOTE);
|
||||
}
|
||||
return Character.codePointCount(input, 0, input.length());
|
||||
}
|
||||
}
|
||||
|
||||
static class CsvUnescaper extends CharSequenceTranslator {
|
||||
|
||||
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 = {CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, CharUtils.LF};
|
||||
|
||||
@Override
|
||||
public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
|
||||
|
||||
if (index != 0) {
|
||||
throw new IllegalStateException("CsvUnescaper should never reach the [1] index");
|
||||
}
|
||||
|
||||
if ( input.charAt(0) != CSV_QUOTE || input.charAt(input.length() - 1) != CSV_QUOTE ) {
|
||||
out.write(input.toString());
|
||||
return Character.codePointCount(input, 0, input.length());
|
||||
}
|
||||
|
||||
// strip quotes
|
||||
final String quoteless = input.subSequence(1, input.length() - 1).toString();
|
||||
|
||||
if ( StringUtils.containsAny(quoteless, CSV_SEARCH_CHARS) ) {
|
||||
// deal with escaped quotes; ie) ""
|
||||
out.write(StringUtils.replace(quoteless, CSV_QUOTE_STR + CSV_QUOTE_STR, CSV_QUOTE_STR));
|
||||
} else {
|
||||
out.write(input.toString());
|
||||
}
|
||||
return Character.codePointCount(input, 0, input.length());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translator object for escaping Java.
|
||||
*
|
||||
|
@ -236,6 +296,8 @@ public class StringEscapeUtils {
|
|||
new LookupTranslator(EntityArrays.HTML40_EXTENDED_ESCAPE())
|
||||
);
|
||||
|
||||
/* UNESCAPE TRANSLATORS */
|
||||
|
||||
/**
|
||||
* Translator object for escaping individual Comma Separated Values.
|
||||
*
|
||||
|
@ -247,36 +309,6 @@ public class StringEscapeUtils {
|
|||
*/
|
||||
public static final CharSequenceTranslator ESCAPE_CSV = new CsvEscaper();
|
||||
|
||||
// TODO: Create a parent class - 'SinglePassTranslator' ?
|
||||
// It would handle the index checking + length returning,
|
||||
// and could also have an optimization check method.
|
||||
static class CsvEscaper extends CharSequenceTranslator {
|
||||
|
||||
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 = { CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, CharUtils.LF };
|
||||
|
||||
@Override
|
||||
public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
|
||||
|
||||
if (index != 0) {
|
||||
throw new IllegalStateException("CsvEscaper should never reach the [1] index");
|
||||
}
|
||||
|
||||
if (StringUtils.containsNone(input.toString(), CSV_SEARCH_CHARS)) {
|
||||
out.write(input.toString());
|
||||
} else {
|
||||
out.write(CSV_QUOTE);
|
||||
out.write(StringUtils.replace(input.toString(), CSV_QUOTE_STR, CSV_QUOTE_STR + CSV_QUOTE_STR));
|
||||
out.write(CSV_QUOTE);
|
||||
}
|
||||
return Character.codePointCount(input, 0, input.length());
|
||||
}
|
||||
}
|
||||
|
||||
/* UNESCAPE TRANSLATORS */
|
||||
|
||||
/**
|
||||
* Translator object for unescaping escaped Java.
|
||||
*
|
||||
|
@ -383,75 +415,30 @@ public class StringEscapeUtils {
|
|||
*/
|
||||
public static final CharSequenceTranslator UNESCAPE_CSV = new CsvUnescaper();
|
||||
|
||||
static class CsvUnescaper extends CharSequenceTranslator {
|
||||
|
||||
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 = {CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, CharUtils.LF};
|
||||
|
||||
@Override
|
||||
public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
|
||||
|
||||
if (index != 0) {
|
||||
throw new IllegalStateException("CsvUnescaper should never reach the [1] index");
|
||||
}
|
||||
|
||||
if ( input.charAt(0) != CSV_QUOTE || input.charAt(input.length() - 1) != CSV_QUOTE ) {
|
||||
out.write(input.toString());
|
||||
return Character.codePointCount(input, 0, input.length());
|
||||
}
|
||||
|
||||
// strip quotes
|
||||
final String quoteless = input.subSequence(1, input.length() - 1).toString();
|
||||
|
||||
if ( StringUtils.containsAny(quoteless, CSV_SEARCH_CHARS) ) {
|
||||
// deal with escaped quotes; ie) ""
|
||||
out.write(StringUtils.replace(quoteless, CSV_QUOTE_STR + CSV_QUOTE_STR, CSV_QUOTE_STR));
|
||||
} else {
|
||||
out.write(input.toString());
|
||||
}
|
||||
return Character.codePointCount(input, 0, input.length());
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper functions */
|
||||
|
||||
/**
|
||||
* {@link StringEscapeUtils} instances should NOT be constructed in
|
||||
* standard programming.
|
||||
* Returns a {@link String} value for a CSV column enclosed in double quotes,
|
||||
* if required.
|
||||
*
|
||||
* <p>Instead, the class should be used as:</p>
|
||||
* <pre>StringEscapeUtils.escapeJava("foo");</pre>
|
||||
* <p>If the value contains a comma, newline or double quote, then the
|
||||
* String value is returned enclosed in double quotes.</p>
|
||||
*
|
||||
* <p>This constructor is public to permit tools that require a JavaBean
|
||||
* instance to operate.</p>
|
||||
* <p>Any double quote characters in the value are escaped with another double quote.</p>
|
||||
*
|
||||
* <p>If the value does not contain a comma, newline or double quote, then the
|
||||
* String value is returned unchanged.</p>
|
||||
*
|
||||
* see <a href="https://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia</a> and
|
||||
* <a href="https://datatracker.ietf.org/doc/html/rfc4180">RFC 4180</a>.
|
||||
*
|
||||
* @param input 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, {@code null} if null string input
|
||||
* @since 2.4
|
||||
*/
|
||||
public StringEscapeUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes the characters in a {@link String} using Java String rules.
|
||||
*
|
||||
* <p>Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
|
||||
*
|
||||
* <p>So a tab becomes the characters {@code '\\'} and
|
||||
* {@code 't'}.</p>
|
||||
*
|
||||
* <p>The only difference between Java strings and JavaScript strings
|
||||
* is that in JavaScript, a single quote and forward-slash (/) are escaped.</p>
|
||||
*
|
||||
* <p>Example:</p>
|
||||
* <pre>
|
||||
* input string: He didn't say, "Stop!"
|
||||
* output string: He didn't say, \"Stop!\"
|
||||
* </pre>
|
||||
*
|
||||
* @param input String to escape values in, may be null
|
||||
* @return String with escaped values, {@code null} if null string input
|
||||
*/
|
||||
public static final String escapeJava(final String input) {
|
||||
return ESCAPE_JAVA.translate(input);
|
||||
public static final String escapeCsv(final String input) {
|
||||
return ESCAPE_CSV.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -483,78 +470,16 @@ public class StringEscapeUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Escapes the characters in a {@link String} using Json String rules.
|
||||
* <p>Escapes any values it finds into their Json String form.
|
||||
* Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
|
||||
* Escapes the characters in a {@link String} using HTML entities.
|
||||
* <p>Supports only the HTML 3.0 entities.</p>
|
||||
*
|
||||
* <p>So a tab becomes the characters {@code '\\'} and
|
||||
* {@code 't'}.</p>
|
||||
*
|
||||
* <p>The only difference between Java strings and Json strings
|
||||
* is that in Json, forward-slash (/) is escaped.</p>
|
||||
*
|
||||
* <p>See https://www.ietf.org/rfc/rfc4627.txt for further details.</p>
|
||||
*
|
||||
* <p>Example:</p>
|
||||
* <pre>
|
||||
* input string: He didn't say, "Stop!"
|
||||
* output string: He didn't say, \"Stop!\"
|
||||
* </pre>
|
||||
*
|
||||
* @param input String to escape values in, may be null
|
||||
* @return String with escaped values, {@code null} if null string input
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static final String escapeJson(final String input) {
|
||||
return ESCAPE_JSON.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes any Java literals found in the {@link String}.
|
||||
* For example, it will turn a sequence of {@code '\'} and
|
||||
* {@code 'n'} into a newline character, unless the {@code '\'}
|
||||
* is preceded by another {@code '\'}.
|
||||
*
|
||||
* @param input the {@link String} to unescape, may be null
|
||||
* @return a new unescaped {@link String}, {@code null} if null string input
|
||||
*/
|
||||
public static final String unescapeJava(final String input) {
|
||||
return UNESCAPE_JAVA.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes any EcmaScript literals found in the {@link String}.
|
||||
*
|
||||
* <p>For example, it will turn a sequence of {@code '\'} and {@code 'n'}
|
||||
* into a newline character, unless the {@code '\'} is preceded by another
|
||||
* {@code '\'}.</p>
|
||||
*
|
||||
* @see #unescapeJava(String)
|
||||
* @param input the {@link String} to unescape, may be null
|
||||
* @return A new unescaped {@link String}, {@code null} if null string input
|
||||
* @param input the {@link String} to escape, may be null
|
||||
* @return a new escaped {@link String}, {@code null} if null string input
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public static final String unescapeEcmaScript(final String input) {
|
||||
return UNESCAPE_ECMASCRIPT.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes any Json literals found in the {@link String}.
|
||||
*
|
||||
* <p>For example, it will turn a sequence of {@code '\'} and {@code 'n'}
|
||||
* into a newline character, unless the {@code '\'} is preceded by another
|
||||
* {@code '\'}.</p>
|
||||
*
|
||||
* @see #unescapeJava(String)
|
||||
* @param input the {@link String} to unescape, may be null
|
||||
* @return A new unescaped {@link String}, {@code null} if null string input
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static final String unescapeJson(final String input) {
|
||||
return UNESCAPE_JSON.translate(input);
|
||||
public static final String escapeHtml3(final String input) {
|
||||
return ESCAPE_HTML3.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -589,51 +514,55 @@ public class StringEscapeUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Escapes the characters in a {@link String} using HTML entities.
|
||||
* <p>Supports only the HTML 3.0 entities.</p>
|
||||
* Escapes the characters in a {@link String} using Java String rules.
|
||||
*
|
||||
* @param input the {@link String} to escape, may be null
|
||||
* @return a new escaped {@link String}, {@code null} if null string input
|
||||
* <p>Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
|
||||
*
|
||||
* @since 3.0
|
||||
* <p>So a tab becomes the characters {@code '\\'} and
|
||||
* {@code 't'}.</p>
|
||||
*
|
||||
* <p>The only difference between Java strings and JavaScript strings
|
||||
* is that in JavaScript, a single quote and forward-slash (/) are escaped.</p>
|
||||
*
|
||||
* <p>Example:</p>
|
||||
* <pre>
|
||||
* input string: He didn't say, "Stop!"
|
||||
* output string: He didn't say, \"Stop!\"
|
||||
* </pre>
|
||||
*
|
||||
* @param input String to escape values in, may be null
|
||||
* @return String with escaped values, {@code null} if null string input
|
||||
*/
|
||||
public static final String escapeHtml3(final String input) {
|
||||
return ESCAPE_HTML3.translate(input);
|
||||
public static final String escapeJava(final String input) {
|
||||
return ESCAPE_JAVA.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes a string containing entity escapes to a string
|
||||
* containing the actual Unicode characters corresponding to the
|
||||
* escapes. Supports HTML 4.0 entities.
|
||||
* Escapes the characters in a {@link String} using Json String rules.
|
||||
* <p>Escapes any values it finds into their Json String form.
|
||||
* Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
|
||||
*
|
||||
* <p>For example, the string {@code "<Français>"}
|
||||
* will become {@code "<Français>"}</p>
|
||||
* <p>So a tab becomes the characters {@code '\\'} and
|
||||
* {@code 't'}.</p>
|
||||
*
|
||||
* <p>If an entity is unrecognized, it is left alone, and inserted
|
||||
* verbatim into the result string. e.g. {@code ">&zzzz;x"} will
|
||||
* become {@code ">&zzzz;x"}.</p>
|
||||
* <p>The only difference between Java strings and Json strings
|
||||
* is that in Json, forward-slash (/) is escaped.</p>
|
||||
*
|
||||
* @param input the {@link String} to unescape, may be null
|
||||
* @return a new unescaped {@link String}, {@code null} if null string input
|
||||
* <p>See https://www.ietf.org/rfc/rfc4627.txt for further details.</p>
|
||||
*
|
||||
* @since 3.0
|
||||
* <p>Example:</p>
|
||||
* <pre>
|
||||
* input string: He didn't say, "Stop!"
|
||||
* output string: He didn't say, \"Stop!\"
|
||||
* </pre>
|
||||
*
|
||||
* @param input String to escape values in, may be null
|
||||
* @return String with escaped values, {@code null} if null string input
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static final String unescapeHtml4(final String input) {
|
||||
return UNESCAPE_HTML4.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes a string containing entity escapes to a string
|
||||
* containing the actual Unicode characters corresponding to the
|
||||
* escapes. Supports only HTML 3.0 entities.
|
||||
*
|
||||
* @param input the {@link String} to unescape, may be null
|
||||
* @return a new unescaped {@link String}, {@code null} if null string input
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public static final String unescapeHtml3(final String input) {
|
||||
return UNESCAPE_HTML3.translate(input);
|
||||
public static final String escapeJson(final String input) {
|
||||
return ESCAPE_JSON.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -723,52 +652,6 @@ public class StringEscapeUtils {
|
|||
return ESCAPE_XML11.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes a string containing XML entity escapes to a string
|
||||
* containing the actual Unicode characters corresponding to the
|
||||
* escapes.
|
||||
*
|
||||
* <p>Supports only the five basic XML entities (gt, lt, quot, amp, apos).
|
||||
* Does not support DTDs or external entities.</p>
|
||||
*
|
||||
* <p>Note that numerical \\u Unicode codes are unescaped to their respective
|
||||
* Unicode characters. This may change in future releases.</p>
|
||||
*
|
||||
* @param input the {@link String} to unescape, may be null
|
||||
* @return a new unescaped {@link String}, {@code null} if null string input
|
||||
* @see #escapeXml(String)
|
||||
* @see #escapeXml10(String)
|
||||
* @see #escapeXml11(String)
|
||||
*/
|
||||
public static final String unescapeXml(final String input) {
|
||||
return UNESCAPE_XML.translate(input);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a {@link String} value for a CSV column enclosed in double quotes,
|
||||
* if required.
|
||||
*
|
||||
* <p>If the value contains a comma, newline or double quote, then the
|
||||
* String value is returned enclosed in double quotes.</p>
|
||||
*
|
||||
* <p>Any double quote characters in the value are escaped with another double quote.</p>
|
||||
*
|
||||
* <p>If the value does not contain a comma, newline or double quote, then the
|
||||
* String value is returned unchanged.</p>
|
||||
*
|
||||
* see <a href="https://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia</a> and
|
||||
* <a href="https://datatracker.ietf.org/doc/html/rfc4180">RFC 4180</a>.
|
||||
*
|
||||
* @param input 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, {@code null} if null string input
|
||||
* @since 2.4
|
||||
*/
|
||||
public static final String escapeCsv(final String input) {
|
||||
return ESCAPE_CSV.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link String} value for an unescaped CSV column.
|
||||
*
|
||||
|
@ -794,4 +677,121 @@ public class StringEscapeUtils {
|
|||
return UNESCAPE_CSV.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes any EcmaScript literals found in the {@link String}.
|
||||
*
|
||||
* <p>For example, it will turn a sequence of {@code '\'} and {@code 'n'}
|
||||
* into a newline character, unless the {@code '\'} is preceded by another
|
||||
* {@code '\'}.</p>
|
||||
*
|
||||
* @see #unescapeJava(String)
|
||||
* @param input the {@link String} to unescape, may be null
|
||||
* @return A new unescaped {@link String}, {@code null} if null string input
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public static final String unescapeEcmaScript(final String input) {
|
||||
return UNESCAPE_ECMASCRIPT.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes a string containing entity escapes to a string
|
||||
* containing the actual Unicode characters corresponding to the
|
||||
* escapes. Supports only HTML 3.0 entities.
|
||||
*
|
||||
* @param input the {@link String} to unescape, may be null
|
||||
* @return a new unescaped {@link String}, {@code null} if null string input
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public static final String unescapeHtml3(final String input) {
|
||||
return UNESCAPE_HTML3.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes a string containing entity escapes to a string
|
||||
* containing the actual Unicode characters corresponding to the
|
||||
* escapes. Supports HTML 4.0 entities.
|
||||
*
|
||||
* <p>For example, the string {@code "<Français>"}
|
||||
* will become {@code "<Français>"}</p>
|
||||
*
|
||||
* <p>If an entity is unrecognized, it is left alone, and inserted
|
||||
* verbatim into the result string. e.g. {@code ">&zzzz;x"} will
|
||||
* become {@code ">&zzzz;x"}.</p>
|
||||
*
|
||||
* @param input the {@link String} to unescape, may be null
|
||||
* @return a new unescaped {@link String}, {@code null} if null string input
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public static final String unescapeHtml4(final String input) {
|
||||
return UNESCAPE_HTML4.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes any Java literals found in the {@link String}.
|
||||
* For example, it will turn a sequence of {@code '\'} and
|
||||
* {@code 'n'} into a newline character, unless the {@code '\'}
|
||||
* is preceded by another {@code '\'}.
|
||||
*
|
||||
* @param input the {@link String} to unescape, may be null
|
||||
* @return a new unescaped {@link String}, {@code null} if null string input
|
||||
*/
|
||||
public static final String unescapeJava(final String input) {
|
||||
return UNESCAPE_JAVA.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes any Json literals found in the {@link String}.
|
||||
*
|
||||
* <p>For example, it will turn a sequence of {@code '\'} and {@code 'n'}
|
||||
* into a newline character, unless the {@code '\'} is preceded by another
|
||||
* {@code '\'}.</p>
|
||||
*
|
||||
* @see #unescapeJava(String)
|
||||
* @param input the {@link String} to unescape, may be null
|
||||
* @return A new unescaped {@link String}, {@code null} if null string input
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static final String unescapeJson(final String input) {
|
||||
return UNESCAPE_JSON.translate(input);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unescapes a string containing XML entity escapes to a string
|
||||
* containing the actual Unicode characters corresponding to the
|
||||
* escapes.
|
||||
*
|
||||
* <p>Supports only the five basic XML entities (gt, lt, quot, amp, apos).
|
||||
* Does not support DTDs or external entities.</p>
|
||||
*
|
||||
* <p>Note that numerical \\u Unicode codes are unescaped to their respective
|
||||
* Unicode characters. This may change in future releases.</p>
|
||||
*
|
||||
* @param input the {@link String} to unescape, may be null
|
||||
* @return a new unescaped {@link String}, {@code null} if null string input
|
||||
* @see #escapeXml(String)
|
||||
* @see #escapeXml10(String)
|
||||
* @see #escapeXml11(String)
|
||||
*/
|
||||
public static final String unescapeXml(final String input) {
|
||||
return UNESCAPE_XML.translate(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link StringEscapeUtils} instances should NOT be constructed in
|
||||
* standard programming.
|
||||
*
|
||||
* <p>Instead, the class should be used as:</p>
|
||||
* <pre>StringEscapeUtils.escapeJava("foo");</pre>
|
||||
*
|
||||
* <p>This constructor is public to permit tools that require a JavaBean
|
||||
* instance to operate.</p>
|
||||
*/
|
||||
public StringEscapeUtils() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -60,6 +60,15 @@ public abstract class Diff<T> extends Pair<T, T> {
|
|||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the field.
|
||||
*
|
||||
* @return the field name
|
||||
*/
|
||||
public final String getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the field.
|
||||
*
|
||||
|
@ -70,12 +79,15 @@ public abstract class Diff<T> extends Pair<T, T> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the field.
|
||||
* Throws {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @return the field name
|
||||
* @param value
|
||||
* ignored
|
||||
* @return nothing
|
||||
*/
|
||||
public final String getFieldName() {
|
||||
return fieldName;
|
||||
@Override
|
||||
public final T setValue(final T value) {
|
||||
throw new UnsupportedOperationException("Cannot alter Diff object.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -92,16 +104,4 @@ public abstract class Diff<T> extends Pair<T, T> {
|
|||
public final String toString() {
|
||||
return String.format("[%s: %s, %s]", fieldName, getLeft(), getRight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @param value
|
||||
* ignored
|
||||
* @return nothing
|
||||
*/
|
||||
@Override
|
||||
public final T setValue(final T value) {
|
||||
throw new UnsupportedOperationException("Cannot alter Diff object.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,36 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
|
|||
private final T right;
|
||||
private final ToStringStyle style;
|
||||
|
||||
/**
|
||||
* Constructs a builder for the specified objects with the specified style.
|
||||
*
|
||||
* <p>
|
||||
* If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will
|
||||
* not evaluate any calls to {@code append(...)} and will return an empty
|
||||
* {@link DiffResult} when {@link #build()} is executed.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This delegates to {@link #DiffBuilder(Object, Object, ToStringStyle, boolean)}
|
||||
* with the testTriviallyEqual flag enabled.
|
||||
* </p>
|
||||
*
|
||||
* @param lhs
|
||||
* {@code this} object
|
||||
* @param rhs
|
||||
* the object to diff against
|
||||
* @param style
|
||||
* the style will use when outputting the objects, {@code null}
|
||||
* uses the default
|
||||
* @throws NullPointerException
|
||||
* if {@code lhs} or {@code rhs} is {@code null}
|
||||
*/
|
||||
public DiffBuilder(final T lhs, final T rhs,
|
||||
final ToStringStyle style) {
|
||||
|
||||
this(lhs, rhs, style, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a builder for the specified objects with the specified style.
|
||||
*
|
||||
|
@ -117,36 +147,6 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
|
|||
this.objectsTriviallyEqual = testTriviallyEqual && Objects.equals(lhs, rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a builder for the specified objects with the specified style.
|
||||
*
|
||||
* <p>
|
||||
* If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will
|
||||
* not evaluate any calls to {@code append(...)} and will return an empty
|
||||
* {@link DiffResult} when {@link #build()} is executed.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This delegates to {@link #DiffBuilder(Object, Object, ToStringStyle, boolean)}
|
||||
* with the testTriviallyEqual flag enabled.
|
||||
* </p>
|
||||
*
|
||||
* @param lhs
|
||||
* {@code this} object
|
||||
* @param rhs
|
||||
* the object to diff against
|
||||
* @param style
|
||||
* the style will use when outputting the objects, {@code null}
|
||||
* uses the default
|
||||
* @throws NullPointerException
|
||||
* if {@code lhs} or {@code rhs} is {@code null}
|
||||
*/
|
||||
public DiffBuilder(final T lhs, final T rhs,
|
||||
final ToStringStyle style) {
|
||||
|
||||
this(lhs, rhs, style, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if two {@code boolean}s are equal.
|
||||
*
|
||||
|
@ -373,6 +373,49 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append diffs from another {@link DiffResult}.
|
||||
*
|
||||
* <p>
|
||||
* This method is useful if you want to compare properties which are
|
||||
* themselves Diffable and would like to know which specific part of
|
||||
* it is different.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* public class Person implements Diffable<Person> {
|
||||
* String name;
|
||||
* Address address; // implements Diffable<Address>
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* public DiffResult diff(Person obj) {
|
||||
* return new DiffBuilder(this, obj, ToStringStyle.SHORT_PREFIX_STYLE)
|
||||
* .append("name", this.name, obj.name)
|
||||
* .append("address", this.address.diff(obj.address))
|
||||
* .build();
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param fieldName
|
||||
* the field name
|
||||
* @param diffResult
|
||||
* the {@link DiffResult} to append
|
||||
* @return this
|
||||
* @throws NullPointerException if field name is {@code null} or diffResult is {@code null}
|
||||
* @since 3.5
|
||||
*/
|
||||
public DiffBuilder<T> append(final String fieldName, final DiffResult<T> diffResult) {
|
||||
validateFieldNameNotNull(fieldName);
|
||||
Objects.requireNonNull(diffResult, "diffResult");
|
||||
if (objectsTriviallyEqual) {
|
||||
return this;
|
||||
}
|
||||
diffResult.getDiffs().forEach(diff -> append(fieldName + "." + diff.getFieldName(), diff.getLeft(), diff.getRight()));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if two {@code double}s are equal.
|
||||
*
|
||||
|
@ -677,82 +720,6 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if two {@code short}s are equal.
|
||||
*
|
||||
* @param fieldName
|
||||
* the field name
|
||||
* @param lhs
|
||||
* the left-hand {@code short}
|
||||
* @param rhs
|
||||
* the right-hand {@code short}
|
||||
* @return this
|
||||
* @throws NullPointerException
|
||||
* if field name is {@code null}
|
||||
*/
|
||||
public DiffBuilder<T> append(final String fieldName, final short lhs,
|
||||
final short rhs) {
|
||||
validateFieldNameNotNull(fieldName);
|
||||
|
||||
if (objectsTriviallyEqual) {
|
||||
return this;
|
||||
}
|
||||
if (lhs != rhs) {
|
||||
diffs.add(new Diff<Short>(fieldName) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Short getLeft() {
|
||||
return Short.valueOf(lhs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Short getRight() {
|
||||
return Short.valueOf(rhs);
|
||||
}
|
||||
});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if two {@code short[]}s are equal.
|
||||
*
|
||||
* @param fieldName
|
||||
* the field name
|
||||
* @param lhs
|
||||
* the left-hand {@code short[]}
|
||||
* @param rhs
|
||||
* the right-hand {@code short[]}
|
||||
* @return this
|
||||
* @throws NullPointerException
|
||||
* if field name is {@code null}
|
||||
*/
|
||||
public DiffBuilder<T> append(final String fieldName, final short[] lhs,
|
||||
final short[] rhs) {
|
||||
validateFieldNameNotNull(fieldName);
|
||||
|
||||
if (objectsTriviallyEqual) {
|
||||
return this;
|
||||
}
|
||||
if (!Arrays.equals(lhs, rhs)) {
|
||||
diffs.add(new Diff<Short[]>(fieldName) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Short[] getLeft() {
|
||||
return ArrayUtils.toObject(lhs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Short[] getRight() {
|
||||
return ArrayUtils.toObject(rhs);
|
||||
}
|
||||
});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if two {@link Objects}s are equal.
|
||||
*
|
||||
|
@ -875,45 +842,78 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Append diffs from another {@link DiffResult}.
|
||||
*
|
||||
* <p>
|
||||
* This method is useful if you want to compare properties which are
|
||||
* themselves Diffable and would like to know which specific part of
|
||||
* it is different.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* public class Person implements Diffable<Person> {
|
||||
* String name;
|
||||
* Address address; // implements Diffable<Address>
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* public DiffResult diff(Person obj) {
|
||||
* return new DiffBuilder(this, obj, ToStringStyle.SHORT_PREFIX_STYLE)
|
||||
* .append("name", this.name, obj.name)
|
||||
* .append("address", this.address.diff(obj.address))
|
||||
* .build();
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* Test if two {@code short}s are equal.
|
||||
*
|
||||
* @param fieldName
|
||||
* the field name
|
||||
* @param diffResult
|
||||
* the {@link DiffResult} to append
|
||||
* @param lhs
|
||||
* the left-hand {@code short}
|
||||
* @param rhs
|
||||
* the right-hand {@code short}
|
||||
* @return this
|
||||
* @throws NullPointerException if field name is {@code null} or diffResult is {@code null}
|
||||
* @since 3.5
|
||||
* @throws NullPointerException
|
||||
* if field name is {@code null}
|
||||
*/
|
||||
public DiffBuilder<T> append(final String fieldName, final DiffResult<T> diffResult) {
|
||||
public DiffBuilder<T> append(final String fieldName, final short lhs,
|
||||
final short rhs) {
|
||||
validateFieldNameNotNull(fieldName);
|
||||
Objects.requireNonNull(diffResult, "diffResult");
|
||||
|
||||
if (objectsTriviallyEqual) {
|
||||
return this;
|
||||
}
|
||||
diffResult.getDiffs().forEach(diff -> append(fieldName + "." + diff.getFieldName(), diff.getLeft(), diff.getRight()));
|
||||
if (lhs != rhs) {
|
||||
diffs.add(new Diff<Short>(fieldName) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Short getLeft() {
|
||||
return Short.valueOf(lhs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Short getRight() {
|
||||
return Short.valueOf(rhs);
|
||||
}
|
||||
});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if two {@code short[]}s are equal.
|
||||
*
|
||||
* @param fieldName
|
||||
* the field name
|
||||
* @param lhs
|
||||
* the left-hand {@code short[]}
|
||||
* @param rhs
|
||||
* the right-hand {@code short[]}
|
||||
* @return this
|
||||
* @throws NullPointerException
|
||||
* if field name is {@code null}
|
||||
*/
|
||||
public DiffBuilder<T> append(final String fieldName, final short[] lhs,
|
||||
final short[] rhs) {
|
||||
validateFieldNameNotNull(fieldName);
|
||||
|
||||
if (objectsTriviallyEqual) {
|
||||
return this;
|
||||
}
|
||||
if (!Arrays.equals(lhs, rhs)) {
|
||||
diffs.add(new Diff<Short[]>(fieldName) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Short[] getLeft() {
|
||||
return ArrayUtils.toObject(lhs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Short[] getRight() {
|
||||
return ArrayUtils.toObject(rhs);
|
||||
}
|
||||
});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -83,6 +83,16 @@ public class DiffResult<T> implements Iterable<Diff<?>> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable list of {@link Diff}s. The list may be empty if
|
||||
* there were no differences between the objects.
|
||||
*
|
||||
* @return an unmodifiable list of {@link Diff}s
|
||||
*/
|
||||
public List<Diff<?>> getDiffs() {
|
||||
return Collections.unmodifiableList(diffList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object the right object has been compared to.
|
||||
*
|
||||
|
@ -93,6 +103,15 @@ public class DiffResult<T> implements Iterable<Diff<?>> {
|
|||
return this.lhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of differences between the two objects.
|
||||
*
|
||||
* @return the number of differences
|
||||
*/
|
||||
public int getNumberOfDiffs() {
|
||||
return diffList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object the left object has been compared to.
|
||||
*
|
||||
|
@ -103,25 +122,6 @@ public class DiffResult<T> implements Iterable<Diff<?>> {
|
|||
return this.rhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable list of {@link Diff}s. The list may be empty if
|
||||
* there were no differences between the objects.
|
||||
*
|
||||
* @return an unmodifiable list of {@link Diff}s
|
||||
*/
|
||||
public List<Diff<?>> getDiffs() {
|
||||
return Collections.unmodifiableList(diffList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of differences between the two objects.
|
||||
*
|
||||
* @return the number of differences
|
||||
*/
|
||||
public int getNumberOfDiffs() {
|
||||
return diffList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the style used by the {@link #toString()} method.
|
||||
*
|
||||
|
@ -131,6 +131,16 @@ public class DiffResult<T> implements Iterable<Diff<?>> {
|
|||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over the {@link Diff} objects contained in this list.
|
||||
*
|
||||
* @return the iterator
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Diff<?>> iterator() {
|
||||
return diffList.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link String} description of the differences contained within
|
||||
* this {@link DiffResult}. A {@link ToStringBuilder} is used for each object
|
||||
|
@ -189,14 +199,4 @@ public class DiffResult<T> implements Iterable<Diff<?>> {
|
|||
|
||||
return String.format("%s %s %s", lhsBuilder.build(), DIFFERS_STRING, rhsBuilder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over the {@link Diff} objects contained in this list.
|
||||
*
|
||||
* @return the iterator
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Diff<?>> iterator() {
|
||||
return diffList.iterator();
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -43,15 +43,6 @@ final class IDKey {
|
|||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns hash code - i.e. the system identity hash code.
|
||||
* @return the hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if instances are equal
|
||||
* @param other The other object to compare to
|
||||
|
@ -69,4 +60,13 @@ final class IDKey {
|
|||
// Note that identity equals is used.
|
||||
return value == idKey.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns hash code - i.e. the system identity hash code.
|
||||
* @return the hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,86 +82,8 @@ public class MultilineRecursiveToStringStyle extends RecursiveToStringStyle {
|
|||
resetIndent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the fields responsible for the line breaks and indenting.
|
||||
* Must be invoked after changing the {@link #spaces} value.
|
||||
*/
|
||||
private void resetIndent() {
|
||||
setArrayStart("{" + System.lineSeparator() + spacer(spaces));
|
||||
setArraySeparator("," + System.lineSeparator() + spacer(spaces));
|
||||
setArrayEnd(System.lineSeparator() + spacer(spaces - INDENT) + "}");
|
||||
|
||||
setContentStart("[" + System.lineSeparator() + spacer(spaces));
|
||||
setFieldSeparator("," + System.lineSeparator() + spacer(spaces));
|
||||
setContentEnd(System.lineSeparator() + spacer(spaces - INDENT) + "]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a StringBuilder responsible for the indenting.
|
||||
*
|
||||
* @param spaces how far to indent
|
||||
* @return a StringBuilder with {spaces} leading space characters.
|
||||
*/
|
||||
private StringBuilder spacer(final int spaces) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < spaces; i++) {
|
||||
sb.append(" ");
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) {
|
||||
if (!ClassUtils.isPrimitiveWrapper(value.getClass()) && !String.class.equals(value.getClass())
|
||||
&& accept(value.getClass())) {
|
||||
spaces += INDENT;
|
||||
resetIndent();
|
||||
buffer.append(ReflectionToStringBuilder.toString(value, this));
|
||||
spaces -= INDENT;
|
||||
resetIndent();
|
||||
} else {
|
||||
super.appendDetail(buffer, fieldName, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object[] array) {
|
||||
spaces += INDENT;
|
||||
resetIndent();
|
||||
super.appendDetail(buffer, fieldName, array);
|
||||
spaces -= INDENT;
|
||||
resetIndent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reflectionAppendArrayDetail(final StringBuffer buffer, final String fieldName, final Object array) {
|
||||
spaces += INDENT;
|
||||
resetIndent();
|
||||
super.reflectionAppendArrayDetail(buffer, fieldName, array);
|
||||
spaces -= INDENT;
|
||||
resetIndent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendDetail(final StringBuffer buffer, final String fieldName, final long[] array) {
|
||||
spaces += INDENT;
|
||||
resetIndent();
|
||||
super.appendDetail(buffer, fieldName, array);
|
||||
spaces -= INDENT;
|
||||
resetIndent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendDetail(final StringBuffer buffer, final String fieldName, final int[] array) {
|
||||
spaces += INDENT;
|
||||
resetIndent();
|
||||
super.appendDetail(buffer, fieldName, array);
|
||||
spaces -= INDENT;
|
||||
resetIndent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendDetail(final StringBuffer buffer, final String fieldName, final short[] array) {
|
||||
protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean[] array) {
|
||||
spaces += INDENT;
|
||||
resetIndent();
|
||||
super.appendDetail(buffer, fieldName, array);
|
||||
|
@ -206,7 +128,7 @@ public class MultilineRecursiveToStringStyle extends RecursiveToStringStyle {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean[] array) {
|
||||
protected void appendDetail(final StringBuffer buffer, final String fieldName, final int[] array) {
|
||||
spaces += INDENT;
|
||||
resetIndent();
|
||||
super.appendDetail(buffer, fieldName, array);
|
||||
|
@ -214,4 +136,82 @@ public class MultilineRecursiveToStringStyle extends RecursiveToStringStyle {
|
|||
resetIndent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendDetail(final StringBuffer buffer, final String fieldName, final long[] array) {
|
||||
spaces += INDENT;
|
||||
resetIndent();
|
||||
super.appendDetail(buffer, fieldName, array);
|
||||
spaces -= INDENT;
|
||||
resetIndent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) {
|
||||
if (!ClassUtils.isPrimitiveWrapper(value.getClass()) && !String.class.equals(value.getClass())
|
||||
&& accept(value.getClass())) {
|
||||
spaces += INDENT;
|
||||
resetIndent();
|
||||
buffer.append(ReflectionToStringBuilder.toString(value, this));
|
||||
spaces -= INDENT;
|
||||
resetIndent();
|
||||
} else {
|
||||
super.appendDetail(buffer, fieldName, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object[] array) {
|
||||
spaces += INDENT;
|
||||
resetIndent();
|
||||
super.appendDetail(buffer, fieldName, array);
|
||||
spaces -= INDENT;
|
||||
resetIndent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendDetail(final StringBuffer buffer, final String fieldName, final short[] array) {
|
||||
spaces += INDENT;
|
||||
resetIndent();
|
||||
super.appendDetail(buffer, fieldName, array);
|
||||
spaces -= INDENT;
|
||||
resetIndent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reflectionAppendArrayDetail(final StringBuffer buffer, final String fieldName, final Object array) {
|
||||
spaces += INDENT;
|
||||
resetIndent();
|
||||
super.reflectionAppendArrayDetail(buffer, fieldName, array);
|
||||
spaces -= INDENT;
|
||||
resetIndent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the fields responsible for the line breaks and indenting.
|
||||
* Must be invoked after changing the {@link #spaces} value.
|
||||
*/
|
||||
private void resetIndent() {
|
||||
setArrayStart("{" + System.lineSeparator() + spacer(spaces));
|
||||
setArraySeparator("," + System.lineSeparator() + spacer(spaces));
|
||||
setArrayEnd(System.lineSeparator() + spacer(spaces - INDENT) + "}");
|
||||
|
||||
setContentStart("[" + System.lineSeparator() + spacer(spaces));
|
||||
setFieldSeparator("," + System.lineSeparator() + spacer(spaces));
|
||||
setContentEnd(System.lineSeparator() + spacer(spaces - INDENT) + "]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a StringBuilder responsible for the indenting.
|
||||
*
|
||||
* @param spaces how far to indent
|
||||
* @return a StringBuilder with {spaces} leading space characters.
|
||||
*/
|
||||
private StringBuilder spacer(final int spaces) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < spaces; i++) {
|
||||
sb.append(" ");
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -65,24 +65,6 @@ public class RecursiveToStringStyle extends ToStringStyle {
|
|||
public RecursiveToStringStyle() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) {
|
||||
if (!ClassUtils.isPrimitiveWrapper(value.getClass()) &&
|
||||
!String.class.equals(value.getClass()) &&
|
||||
accept(value.getClass())) {
|
||||
buffer.append(ReflectionToStringBuilder.toString(value, this));
|
||||
} else {
|
||||
super.appendDetail(buffer, fieldName, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendDetail(final StringBuffer buffer, final String fieldName, final Collection<?> coll) {
|
||||
appendClassName(buffer, coll);
|
||||
appendIdentityHashCode(buffer, coll);
|
||||
appendDetail(buffer, fieldName, coll.toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not to recursively format the given {@link Class}.
|
||||
* By default, this method always returns {@code true}, but may be overwritten by
|
||||
|
@ -95,4 +77,22 @@ public class RecursiveToStringStyle extends ToStringStyle {
|
|||
protected boolean accept(final Class<?> clazz) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendDetail(final StringBuffer buffer, final String fieldName, final Collection<?> coll) {
|
||||
appendClassName(buffer, coll);
|
||||
appendIdentityHashCode(buffer, coll);
|
||||
appendDetail(buffer, fieldName, coll.toArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) {
|
||||
if (!ClassUtils.isPrimitiveWrapper(value.getClass()) &&
|
||||
!String.class.equals(value.getClass()) &&
|
||||
accept(value.getClass())) {
|
||||
buffer.append(ReflectionToStringBuilder.toString(value, this));
|
||||
} else {
|
||||
super.appendDetail(buffer, fieldName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,6 +108,49 @@ public class ReflectionDiffBuilder<T> implements Builder<DiffResult<T>> {
|
|||
this.diffBuilder = new DiffBuilder<>(lhs, rhs, style);
|
||||
}
|
||||
|
||||
private boolean accept(final Field field) {
|
||||
if (field.getName().indexOf(ClassUtils.INNER_CLASS_SEPARATOR_CHAR) != -1) {
|
||||
return false;
|
||||
}
|
||||
if (Modifier.isTransient(field.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
if (this.excludeFieldNames != null
|
||||
&& Arrays.binarySearch(this.excludeFieldNames, field.getName()) >= 0) {
|
||||
// Reject fields from the getExcludeFieldNames list.
|
||||
return false;
|
||||
}
|
||||
return !field.isAnnotationPresent(DiffExclude.class);
|
||||
}
|
||||
|
||||
|
||||
private void appendFields(final Class<?> clazz) {
|
||||
for (final Field field : FieldUtils.getAllFields(clazz)) {
|
||||
if (accept(field)) {
|
||||
try {
|
||||
diffBuilder.append(field.getName(), FieldUtils.readField(field, left, true), FieldUtils.readField(field, right, true));
|
||||
} catch (final IllegalAccessException e) {
|
||||
// this can't happen. Would get a Security exception instead
|
||||
// throw a runtime exception in case the impossible happens.
|
||||
throw new IllegalArgumentException("Unexpected IllegalAccessException: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiffResult<T> build() {
|
||||
if (left.equals(right)) {
|
||||
return diffBuilder.build();
|
||||
}
|
||||
|
||||
appendFields(left.getClass());
|
||||
return diffBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the field names that should be excluded from the diff.
|
||||
*
|
||||
|
@ -118,7 +161,6 @@ public class ReflectionDiffBuilder<T> implements Builder<DiffResult<T>> {
|
|||
return this.excludeFieldNames.clone();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the field names to exclude.
|
||||
*
|
||||
|
@ -137,46 +179,4 @@ public class ReflectionDiffBuilder<T> implements Builder<DiffResult<T>> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiffResult<T> build() {
|
||||
if (left.equals(right)) {
|
||||
return diffBuilder.build();
|
||||
}
|
||||
|
||||
appendFields(left.getClass());
|
||||
return diffBuilder.build();
|
||||
}
|
||||
|
||||
private void appendFields(final Class<?> clazz) {
|
||||
for (final Field field : FieldUtils.getAllFields(clazz)) {
|
||||
if (accept(field)) {
|
||||
try {
|
||||
diffBuilder.append(field.getName(), FieldUtils.readField(field, left, true), FieldUtils.readField(field, right, true));
|
||||
} catch (final IllegalAccessException e) {
|
||||
// this can't happen. Would get a Security exception instead
|
||||
// throw a runtime exception in case the impossible happens.
|
||||
throw new IllegalArgumentException("Unexpected IllegalAccessException: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean accept(final Field field) {
|
||||
if (field.getName().indexOf(ClassUtils.INNER_CLASS_SEPARATOR_CHAR) != -1) {
|
||||
return false;
|
||||
}
|
||||
if (Modifier.isTransient(field.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
if (this.excludeFieldNames != null
|
||||
&& Arrays.binarySearch(this.excludeFieldNames, field.getName()) >= 0) {
|
||||
// Reject fields from the getExcludeFieldNames list.
|
||||
return false;
|
||||
}
|
||||
return !field.isAnnotationPresent(DiffExclude.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,152 +46,6 @@ public class StandardToStringStyle extends ToStringStyle {
|
|||
public StandardToStringStyle() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to use the class name.
|
||||
*
|
||||
* @return the current useClassName flag
|
||||
*/
|
||||
@Override
|
||||
public boolean isUseClassName() {
|
||||
return super.isUseClassName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to use the class name.
|
||||
*
|
||||
* @param useClassName the new useClassName flag
|
||||
*/
|
||||
@Override
|
||||
public void setUseClassName(final boolean useClassName) {
|
||||
super.setUseClassName(useClassName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to output short or long class names.
|
||||
*
|
||||
* @return the current useShortClassName flag
|
||||
* @since 2.0
|
||||
*/
|
||||
@Override
|
||||
public boolean isUseShortClassName() {
|
||||
return super.isUseShortClassName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to output short or long class names.
|
||||
*
|
||||
* @param useShortClassName the new useShortClassName flag
|
||||
* @since 2.0
|
||||
*/
|
||||
@Override
|
||||
public void setUseShortClassName(final boolean useShortClassName) {
|
||||
super.setUseShortClassName(useShortClassName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to use the identity hash code.
|
||||
* @return the current useIdentityHashCode flag
|
||||
*/
|
||||
@Override
|
||||
public boolean isUseIdentityHashCode() {
|
||||
return super.isUseIdentityHashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to use the identity hash code.
|
||||
*
|
||||
* @param useIdentityHashCode the new useIdentityHashCode flag
|
||||
*/
|
||||
@Override
|
||||
public void setUseIdentityHashCode(final boolean useIdentityHashCode) {
|
||||
super.setUseIdentityHashCode(useIdentityHashCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to use the field names passed in.
|
||||
*
|
||||
* @return the current useFieldNames flag
|
||||
*/
|
||||
@Override
|
||||
public boolean isUseFieldNames() {
|
||||
return super.isUseFieldNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to use the field names passed in.
|
||||
*
|
||||
* @param useFieldNames the new useFieldNames flag
|
||||
*/
|
||||
@Override
|
||||
public void setUseFieldNames(final boolean useFieldNames) {
|
||||
super.setUseFieldNames(useFieldNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to use full detail when the caller doesn't
|
||||
* specify.
|
||||
*
|
||||
* @return the current defaultFullDetail flag
|
||||
*/
|
||||
@Override
|
||||
public boolean isDefaultFullDetail() {
|
||||
return super.isDefaultFullDetail();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to use full detail when the caller doesn't
|
||||
* specify.
|
||||
*
|
||||
* @param defaultFullDetail the new defaultFullDetail flag
|
||||
*/
|
||||
@Override
|
||||
public void setDefaultFullDetail(final boolean defaultFullDetail) {
|
||||
super.setDefaultFullDetail(defaultFullDetail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to output array content detail.
|
||||
*
|
||||
* @return the current array content detail setting
|
||||
*/
|
||||
@Override
|
||||
public boolean isArrayContentDetail() {
|
||||
return super.isArrayContentDetail();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to output array content detail.
|
||||
*
|
||||
* @param arrayContentDetail the new arrayContentDetail flag
|
||||
*/
|
||||
@Override
|
||||
public void setArrayContentDetail(final boolean arrayContentDetail) {
|
||||
super.setArrayContentDetail(arrayContentDetail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array start text.
|
||||
*
|
||||
* @return the current array start text
|
||||
*/
|
||||
@Override
|
||||
public String getArrayStart() {
|
||||
return super.getArrayStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the array start text.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
*
|
||||
* @param arrayStart the new array start text
|
||||
*/
|
||||
@Override
|
||||
public void setArrayStart(final String arrayStart) {
|
||||
super.setArrayStart(arrayStart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array end text.
|
||||
*
|
||||
|
@ -202,19 +56,6 @@ public class StandardToStringStyle extends ToStringStyle {
|
|||
return super.getArrayEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the array end text.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
*
|
||||
* @param arrayEnd the new array end text
|
||||
*/
|
||||
@Override
|
||||
public void setArrayEnd(final String arrayEnd) {
|
||||
super.setArrayEnd(arrayEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array separator text.
|
||||
*
|
||||
|
@ -226,39 +67,13 @@ public class StandardToStringStyle extends ToStringStyle {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the array separator text.
|
||||
* Gets the array start text.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
*
|
||||
* @param arraySeparator the new array separator text
|
||||
* @return the current array start text
|
||||
*/
|
||||
@Override
|
||||
public void setArraySeparator(final String arraySeparator) {
|
||||
super.setArraySeparator(arraySeparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the content start text.
|
||||
*
|
||||
* @return the current content start text
|
||||
*/
|
||||
@Override
|
||||
public String getContentStart() {
|
||||
return super.getContentStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content start text.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
*
|
||||
* @param contentStart the new content start text
|
||||
*/
|
||||
@Override
|
||||
public void setContentStart(final String contentStart) {
|
||||
super.setContentStart(contentStart);
|
||||
public String getArrayStart() {
|
||||
return super.getArrayStart();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -272,16 +87,13 @@ public class StandardToStringStyle extends ToStringStyle {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the content end text.
|
||||
* Gets the content start text.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
*
|
||||
* @param contentEnd the new content end text
|
||||
* @return the current content start text
|
||||
*/
|
||||
@Override
|
||||
public void setContentEnd(final String contentEnd) {
|
||||
super.setContentEnd(contentEnd);
|
||||
public String getContentStart() {
|
||||
return super.getContentStart();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -294,19 +106,6 @@ public class StandardToStringStyle extends ToStringStyle {
|
|||
return super.getFieldNameValueSeparator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the field name value separator text.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
*
|
||||
* @param fieldNameValueSeparator the new field name value separator text
|
||||
*/
|
||||
@Override
|
||||
public void setFieldNameValueSeparator(final String fieldNameValueSeparator) {
|
||||
super.setFieldNameValueSeparator(fieldNameValueSeparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the field separator text.
|
||||
*
|
||||
|
@ -317,67 +116,6 @@ public class StandardToStringStyle extends ToStringStyle {
|
|||
return super.getFieldSeparator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the field separator text.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
*
|
||||
* @param fieldSeparator the new field separator text
|
||||
*/
|
||||
@Override
|
||||
public void setFieldSeparator(final 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
|
||||
*/
|
||||
@Override
|
||||
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
|
||||
*/
|
||||
@Override
|
||||
public void setFieldSeparatorAtStart(final 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
|
||||
*/
|
||||
@Override
|
||||
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
|
||||
*/
|
||||
@Override
|
||||
public void setFieldSeparatorAtEnd(final boolean fieldSeparatorAtEnd) {
|
||||
super.setFieldSeparatorAtEnd(fieldSeparatorAtEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text to output when {@code null} found.
|
||||
*
|
||||
|
@ -389,16 +127,16 @@ public class StandardToStringStyle extends ToStringStyle {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the text to output when {@code null} found.
|
||||
* Gets the end text to output when a {@link Collection},
|
||||
* {@link Map} or {@link Array} size is output.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
* <p>This is output after the size value.</p>
|
||||
*
|
||||
* @param nullText the new text to output when {@code null} found
|
||||
* @return the current end of size text
|
||||
*/
|
||||
@Override
|
||||
public void setNullText(final String nullText) {
|
||||
super.setNullText(nullText);
|
||||
public String getSizeEndText() {
|
||||
return super.getSizeEndText();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -415,32 +153,263 @@ public class StandardToStringStyle extends ToStringStyle {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the start text to output when a {@link Collection},
|
||||
* {@link Map} or {@link Array} size is output.
|
||||
*
|
||||
* <p>This is output before the size value.</p>
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted to
|
||||
* an empty String.</p>
|
||||
*
|
||||
* @param sizeStartText the new start of size text
|
||||
*/
|
||||
@Override
|
||||
public void setSizeStartText(final String sizeStartText) {
|
||||
super.setSizeStartText(sizeStartText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the end text to output when a {@link Collection},
|
||||
* {@link Map} or {@link Array} size is output.
|
||||
* Gets the end text to output when an {@link Object} is
|
||||
* output in summary mode.
|
||||
*
|
||||
* <p>This is output after the size value.</p>
|
||||
*
|
||||
* @return the current end of size text
|
||||
* @return the current end of summary text
|
||||
*/
|
||||
@Override
|
||||
public String getSizeEndText() {
|
||||
return super.getSizeEndText();
|
||||
public String getSummaryObjectEndText() {
|
||||
return super.getSummaryObjectEndText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the start text to output when an {@link Object} is
|
||||
* output in summary mode.
|
||||
*
|
||||
* <p>This is output before the size value.</p>
|
||||
*
|
||||
* @return the current start of summary text
|
||||
*/
|
||||
@Override
|
||||
public String getSummaryObjectStartText() {
|
||||
return super.getSummaryObjectStartText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to output array content detail.
|
||||
*
|
||||
* @return the current array content detail setting
|
||||
*/
|
||||
@Override
|
||||
public boolean isArrayContentDetail() {
|
||||
return super.isArrayContentDetail();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to use full detail when the caller doesn't
|
||||
* specify.
|
||||
*
|
||||
* @return the current defaultFullDetail flag
|
||||
*/
|
||||
@Override
|
||||
public boolean isDefaultFullDetail() {
|
||||
return super.isDefaultFullDetail();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the field separator should be added at the end
|
||||
* of each buffer.
|
||||
*
|
||||
* @return fieldSeparatorAtEnd flag
|
||||
* @since 2.0
|
||||
*/
|
||||
@Override
|
||||
public boolean isFieldSeparatorAtEnd() {
|
||||
return super.isFieldSeparatorAtEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the field separator should be added at the start
|
||||
* of each buffer.
|
||||
*
|
||||
* @return the fieldSeparatorAtStart flag
|
||||
* @since 2.0
|
||||
*/
|
||||
@Override
|
||||
public boolean isFieldSeparatorAtStart() {
|
||||
return super.isFieldSeparatorAtStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to use the class name.
|
||||
*
|
||||
* @return the current useClassName flag
|
||||
*/
|
||||
@Override
|
||||
public boolean isUseClassName() {
|
||||
return super.isUseClassName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to use the field names passed in.
|
||||
*
|
||||
* @return the current useFieldNames flag
|
||||
*/
|
||||
@Override
|
||||
public boolean isUseFieldNames() {
|
||||
return super.isUseFieldNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to use the identity hash code.
|
||||
* @return the current useIdentityHashCode flag
|
||||
*/
|
||||
@Override
|
||||
public boolean isUseIdentityHashCode() {
|
||||
return super.isUseIdentityHashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to output short or long class names.
|
||||
*
|
||||
* @return the current useShortClassName flag
|
||||
* @since 2.0
|
||||
*/
|
||||
@Override
|
||||
public boolean isUseShortClassName() {
|
||||
return super.isUseShortClassName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to output array content detail.
|
||||
*
|
||||
* @param arrayContentDetail the new arrayContentDetail flag
|
||||
*/
|
||||
@Override
|
||||
public void setArrayContentDetail(final boolean arrayContentDetail) {
|
||||
super.setArrayContentDetail(arrayContentDetail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the array end text.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
*
|
||||
* @param arrayEnd the new array end text
|
||||
*/
|
||||
@Override
|
||||
public void setArrayEnd(final String arrayEnd) {
|
||||
super.setArrayEnd(arrayEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the array separator text.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
*
|
||||
* @param arraySeparator the new array separator text
|
||||
*/
|
||||
@Override
|
||||
public void setArraySeparator(final String arraySeparator) {
|
||||
super.setArraySeparator(arraySeparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the array start text.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
*
|
||||
* @param arrayStart the new array start text
|
||||
*/
|
||||
@Override
|
||||
public void setArrayStart(final String arrayStart) {
|
||||
super.setArrayStart(arrayStart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content end text.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
*
|
||||
* @param contentEnd the new content end text
|
||||
*/
|
||||
@Override
|
||||
public void setContentEnd(final String contentEnd) {
|
||||
super.setContentEnd(contentEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content start text.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
*
|
||||
* @param contentStart the new content start text
|
||||
*/
|
||||
@Override
|
||||
public void setContentStart(final String contentStart) {
|
||||
super.setContentStart(contentStart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to use full detail when the caller doesn't
|
||||
* specify.
|
||||
*
|
||||
* @param defaultFullDetail the new defaultFullDetail flag
|
||||
*/
|
||||
@Override
|
||||
public void setDefaultFullDetail(final boolean defaultFullDetail) {
|
||||
super.setDefaultFullDetail(defaultFullDetail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the field name value separator text.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
*
|
||||
* @param fieldNameValueSeparator the new field name value separator text
|
||||
*/
|
||||
@Override
|
||||
public void setFieldNameValueSeparator(final String fieldNameValueSeparator) {
|
||||
super.setFieldNameValueSeparator(fieldNameValueSeparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the field separator text.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
*
|
||||
* @param fieldSeparator the new field separator text
|
||||
*/
|
||||
@Override
|
||||
public void setFieldSeparator(final String fieldSeparator) {
|
||||
super.setFieldSeparator(fieldSeparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the field separator should be added at the end
|
||||
* of each buffer.
|
||||
*
|
||||
* @param fieldSeparatorAtEnd the fieldSeparatorAtEnd flag
|
||||
* @since 2.0
|
||||
*/
|
||||
@Override
|
||||
public void setFieldSeparatorAtEnd(final boolean fieldSeparatorAtEnd) {
|
||||
super.setFieldSeparatorAtEnd(fieldSeparatorAtEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the field separator should be added at the start
|
||||
* of each buffer.
|
||||
*
|
||||
* @param fieldSeparatorAtStart the fieldSeparatorAtStart flag
|
||||
* @since 2.0
|
||||
*/
|
||||
@Override
|
||||
public void setFieldSeparatorAtStart(final boolean fieldSeparatorAtStart) {
|
||||
super.setFieldSeparatorAtStart(fieldSeparatorAtStart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text to output when {@code null} found.
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted
|
||||
* to an empty String.</p>
|
||||
*
|
||||
* @param nullText the new text to output when {@code null} found
|
||||
*/
|
||||
@Override
|
||||
public void setNullText(final String nullText) {
|
||||
super.setNullText(nullText);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -460,16 +429,35 @@ public class StandardToStringStyle extends ToStringStyle {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the start text to output when an {@link Object} is
|
||||
* output in summary mode.
|
||||
* Sets the start text to output when a {@link Collection},
|
||||
* {@link Map} or {@link Array} size is output.
|
||||
*
|
||||
* <p>This is output before the size value.</p>
|
||||
*
|
||||
* @return the current start of summary text
|
||||
* <p>{@code null} is accepted, but will be converted to
|
||||
* an empty String.</p>
|
||||
*
|
||||
* @param sizeStartText the new start of size text
|
||||
*/
|
||||
@Override
|
||||
public String getSummaryObjectStartText() {
|
||||
return super.getSummaryObjectStartText();
|
||||
public void setSizeStartText(final String sizeStartText) {
|
||||
super.setSizeStartText(sizeStartText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end text to output when an {@link Object} is
|
||||
* output in summary mode.
|
||||
*
|
||||
* <p>This is output after the size value.</p>
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted to
|
||||
* an empty String.</p>
|
||||
*
|
||||
* @param summaryObjectEndText the new end of summary text
|
||||
*/
|
||||
@Override
|
||||
public void setSummaryObjectEndText(final String summaryObjectEndText) {
|
||||
super.setSummaryObjectEndText(summaryObjectEndText);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -489,32 +477,44 @@ public class StandardToStringStyle extends ToStringStyle {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the end text to output when an {@link Object} is
|
||||
* output in summary mode.
|
||||
* Sets whether to use the class name.
|
||||
*
|
||||
* <p>This is output after the size value.</p>
|
||||
*
|
||||
* @return the current end of summary text
|
||||
* @param useClassName the new useClassName flag
|
||||
*/
|
||||
@Override
|
||||
public String getSummaryObjectEndText() {
|
||||
return super.getSummaryObjectEndText();
|
||||
public void setUseClassName(final boolean useClassName) {
|
||||
super.setUseClassName(useClassName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end text to output when an {@link Object} is
|
||||
* output in summary mode.
|
||||
* Sets whether to use the field names passed in.
|
||||
*
|
||||
* <p>This is output after the size value.</p>
|
||||
*
|
||||
* <p>{@code null} is accepted, but will be converted to
|
||||
* an empty String.</p>
|
||||
*
|
||||
* @param summaryObjectEndText the new end of summary text
|
||||
* @param useFieldNames the new useFieldNames flag
|
||||
*/
|
||||
@Override
|
||||
public void setSummaryObjectEndText(final String summaryObjectEndText) {
|
||||
super.setSummaryObjectEndText(summaryObjectEndText);
|
||||
public void setUseFieldNames(final boolean useFieldNames) {
|
||||
super.setUseFieldNames(useFieldNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to use the identity hash code.
|
||||
*
|
||||
* @param useIdentityHashCode the new useIdentityHashCode flag
|
||||
*/
|
||||
@Override
|
||||
public void setUseIdentityHashCode(final boolean useIdentityHashCode) {
|
||||
super.setUseIdentityHashCode(useIdentityHashCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to output short or long class names.
|
||||
*
|
||||
* @param useShortClassName the new useShortClassName flag
|
||||
* @since 2.0
|
||||
*/
|
||||
@Override
|
||||
public void setUseShortClassName(final boolean useShortClassName) {
|
||||
super.setUseShortClassName(useShortClassName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -116,25 +116,6 @@ public class ToStringBuilder implements Builder<String> {
|
|||
return defaultStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default {@link ToStringStyle} to use.
|
||||
*
|
||||
* <p>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 {@link ToStringStyle} to the constructor instead
|
||||
* of changing this global default.</p>
|
||||
*
|
||||
* <p>This method is not intended for use from multiple threads.
|
||||
* Internally, a {@code volatile} variable is used to provide the guarantee
|
||||
* that the latest value set is the value returned from {@link #getDefaultStyle}.</p>
|
||||
*
|
||||
* @param style the default {@link ToStringStyle}
|
||||
* @throws NullPointerException if the style is {@code null}
|
||||
*/
|
||||
public static void setDefaultStyle(final ToStringStyle style) {
|
||||
defaultStyle = Objects.requireNonNull(style, "style");
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses {@link ReflectionToStringBuilder} to generate a
|
||||
* {@code toString} for the specified object.
|
||||
|
@ -195,6 +176,25 @@ public class ToStringBuilder implements Builder<String> {
|
|||
return ReflectionToStringBuilder.toString(object, style, outputTransients, false, reflectUpToClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default {@link ToStringStyle} to use.
|
||||
*
|
||||
* <p>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 {@link ToStringStyle} to the constructor instead
|
||||
* of changing this global default.</p>
|
||||
*
|
||||
* <p>This method is not intended for use from multiple threads.
|
||||
* Internally, a {@code volatile} variable is used to provide the guarantee
|
||||
* that the latest value set is the value returned from {@link #getDefaultStyle}.</p>
|
||||
*
|
||||
* @param style the default {@link ToStringStyle}
|
||||
* @throws NullPointerException if the style is {@code null}
|
||||
*/
|
||||
public static void setDefaultStyle(final ToStringStyle style) {
|
||||
defaultStyle = Objects.requireNonNull(style, "style");
|
||||
}
|
||||
|
||||
/**
|
||||
* Current toString buffer, not null.
|
||||
*/
|
||||
|
@ -968,6 +968,21 @@ public class ToStringBuilder implements Builder<String> {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the String that was build as an object representation. The
|
||||
* default implementation utilizes the {@link #toString()} implementation.
|
||||
*
|
||||
* @return the String {@code toString}
|
||||
*
|
||||
* @see #toString()
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
@Override
|
||||
public String build() {
|
||||
return toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Object} being output.
|
||||
*
|
||||
|
@ -1016,19 +1031,4 @@ public class ToStringBuilder implements Builder<String> {
|
|||
}
|
||||
return this.getStringBuffer().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the String that was build as an object representation. The
|
||||
* default implementation utilizes the {@link #toString()} implementation.
|
||||
*
|
||||
* @return the String {@code toString}
|
||||
*
|
||||
* @see #toString()
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
@Override
|
||||
public String build() {
|
||||
return toString();
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -28,111 +28,6 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||
*/
|
||||
public abstract class AbstractCircuitBreaker<T> implements CircuitBreaker<T> {
|
||||
|
||||
/**
|
||||
* The name of the <em>open</em> property as it is passed to registered
|
||||
* change listeners.
|
||||
*/
|
||||
public static final String PROPERTY_NAME = "open";
|
||||
|
||||
/** The current state of this circuit breaker. */
|
||||
protected final AtomicReference<State> state = new AtomicReference<>(State.CLOSED);
|
||||
|
||||
/** An object for managing change listeners registered at this instance. */
|
||||
private final PropertyChangeSupport changeSupport;
|
||||
|
||||
/**
|
||||
* Creates an {@link AbstractCircuitBreaker}. It also creates an internal {@link PropertyChangeSupport}.
|
||||
*/
|
||||
public AbstractCircuitBreaker() {
|
||||
changeSupport = new PropertyChangeSupport(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return isOpen(state.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return !isOpen();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public abstract boolean checkState();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public abstract boolean incrementAndCheckState(T increment);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
changeState(State.CLOSED);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void open() {
|
||||
changeState(State.OPEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given state value to a boolean <em>open</em> property.
|
||||
*
|
||||
* @param state the state to be converted
|
||||
* @return the boolean open flag
|
||||
*/
|
||||
protected static boolean isOpen(final State state) {
|
||||
return state == State.OPEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the internal state of this circuit breaker. If there is actually a change
|
||||
* of the state value, all registered change listeners are notified.
|
||||
*
|
||||
* @param newState the new state to be set
|
||||
*/
|
||||
protected void changeState(final State newState) {
|
||||
if (state.compareAndSet(newState.oppositeState(), newState)) {
|
||||
changeSupport.firePropertyChange(PROPERTY_NAME, !isOpen(newState), isOpen(newState));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a change listener to this circuit breaker. This listener is notified whenever
|
||||
* the state of this circuit breaker changes. If the listener is
|
||||
* <strong>null</strong>, it is silently ignored.
|
||||
*
|
||||
* @param listener the listener to be added
|
||||
*/
|
||||
public void addChangeListener(final PropertyChangeListener listener) {
|
||||
changeSupport.addPropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified change listener from this circuit breaker.
|
||||
*
|
||||
* @param listener the listener to be removed
|
||||
*/
|
||||
public void removeChangeListener(final PropertyChangeListener listener) {
|
||||
changeSupport.removePropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal enumeration representing the different states of a circuit
|
||||
* breaker. This class also contains some logic for performing state
|
||||
|
@ -172,4 +67,109 @@ public abstract class AbstractCircuitBreaker<T> implements CircuitBreaker<T> {
|
|||
public abstract State oppositeState();
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the <em>open</em> property as it is passed to registered
|
||||
* change listeners.
|
||||
*/
|
||||
public static final String PROPERTY_NAME = "open";
|
||||
|
||||
/**
|
||||
* Converts the given state value to a boolean <em>open</em> property.
|
||||
*
|
||||
* @param state the state to be converted
|
||||
* @return the boolean open flag
|
||||
*/
|
||||
protected static boolean isOpen(final State state) {
|
||||
return state == State.OPEN;
|
||||
}
|
||||
|
||||
/** The current state of this circuit breaker. */
|
||||
protected final AtomicReference<State> state = new AtomicReference<>(State.CLOSED);
|
||||
|
||||
/** An object for managing change listeners registered at this instance. */
|
||||
private final PropertyChangeSupport changeSupport;
|
||||
|
||||
/**
|
||||
* Creates an {@link AbstractCircuitBreaker}. It also creates an internal {@link PropertyChangeSupport}.
|
||||
*/
|
||||
public AbstractCircuitBreaker() {
|
||||
changeSupport = new PropertyChangeSupport(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a change listener to this circuit breaker. This listener is notified whenever
|
||||
* the state of this circuit breaker changes. If the listener is
|
||||
* <strong>null</strong>, it is silently ignored.
|
||||
*
|
||||
* @param listener the listener to be added
|
||||
*/
|
||||
public void addChangeListener(final PropertyChangeListener listener) {
|
||||
changeSupport.addPropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the internal state of this circuit breaker. If there is actually a change
|
||||
* of the state value, all registered change listeners are notified.
|
||||
*
|
||||
* @param newState the new state to be set
|
||||
*/
|
||||
protected void changeState(final State newState) {
|
||||
if (state.compareAndSet(newState.oppositeState(), newState)) {
|
||||
changeSupport.firePropertyChange(PROPERTY_NAME, !isOpen(newState), isOpen(newState));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public abstract boolean checkState();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
changeState(State.CLOSED);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public abstract boolean incrementAndCheckState(T increment);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return !isOpen();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return isOpen(state.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void open() {
|
||||
changeState(State.OPEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified change listener from this circuit breaker.
|
||||
*
|
||||
* @param listener the listener to be removed
|
||||
*/
|
||||
public void removeChangeListener(final PropertyChangeListener listener) {
|
||||
changeSupport.removePropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -147,6 +147,14 @@ public abstract class AbstractConcurrentInitializer<T, E extends Exception> impl
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an Exception with a type of E as defined by a concrete subclass of this class.
|
||||
*
|
||||
* @param e The actual exception that was thrown
|
||||
* @return a new exception with the actual type of E, that wraps e.
|
||||
*/
|
||||
protected abstract E getTypedException(Exception e);
|
||||
|
||||
/**
|
||||
* Creates and initializes the object managed by this {@code
|
||||
* ConcurrentInitializer}. This method is called by {@link #get()} when the object is accessed for the first time. An implementation can focus on the
|
||||
|
@ -187,12 +195,4 @@ public abstract class AbstractConcurrentInitializer<T, E extends Exception> impl
|
|||
*/
|
||||
protected abstract boolean isInitialized();
|
||||
|
||||
/**
|
||||
* Gets an Exception with a type of E as defined by a concrete subclass of this class.
|
||||
*
|
||||
* @param e The actual exception that was thrown
|
||||
* @return a new exception with the actual type of E, that wraps e.
|
||||
*/
|
||||
protected abstract E getTypedException(Exception e);
|
||||
|
||||
}
|
||||
|
|
|
@ -86,9 +86,6 @@ public class AtomicInitializer<T> extends AbstractConcurrentInitializer<T, Concu
|
|||
|
||||
private static final Object NO_INIT = new Object();
|
||||
|
||||
/** Holds the reference to the managed object. */
|
||||
private final AtomicReference<T> reference = new AtomicReference<>(getNoInit());
|
||||
|
||||
/**
|
||||
* Creates a new builder.
|
||||
*
|
||||
|
@ -100,6 +97,9 @@ public class AtomicInitializer<T> extends AbstractConcurrentInitializer<T, Concu
|
|||
return new Builder<>();
|
||||
}
|
||||
|
||||
/** Holds the reference to the managed object. */
|
||||
private final AtomicReference<T> reference = new AtomicReference<>(getNoInit());
|
||||
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
*/
|
||||
|
@ -147,6 +147,14 @@ public class AtomicInitializer<T> extends AbstractConcurrentInitializer<T, Concu
|
|||
return (T) NO_INIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected ConcurrentException getTypedException(Exception e) {
|
||||
return new ConcurrentException(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether this instance is initialized. Once initialized, always returns true.
|
||||
*
|
||||
|
@ -157,12 +165,4 @@ public class AtomicInitializer<T> extends AbstractConcurrentInitializer<T, Concu
|
|||
public boolean isInitialized() {
|
||||
return reference.get() != NO_INIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected ConcurrentException getTypedException(Exception e) {
|
||||
return new ConcurrentException(e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,12 +75,6 @@ public class AtomicSafeInitializer<T> extends AbstractConcurrentInitializer<T, C
|
|||
|
||||
private static final Object NO_INIT = new Object();
|
||||
|
||||
/** A guard which ensures that initialize() is called only once. */
|
||||
private final AtomicReference<AtomicSafeInitializer<T>> factory = new AtomicReference<>();
|
||||
|
||||
/** Holds the reference to the managed object. */
|
||||
private final AtomicReference<T> reference = new AtomicReference<>(getNoInit());
|
||||
|
||||
/**
|
||||
* Creates a new builder.
|
||||
*
|
||||
|
@ -92,6 +86,12 @@ public class AtomicSafeInitializer<T> extends AbstractConcurrentInitializer<T, C
|
|||
return new Builder<>();
|
||||
}
|
||||
|
||||
/** A guard which ensures that initialize() is called only once. */
|
||||
private final AtomicReference<AtomicSafeInitializer<T>> factory = new AtomicReference<>();
|
||||
|
||||
/** Holds the reference to the managed object. */
|
||||
private final AtomicReference<T> reference = new AtomicReference<>(getNoInit());
|
||||
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
*/
|
||||
|
@ -135,6 +135,14 @@ public class AtomicSafeInitializer<T> extends AbstractConcurrentInitializer<T, C
|
|||
return (T) NO_INIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected ConcurrentException getTypedException(Exception e) {
|
||||
return new ConcurrentException(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether this instance is initialized. Once initialized, always returns true.
|
||||
*
|
||||
|
@ -145,12 +153,4 @@ public class AtomicSafeInitializer<T> extends AbstractConcurrentInitializer<T, C
|
|||
public boolean isInitialized() {
|
||||
return reference.get() != NO_INIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected ConcurrentException getTypedException(Exception e) {
|
||||
return new ConcurrentException(e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,6 +101,12 @@ public class BackgroundInitializer<T> extends AbstractConcurrentInitializer<T, E
|
|||
*/
|
||||
private ExecutorService externalExecutor;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public I get() {
|
||||
return (I) new BackgroundInitializer(getInitializer(), getCloser(), externalExecutor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the external executor service for executing tasks. null is an permitted value.
|
||||
*
|
||||
|
@ -114,12 +120,49 @@ public class BackgroundInitializer<T> extends AbstractConcurrentInitializer<T, E
|
|||
return asThis();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public I get() {
|
||||
return (I) new BackgroundInitializer(getInitializer(), getCloser(), externalExecutor);
|
||||
}
|
||||
|
||||
private class InitializationTask implements Callable<T> {
|
||||
/** Stores the executor service to be destroyed at the end. */
|
||||
private final ExecutorService execFinally;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link InitializationTask} and initializes
|
||||
* it with the {@link ExecutorService} to be destroyed at the end.
|
||||
*
|
||||
* @param exec the {@link ExecutorService}
|
||||
*/
|
||||
InitializationTask(final ExecutorService exec) {
|
||||
execFinally = exec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates initialization and returns the result.
|
||||
*
|
||||
* @return the result object
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
@Override
|
||||
public T call() throws Exception {
|
||||
try {
|
||||
return initialize();
|
||||
} finally {
|
||||
if (execFinally != null) {
|
||||
execFinally.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder.
|
||||
*
|
||||
* @param <T> the type of object to build.
|
||||
* @return a new builder.
|
||||
* @since 3.14.0
|
||||
*/
|
||||
public static <T> Builder<BackgroundInitializer<T>, T> builder() {
|
||||
return new Builder<>();
|
||||
}
|
||||
|
||||
/** The external executor service for executing tasks. */
|
||||
|
@ -153,17 +196,6 @@ public class BackgroundInitializer<T> extends AbstractConcurrentInitializer<T, E
|
|||
setExternalExecutor(exec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder.
|
||||
*
|
||||
* @param <T> the type of object to build.
|
||||
* @return a new builder.
|
||||
* @since 3.14.0
|
||||
*/
|
||||
public static <T> Builder<BackgroundInitializer<T>, T> builder() {
|
||||
return new Builder<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
*
|
||||
|
@ -176,6 +208,72 @@ public class BackgroundInitializer<T> extends AbstractConcurrentInitializer<T, E
|
|||
setExternalExecutor(exec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link ExecutorService} to be used. This method is called if
|
||||
* no {@link ExecutorService} was provided at construction time.
|
||||
*
|
||||
* @return the {@link ExecutorService} to be used
|
||||
*/
|
||||
private ExecutorService createExecutor() {
|
||||
return Executors.newFixedThreadPool(getTaskCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a task for the background initialization. The {@link Callable}
|
||||
* object returned by this method is passed to the {@link ExecutorService}.
|
||||
* This implementation returns a task that invokes the {@link #initialize()}
|
||||
* method. If a temporary {@link ExecutorService} is used, it is destroyed
|
||||
* at the end of the task.
|
||||
*
|
||||
* @param execDestroy the {@link ExecutorService} to be destroyed by the
|
||||
* task
|
||||
* @return a task for the background initialization
|
||||
*/
|
||||
private Callable<T> createTask(final ExecutorService execDestroy) {
|
||||
return new InitializationTask(execDestroy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result of the background initialization. This method blocks
|
||||
* until initialization is complete. If the background processing caused a
|
||||
* runtime exception, it is directly thrown by this method. Checked
|
||||
* exceptions, including {@link InterruptedException} are wrapped in a
|
||||
* {@link ConcurrentException}. Calling this method before {@link #start()}
|
||||
* was called causes an {@link IllegalStateException} exception to be
|
||||
* thrown.
|
||||
*
|
||||
* @return the object produced by this initializer
|
||||
* @throws ConcurrentException if a checked exception occurred during
|
||||
* background processing
|
||||
* @throws IllegalStateException if {@link #start()} has not been called
|
||||
*/
|
||||
@Override
|
||||
public T get() throws ConcurrentException {
|
||||
try {
|
||||
return getFuture().get();
|
||||
} catch (final ExecutionException execex) {
|
||||
ConcurrentUtils.handleCause(execex);
|
||||
return null; // should not be reached
|
||||
} catch (final InterruptedException iex) {
|
||||
// reset interrupted state
|
||||
Thread.currentThread().interrupt();
|
||||
throw new ConcurrentException(iex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ExecutorService} that is actually used for executing
|
||||
* the background task. This method can be called after {@link #start()}
|
||||
* (before {@code start()} it returns <b>null</b>). If an external executor
|
||||
* was set, this is also the active executor. Otherwise this method returns
|
||||
* the temporary executor that was created by this object.
|
||||
*
|
||||
* @return the {@link ExecutorService} for executing the background task
|
||||
*/
|
||||
protected final synchronized ExecutorService getActiveExecutor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the external {@link ExecutorService} to be used by this class.
|
||||
*
|
||||
|
@ -185,6 +283,46 @@ public class BackgroundInitializer<T> extends AbstractConcurrentInitializer<T, E
|
|||
return externalExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Future} object that was created when {@link #start()}
|
||||
* was called. Therefore this method can only be called after {@code
|
||||
* start()}.
|
||||
*
|
||||
* @return the {@link Future} object wrapped by this initializer
|
||||
* @throws IllegalStateException if {@link #start()} has not been called
|
||||
*/
|
||||
public synchronized Future<T> getFuture() {
|
||||
if (future == null) {
|
||||
throw new IllegalStateException("start() must be called first!");
|
||||
}
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of background tasks to be created for this
|
||||
* initializer. This information is evaluated when a temporary {@code
|
||||
* ExecutorService} is created. This base implementation returns 1. Derived
|
||||
* classes that do more complex background processing can override it. This
|
||||
* method is called from a synchronized block by the {@link #start()}
|
||||
* method. Therefore overriding methods should be careful with obtaining
|
||||
* other locks and return as fast as possible.
|
||||
*
|
||||
* @return the number of background tasks required by this initializer
|
||||
*/
|
||||
protected int getTaskCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected Exception getTypedException(Exception e) {
|
||||
//This Exception object will be used for type comparison in AbstractConcurrentInitializer.initialize but not thrown
|
||||
return new Exception(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether this instance is initialized. Once initialized, always returns true.
|
||||
* If initialization failed then the failure will be cached and this will never return
|
||||
|
@ -273,142 +411,4 @@ public class BackgroundInitializer<T> extends AbstractConcurrentInitializer<T, E
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result of the background initialization. This method blocks
|
||||
* until initialization is complete. If the background processing caused a
|
||||
* runtime exception, it is directly thrown by this method. Checked
|
||||
* exceptions, including {@link InterruptedException} are wrapped in a
|
||||
* {@link ConcurrentException}. Calling this method before {@link #start()}
|
||||
* was called causes an {@link IllegalStateException} exception to be
|
||||
* thrown.
|
||||
*
|
||||
* @return the object produced by this initializer
|
||||
* @throws ConcurrentException if a checked exception occurred during
|
||||
* background processing
|
||||
* @throws IllegalStateException if {@link #start()} has not been called
|
||||
*/
|
||||
@Override
|
||||
public T get() throws ConcurrentException {
|
||||
try {
|
||||
return getFuture().get();
|
||||
} catch (final ExecutionException execex) {
|
||||
ConcurrentUtils.handleCause(execex);
|
||||
return null; // should not be reached
|
||||
} catch (final InterruptedException iex) {
|
||||
// reset interrupted state
|
||||
Thread.currentThread().interrupt();
|
||||
throw new ConcurrentException(iex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Future} object that was created when {@link #start()}
|
||||
* was called. Therefore this method can only be called after {@code
|
||||
* start()}.
|
||||
*
|
||||
* @return the {@link Future} object wrapped by this initializer
|
||||
* @throws IllegalStateException if {@link #start()} has not been called
|
||||
*/
|
||||
public synchronized Future<T> getFuture() {
|
||||
if (future == null) {
|
||||
throw new IllegalStateException("start() must be called first!");
|
||||
}
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ExecutorService} that is actually used for executing
|
||||
* the background task. This method can be called after {@link #start()}
|
||||
* (before {@code start()} it returns <b>null</b>). If an external executor
|
||||
* was set, this is also the active executor. Otherwise this method returns
|
||||
* the temporary executor that was created by this object.
|
||||
*
|
||||
* @return the {@link ExecutorService} for executing the background task
|
||||
*/
|
||||
protected final synchronized ExecutorService getActiveExecutor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of background tasks to be created for this
|
||||
* initializer. This information is evaluated when a temporary {@code
|
||||
* ExecutorService} is created. This base implementation returns 1. Derived
|
||||
* classes that do more complex background processing can override it. This
|
||||
* method is called from a synchronized block by the {@link #start()}
|
||||
* method. Therefore overriding methods should be careful with obtaining
|
||||
* other locks and return as fast as possible.
|
||||
*
|
||||
* @return the number of background tasks required by this initializer
|
||||
*/
|
||||
protected int getTaskCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a task for the background initialization. The {@link Callable}
|
||||
* object returned by this method is passed to the {@link ExecutorService}.
|
||||
* This implementation returns a task that invokes the {@link #initialize()}
|
||||
* method. If a temporary {@link ExecutorService} is used, it is destroyed
|
||||
* at the end of the task.
|
||||
*
|
||||
* @param execDestroy the {@link ExecutorService} to be destroyed by the
|
||||
* task
|
||||
* @return a task for the background initialization
|
||||
*/
|
||||
private Callable<T> createTask(final ExecutorService execDestroy) {
|
||||
return new InitializationTask(execDestroy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link ExecutorService} to be used. This method is called if
|
||||
* no {@link ExecutorService} was provided at construction time.
|
||||
*
|
||||
* @return the {@link ExecutorService} to be used
|
||||
*/
|
||||
private ExecutorService createExecutor() {
|
||||
return Executors.newFixedThreadPool(getTaskCount());
|
||||
}
|
||||
|
||||
private class InitializationTask implements Callable<T> {
|
||||
/** Stores the executor service to be destroyed at the end. */
|
||||
private final ExecutorService execFinally;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link InitializationTask} and initializes
|
||||
* it with the {@link ExecutorService} to be destroyed at the end.
|
||||
*
|
||||
* @param exec the {@link ExecutorService}
|
||||
*/
|
||||
InitializationTask(final ExecutorService exec) {
|
||||
execFinally = exec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates initialization and returns the result.
|
||||
*
|
||||
* @return the result object
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
@Override
|
||||
public T call() throws Exception {
|
||||
try {
|
||||
return initialize();
|
||||
} finally {
|
||||
if (execFinally != null) {
|
||||
execFinally.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected Exception getTypedException(Exception e) {
|
||||
//This Exception object will be used for type comparison in AbstractConcurrentInitializer.initialize but not thrown
|
||||
return new Exception(e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,140 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||
* @since 3.0
|
||||
*/
|
||||
public class BasicThreadFactory implements ThreadFactory {
|
||||
/**
|
||||
* A <em>builder</em> class for creating instances of {@code
|
||||
* BasicThreadFactory}.
|
||||
*
|
||||
* <p>
|
||||
* Using this builder class instances of {@link BasicThreadFactory} can be
|
||||
* created and initialized. The class provides methods that correspond to
|
||||
* the configuration options supported by {@link BasicThreadFactory}. Method
|
||||
* chaining is supported. Refer to the documentation of {@code
|
||||
* BasicThreadFactory} for a usage example.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public static class Builder
|
||||
implements org.apache.commons.lang3.builder.Builder<BasicThreadFactory> {
|
||||
|
||||
/** The wrapped factory. */
|
||||
private ThreadFactory wrappedFactory;
|
||||
|
||||
/** The uncaught exception handler. */
|
||||
private Thread.UncaughtExceptionHandler exceptionHandler;
|
||||
|
||||
/** The naming pattern. */
|
||||
private String namingPattern;
|
||||
|
||||
/** The priority. */
|
||||
private Integer priority;
|
||||
|
||||
/** The daemon flag. */
|
||||
private Boolean daemon;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicThreadFactory} with all configuration
|
||||
* options that have been specified by calling methods on this builder.
|
||||
* After creating the factory {@link #reset()} is called.
|
||||
*
|
||||
* @return the new {@link BasicThreadFactory}
|
||||
*/
|
||||
@Override
|
||||
public BasicThreadFactory build() {
|
||||
final BasicThreadFactory factory = new BasicThreadFactory(this);
|
||||
reset();
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the daemon flag for the new {@link BasicThreadFactory}. If this
|
||||
* flag is set to <b>true</b> the new thread factory will create daemon
|
||||
* threads.
|
||||
*
|
||||
* @param daemon the value of the daemon flag
|
||||
* @return a reference to this {@link Builder}
|
||||
*/
|
||||
public Builder daemon(final boolean daemon) {
|
||||
this.daemon = Boolean.valueOf(daemon);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the naming pattern to be used by the new {@code
|
||||
* BasicThreadFactory}.
|
||||
*
|
||||
* @param pattern the naming pattern (must not be <b>null</b>)
|
||||
* @return a reference to this {@link Builder}
|
||||
* @throws NullPointerException if the naming pattern is <b>null</b>
|
||||
*/
|
||||
public Builder namingPattern(final String pattern) {
|
||||
Objects.requireNonNull(pattern, "pattern");
|
||||
|
||||
namingPattern = pattern;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the priority for the threads created by the new {@code
|
||||
* BasicThreadFactory}.
|
||||
*
|
||||
* @param priority the priority
|
||||
* @return a reference to this {@link Builder}
|
||||
*/
|
||||
public Builder priority(final int priority) {
|
||||
this.priority = Integer.valueOf(priority);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets this builder. All configuration options are set to default
|
||||
* values. Note: If the {@link #build()} method was called, it is not
|
||||
* necessary to call {@code reset()} explicitly because this is done
|
||||
* automatically.
|
||||
*/
|
||||
public void reset() {
|
||||
wrappedFactory = null;
|
||||
exceptionHandler = null;
|
||||
namingPattern = null;
|
||||
priority = null;
|
||||
daemon = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the uncaught exception handler for the threads created by the
|
||||
* new {@link BasicThreadFactory}.
|
||||
*
|
||||
* @param handler the {@link UncaughtExceptionHandler} (must not be
|
||||
* <b>null</b>)
|
||||
* @return a reference to this {@link Builder}
|
||||
* @throws NullPointerException if the exception handler is <b>null</b>
|
||||
*/
|
||||
public Builder uncaughtExceptionHandler(
|
||||
final Thread.UncaughtExceptionHandler handler) {
|
||||
Objects.requireNonNull(handler, "handler");
|
||||
|
||||
exceptionHandler = handler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link ThreadFactory} to be wrapped by the new {@code
|
||||
* BasicThreadFactory}.
|
||||
*
|
||||
* @param factory the wrapped {@link ThreadFactory} (must not be
|
||||
* <b>null</b>)
|
||||
* @return a reference to this {@link Builder}
|
||||
* @throws NullPointerException if the passed in {@link ThreadFactory}
|
||||
* is <b>null</b>
|
||||
*/
|
||||
public Builder wrappedFactory(final ThreadFactory factory) {
|
||||
Objects.requireNonNull(factory, "factory");
|
||||
|
||||
wrappedFactory = factory;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/** A counter for the threads created by this factory. */
|
||||
private final AtomicLong threadCounter;
|
||||
|
||||
|
@ -129,15 +263,15 @@ public class BasicThreadFactory implements ThreadFactory {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapped {@link ThreadFactory}. This factory is used for
|
||||
* actually creating threads. This method never returns <b>null</b>. If no
|
||||
* {@link ThreadFactory} was passed when this object was created, a default
|
||||
* thread factory is returned.
|
||||
* Returns the daemon flag. This flag determines whether newly created
|
||||
* threads should be daemon threads. If <b>true</b>, this factory object
|
||||
* calls {@code setDaemon(true)} on the newly created threads. Result can be
|
||||
* <b>null</b> if no daemon flag was provided at creation time.
|
||||
*
|
||||
* @return the wrapped {@link ThreadFactory}
|
||||
* @return the daemon flag
|
||||
*/
|
||||
public final ThreadFactory getWrappedFactory() {
|
||||
return wrappedFactory;
|
||||
public final Boolean getDaemonFlag() {
|
||||
return daemon;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -150,18 +284,6 @@ public class BasicThreadFactory implements ThreadFactory {
|
|||
return namingPattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the daemon flag. This flag determines whether newly created
|
||||
* threads should be daemon threads. If <b>true</b>, this factory object
|
||||
* calls {@code setDaemon(true)} on the newly created threads. Result can be
|
||||
* <b>null</b> if no daemon flag was provided at creation time.
|
||||
*
|
||||
* @return the daemon flag
|
||||
*/
|
||||
public final Boolean getDaemonFlag() {
|
||||
return daemon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the priority of the threads created by this factory. Result can
|
||||
* be <b>null</b> if no priority was specified.
|
||||
|
@ -172,16 +294,6 @@ public class BasicThreadFactory implements ThreadFactory {
|
|||
return priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link UncaughtExceptionHandler} for the threads created by
|
||||
* this factory. Result can be <b>null</b> if no handler was provided.
|
||||
*
|
||||
* @return the {@link UncaughtExceptionHandler}
|
||||
*/
|
||||
public final Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() {
|
||||
return uncaughtExceptionHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of threads this factory has already created. This
|
||||
* class maintains an internal counter that is incremented each time the
|
||||
|
@ -194,19 +306,25 @@ public class BasicThreadFactory implements ThreadFactory {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a new thread. This implementation delegates to the wrapped
|
||||
* factory for creating the thread. Then, on the newly created thread the
|
||||
* corresponding configuration options are set.
|
||||
* Returns the {@link UncaughtExceptionHandler} for the threads created by
|
||||
* this factory. Result can be <b>null</b> if no handler was provided.
|
||||
*
|
||||
* @param runnable the {@link Runnable} to be executed by the new thread
|
||||
* @return the newly created thread
|
||||
* @return the {@link UncaughtExceptionHandler}
|
||||
*/
|
||||
@Override
|
||||
public Thread newThread(final Runnable runnable) {
|
||||
final Thread thread = getWrappedFactory().newThread(runnable);
|
||||
initializeThread(thread);
|
||||
public final Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() {
|
||||
return uncaughtExceptionHandler;
|
||||
}
|
||||
|
||||
return thread;
|
||||
/**
|
||||
* Returns the wrapped {@link ThreadFactory}. This factory is used for
|
||||
* actually creating threads. This method never returns <b>null</b>. If no
|
||||
* {@link ThreadFactory} was passed when this object was created, a default
|
||||
* thread factory is returned.
|
||||
*
|
||||
* @return the wrapped {@link ThreadFactory}
|
||||
*/
|
||||
public final ThreadFactory getWrappedFactory() {
|
||||
return wrappedFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -238,136 +356,18 @@ public class BasicThreadFactory implements ThreadFactory {
|
|||
}
|
||||
|
||||
/**
|
||||
* A <em>builder</em> class for creating instances of {@code
|
||||
* BasicThreadFactory}.
|
||||
*
|
||||
* <p>
|
||||
* Using this builder class instances of {@link BasicThreadFactory} can be
|
||||
* created and initialized. The class provides methods that correspond to
|
||||
* the configuration options supported by {@link BasicThreadFactory}. Method
|
||||
* chaining is supported. Refer to the documentation of {@code
|
||||
* BasicThreadFactory} for a usage example.
|
||||
* </p>
|
||||
* Creates a new thread. This implementation delegates to the wrapped
|
||||
* factory for creating the thread. Then, on the newly created thread the
|
||||
* corresponding configuration options are set.
|
||||
*
|
||||
* @param runnable the {@link Runnable} to be executed by the new thread
|
||||
* @return the newly created thread
|
||||
*/
|
||||
public static class Builder
|
||||
implements org.apache.commons.lang3.builder.Builder<BasicThreadFactory> {
|
||||
@Override
|
||||
public Thread newThread(final Runnable runnable) {
|
||||
final Thread thread = getWrappedFactory().newThread(runnable);
|
||||
initializeThread(thread);
|
||||
|
||||
/** The wrapped factory. */
|
||||
private ThreadFactory wrappedFactory;
|
||||
|
||||
/** The uncaught exception handler. */
|
||||
private Thread.UncaughtExceptionHandler exceptionHandler;
|
||||
|
||||
/** The naming pattern. */
|
||||
private String namingPattern;
|
||||
|
||||
/** The priority. */
|
||||
private Integer priority;
|
||||
|
||||
/** The daemon flag. */
|
||||
private Boolean daemon;
|
||||
|
||||
/**
|
||||
* Sets the {@link ThreadFactory} to be wrapped by the new {@code
|
||||
* BasicThreadFactory}.
|
||||
*
|
||||
* @param factory the wrapped {@link ThreadFactory} (must not be
|
||||
* <b>null</b>)
|
||||
* @return a reference to this {@link Builder}
|
||||
* @throws NullPointerException if the passed in {@link ThreadFactory}
|
||||
* is <b>null</b>
|
||||
*/
|
||||
public Builder wrappedFactory(final ThreadFactory factory) {
|
||||
Objects.requireNonNull(factory, "factory");
|
||||
|
||||
wrappedFactory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the naming pattern to be used by the new {@code
|
||||
* BasicThreadFactory}.
|
||||
*
|
||||
* @param pattern the naming pattern (must not be <b>null</b>)
|
||||
* @return a reference to this {@link Builder}
|
||||
* @throws NullPointerException if the naming pattern is <b>null</b>
|
||||
*/
|
||||
public Builder namingPattern(final String pattern) {
|
||||
Objects.requireNonNull(pattern, "pattern");
|
||||
|
||||
namingPattern = pattern;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the daemon flag for the new {@link BasicThreadFactory}. If this
|
||||
* flag is set to <b>true</b> the new thread factory will create daemon
|
||||
* threads.
|
||||
*
|
||||
* @param daemon the value of the daemon flag
|
||||
* @return a reference to this {@link Builder}
|
||||
*/
|
||||
public Builder daemon(final boolean daemon) {
|
||||
this.daemon = Boolean.valueOf(daemon);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the priority for the threads created by the new {@code
|
||||
* BasicThreadFactory}.
|
||||
*
|
||||
* @param priority the priority
|
||||
* @return a reference to this {@link Builder}
|
||||
*/
|
||||
public Builder priority(final int priority) {
|
||||
this.priority = Integer.valueOf(priority);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the uncaught exception handler for the threads created by the
|
||||
* new {@link BasicThreadFactory}.
|
||||
*
|
||||
* @param handler the {@link UncaughtExceptionHandler} (must not be
|
||||
* <b>null</b>)
|
||||
* @return a reference to this {@link Builder}
|
||||
* @throws NullPointerException if the exception handler is <b>null</b>
|
||||
*/
|
||||
public Builder uncaughtExceptionHandler(
|
||||
final Thread.UncaughtExceptionHandler handler) {
|
||||
Objects.requireNonNull(handler, "handler");
|
||||
|
||||
exceptionHandler = handler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets this builder. All configuration options are set to default
|
||||
* values. Note: If the {@link #build()} method was called, it is not
|
||||
* necessary to call {@code reset()} explicitly because this is done
|
||||
* automatically.
|
||||
*/
|
||||
public void reset() {
|
||||
wrappedFactory = null;
|
||||
exceptionHandler = null;
|
||||
namingPattern = null;
|
||||
priority = null;
|
||||
daemon = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicThreadFactory} with all configuration
|
||||
* options that have been specified by calling methods on this builder.
|
||||
* After creating the factory {@link #reset()} is called.
|
||||
*
|
||||
* @return the new {@link BasicThreadFactory}
|
||||
*/
|
||||
@Override
|
||||
public BasicThreadFactory build() {
|
||||
final BasicThreadFactory factory = new BasicThreadFactory(this);
|
||||
reset();
|
||||
return factory;
|
||||
}
|
||||
return thread;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,19 +96,6 @@ public class CallableBackgroundInitializer<T> extends BackgroundInitializer<T> {
|
|||
callable = call;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs initialization in a background thread. This implementation
|
||||
* delegates to the {@link Callable} passed at construction time of this
|
||||
* object.
|
||||
*
|
||||
* @return the result of the initialization
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
@Override
|
||||
protected T initialize() throws Exception {
|
||||
return callable.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the passed in {@link Callable} and throws an exception if it is
|
||||
* undefined.
|
||||
|
@ -128,4 +115,17 @@ public class CallableBackgroundInitializer<T> extends BackgroundInitializer<T> {
|
|||
//This Exception object will be used for type comparison in AbstractConcurrentInitializer.initialize but not thrown
|
||||
return new Exception(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs initialization in a background thread. This implementation
|
||||
* delegates to the {@link Callable} passed at construction time of this
|
||||
* object.
|
||||
*
|
||||
* @return the result of the initialization
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
@Override
|
||||
protected T initialize() throws Exception {
|
||||
return callable.call();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,24 +40,6 @@ package org.apache.commons.lang3.concurrent;
|
|||
*/
|
||||
public interface CircuitBreaker<T> {
|
||||
|
||||
/**
|
||||
* Tests the current open state of this circuit breaker. A return value of
|
||||
* <strong>true</strong> means that the circuit breaker is currently open indicating a
|
||||
* problem in the monitored subsystem.
|
||||
*
|
||||
* @return the current open state of this circuit breaker.
|
||||
*/
|
||||
boolean isOpen();
|
||||
|
||||
/**
|
||||
* Tests the current closed state of this circuit breaker. A return value of
|
||||
* <strong>true</strong> means that the circuit breaker is currently closed. This
|
||||
* means that everything is okay with the monitored subsystem.
|
||||
*
|
||||
* @return the current closed state of this circuit breaker.
|
||||
*/
|
||||
boolean isClosed();
|
||||
|
||||
/**
|
||||
* Checks the state of this circuit breaker and changes it if necessary. The return
|
||||
* value indicates whether the circuit breaker is now in state <em>closed</em>; a value
|
||||
|
@ -74,13 +56,6 @@ public interface CircuitBreaker<T> {
|
|||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Opens this circuit breaker. Its state is changed to open. Depending on a concrete
|
||||
* implementation, it may close itself again if the monitored subsystem becomes
|
||||
* available. If this circuit breaker is already open, this method has no effect.
|
||||
*/
|
||||
void open();
|
||||
|
||||
/**
|
||||
* Increments the monitored value and performs a check of the current state of this
|
||||
* circuit breaker. This method works like {@link #checkState()}, but the monitored
|
||||
|
@ -91,4 +66,29 @@ public interface CircuitBreaker<T> {
|
|||
* <strong>false</strong> otherwise
|
||||
*/
|
||||
boolean incrementAndCheckState(T increment);
|
||||
|
||||
/**
|
||||
* Tests the current closed state of this circuit breaker. A return value of
|
||||
* <strong>true</strong> means that the circuit breaker is currently closed. This
|
||||
* means that everything is okay with the monitored subsystem.
|
||||
*
|
||||
* @return the current closed state of this circuit breaker.
|
||||
*/
|
||||
boolean isClosed();
|
||||
|
||||
/**
|
||||
* Tests the current open state of this circuit breaker. A return value of
|
||||
* <strong>true</strong> means that the circuit breaker is currently open indicating a
|
||||
* problem in the monitored subsystem.
|
||||
*
|
||||
* @return the current open state of this circuit breaker.
|
||||
*/
|
||||
boolean isOpen();
|
||||
|
||||
/**
|
||||
* Opens this circuit breaker. Its state is changed to open. Depending on a concrete
|
||||
* implementation, it may close itself again if the monitored subsystem becomes
|
||||
* available. If this circuit breaker is already open, this method has no effect.
|
||||
*/
|
||||
void open();
|
||||
}
|
||||
|
|
|
@ -34,6 +34,15 @@ public class CircuitBreakingException extends RuntimeException {
|
|||
public CircuitBreakingException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link CircuitBreakingException} and initializes it with the given message.
|
||||
*
|
||||
* @param message the error message
|
||||
*/
|
||||
public CircuitBreakingException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link CircuitBreakingException} and initializes it with the given message and cause.
|
||||
*
|
||||
|
@ -44,15 +53,6 @@ public class CircuitBreakingException extends RuntimeException {
|
|||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link CircuitBreakingException} and initializes it with the given message.
|
||||
*
|
||||
* @param message the error message
|
||||
*/
|
||||
public CircuitBreakingException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link CircuitBreakingException} and initializes it with the given cause.
|
||||
*
|
||||
|
|
|
@ -41,17 +41,6 @@ public class ConcurrentException extends Exception {
|
|||
protected ConcurrentException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link ConcurrentException} and initializes it
|
||||
* with the given cause.
|
||||
*
|
||||
* @param cause the cause of this exception
|
||||
* @throws IllegalArgumentException if the cause is not a checked exception
|
||||
*/
|
||||
public ConcurrentException(final Throwable cause) {
|
||||
super(ConcurrentUtils.checkedException(cause));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link ConcurrentException} and initializes it
|
||||
* with the given message and cause.
|
||||
|
@ -63,4 +52,15 @@ public class ConcurrentException extends Exception {
|
|||
public ConcurrentException(final String msg, final Throwable cause) {
|
||||
super(msg, ConcurrentUtils.checkedException(cause));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link ConcurrentException} and initializes it
|
||||
* with the given cause.
|
||||
*
|
||||
* @param cause the cause of this exception
|
||||
* @throws IllegalArgumentException if the cause is not a checked exception
|
||||
*/
|
||||
public ConcurrentException(final Throwable cause) {
|
||||
super(ConcurrentUtils.checkedException(cause));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,17 +44,6 @@ public class ConcurrentRuntimeException extends RuntimeException {
|
|||
protected ConcurrentRuntimeException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link ConcurrentRuntimeException} and
|
||||
* initializes it with the given cause.
|
||||
*
|
||||
* @param cause the cause of this exception
|
||||
* @throws IllegalArgumentException if the cause is not a checked exception
|
||||
*/
|
||||
public ConcurrentRuntimeException(final Throwable cause) {
|
||||
super(ConcurrentUtils.checkedException(cause));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link ConcurrentRuntimeException} and
|
||||
* initializes it with the given message and cause.
|
||||
|
@ -66,4 +55,15 @@ public class ConcurrentRuntimeException extends RuntimeException {
|
|||
public ConcurrentRuntimeException(final String msg, final Throwable cause) {
|
||||
super(msg, ConcurrentUtils.checkedException(cause));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link ConcurrentRuntimeException} and
|
||||
* initializes it with the given cause.
|
||||
*
|
||||
* @param cause the cause of this exception
|
||||
* @throws IllegalArgumentException if the cause is not a checked exception
|
||||
*/
|
||||
public ConcurrentRuntimeException(final Throwable cause) {
|
||||
super(ConcurrentUtils.checkedException(cause));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,10 +33,156 @@ import org.apache.commons.lang3.exception.ExceptionUtils;
|
|||
public class ConcurrentUtils {
|
||||
|
||||
/**
|
||||
* Private constructor so that no instances can be created. This class
|
||||
* contains only static utility methods.
|
||||
* A specialized {@link Future} implementation which wraps a constant value.
|
||||
* @param <T> the type of the value wrapped by this class
|
||||
*/
|
||||
private ConcurrentUtils() {
|
||||
static final class ConstantFuture<T> implements Future<T> {
|
||||
/** The constant value. */
|
||||
private final T value;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link ConstantFuture} and initializes it
|
||||
* with the constant value.
|
||||
*
|
||||
* @param value the value (may be <b>null</b>)
|
||||
*/
|
||||
ConstantFuture(final T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc} The cancel operation is not supported. This
|
||||
* implementation always returns <b>false</b>.
|
||||
*/
|
||||
@Override
|
||||
public boolean cancel(final boolean mayInterruptIfRunning) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc} This implementation just returns the constant value.
|
||||
*/
|
||||
@Override
|
||||
public T get() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc} This implementation just returns the constant value; it
|
||||
* does not block, therefore the timeout has no meaning.
|
||||
*/
|
||||
@Override
|
||||
public T get(final long timeout, final TimeUnit unit) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc} This implementation always returns <b>false</b>; there
|
||||
* is no background process which could be cancelled.
|
||||
*/
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc} This implementation always returns <b>true</b> because
|
||||
* the constant object managed by this {@link Future} implementation is
|
||||
* always available.
|
||||
*/
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the specified {@link Throwable} is a checked exception. If
|
||||
* not, an exception is thrown.
|
||||
*
|
||||
* @param ex the {@link Throwable} to check
|
||||
* @return a flag whether the passed in exception is a checked exception
|
||||
* @throws IllegalArgumentException if the {@link Throwable} is not a
|
||||
* checked exception
|
||||
*/
|
||||
static Throwable checkedException(final Throwable ex) {
|
||||
Validate.isTrue(ExceptionUtils.isChecked(ex), "Not a checked exception: " + ex);
|
||||
return ex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an implementation of {@link Future} that is immediately done
|
||||
* and returns the specified constant value.
|
||||
*
|
||||
* <p>
|
||||
* This can be useful to return a simple constant immediately from the
|
||||
* concurrent processing, perhaps as part of avoiding nulls.
|
||||
* A constant future can also be useful in testing.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the type of the value used by this {@link Future} object
|
||||
* @param value the constant value to return, may be null
|
||||
* @return an instance of Future that will return the value, never null
|
||||
*/
|
||||
public static <T> Future<T> constantFuture(final T value) {
|
||||
return new ConstantFuture<>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a concurrent map contains a key and creates a corresponding
|
||||
* value if not. This method first checks the presence of the key in the
|
||||
* given map. If it is already contained, its value is returned. Otherwise
|
||||
* the {@code get()} method of the passed in {@link ConcurrentInitializer}
|
||||
* is called. With the resulting object
|
||||
* {@link #putIfAbsent(ConcurrentMap, Object, Object)} is called. This
|
||||
* handles the case that in the meantime another thread has added the key to
|
||||
* the map. Both the map and the initializer can be <b>null</b>; in this
|
||||
* case this method simply returns <b>null</b>.
|
||||
*
|
||||
* @param <K> the type of the keys of the map
|
||||
* @param <V> the type of the values of the map
|
||||
* @param map the map to be modified
|
||||
* @param key the key of the value to be added
|
||||
* @param init the {@link ConcurrentInitializer} for creating the value
|
||||
* @return the value stored in the map after this operation; this may or may
|
||||
* not be the object created by the {@link ConcurrentInitializer}
|
||||
* @throws ConcurrentException if the initializer throws an exception
|
||||
*/
|
||||
public static <K, V> V createIfAbsent(final ConcurrentMap<K, V> map, final K key,
|
||||
final ConcurrentInitializer<V> init) throws ConcurrentException {
|
||||
if (map == null || init == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final V value = map.get(key);
|
||||
if (value == null) {
|
||||
return putIfAbsent(map, key, init.get());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a concurrent map contains a key and creates a corresponding
|
||||
* value if not, suppressing checked exceptions. This method calls
|
||||
* {@code createIfAbsent()}. If a {@link ConcurrentException} is thrown, it
|
||||
* is caught and re-thrown as a {@link ConcurrentRuntimeException}.
|
||||
*
|
||||
* @param <K> the type of the keys of the map
|
||||
* @param <V> the type of the values of the map
|
||||
* @param map the map to be modified
|
||||
* @param key the key of the value to be added
|
||||
* @param init the {@link ConcurrentInitializer} for creating the value
|
||||
* @return the value stored in the map after this operation; this may or may
|
||||
* not be the object created by the {@link ConcurrentInitializer}
|
||||
* @throws ConcurrentRuntimeException if the initializer throws an exception
|
||||
*/
|
||||
public static <K, V> V createIfAbsentUnchecked(final ConcurrentMap<K, V> map,
|
||||
final K key, final ConcurrentInitializer<V> init) {
|
||||
try {
|
||||
return createIfAbsent(map, key, init);
|
||||
} catch (final ConcurrentException cex) {
|
||||
throw new ConcurrentRuntimeException(cex.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,20 +276,6 @@ public class ConcurrentUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the specified {@link Throwable} is a checked exception. If
|
||||
* not, an exception is thrown.
|
||||
*
|
||||
* @param ex the {@link Throwable} to check
|
||||
* @return a flag whether the passed in exception is a checked exception
|
||||
* @throws IllegalArgumentException if the {@link Throwable} is not a
|
||||
* checked exception
|
||||
*/
|
||||
static Throwable checkedException(final Throwable ex) {
|
||||
Validate.isTrue(ExceptionUtils.isChecked(ex), "Not a checked exception: " + ex);
|
||||
return ex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the specified {@link ConcurrentInitializer} and returns the
|
||||
* object produced by the initializer. This method just invokes the {@code
|
||||
|
@ -225,142 +357,10 @@ public class ConcurrentUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks if a concurrent map contains a key and creates a corresponding
|
||||
* value if not. This method first checks the presence of the key in the
|
||||
* given map. If it is already contained, its value is returned. Otherwise
|
||||
* the {@code get()} method of the passed in {@link ConcurrentInitializer}
|
||||
* is called. With the resulting object
|
||||
* {@link #putIfAbsent(ConcurrentMap, Object, Object)} is called. This
|
||||
* handles the case that in the meantime another thread has added the key to
|
||||
* the map. Both the map and the initializer can be <b>null</b>; in this
|
||||
* case this method simply returns <b>null</b>.
|
||||
*
|
||||
* @param <K> the type of the keys of the map
|
||||
* @param <V> the type of the values of the map
|
||||
* @param map the map to be modified
|
||||
* @param key the key of the value to be added
|
||||
* @param init the {@link ConcurrentInitializer} for creating the value
|
||||
* @return the value stored in the map after this operation; this may or may
|
||||
* not be the object created by the {@link ConcurrentInitializer}
|
||||
* @throws ConcurrentException if the initializer throws an exception
|
||||
* Private constructor so that no instances can be created. This class
|
||||
* contains only static utility methods.
|
||||
*/
|
||||
public static <K, V> V createIfAbsent(final ConcurrentMap<K, V> map, final K key,
|
||||
final ConcurrentInitializer<V> init) throws ConcurrentException {
|
||||
if (map == null || init == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final V value = map.get(key);
|
||||
if (value == null) {
|
||||
return putIfAbsent(map, key, init.get());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a concurrent map contains a key and creates a corresponding
|
||||
* value if not, suppressing checked exceptions. This method calls
|
||||
* {@code createIfAbsent()}. If a {@link ConcurrentException} is thrown, it
|
||||
* is caught and re-thrown as a {@link ConcurrentRuntimeException}.
|
||||
*
|
||||
* @param <K> the type of the keys of the map
|
||||
* @param <V> the type of the values of the map
|
||||
* @param map the map to be modified
|
||||
* @param key the key of the value to be added
|
||||
* @param init the {@link ConcurrentInitializer} for creating the value
|
||||
* @return the value stored in the map after this operation; this may or may
|
||||
* not be the object created by the {@link ConcurrentInitializer}
|
||||
* @throws ConcurrentRuntimeException if the initializer throws an exception
|
||||
*/
|
||||
public static <K, V> V createIfAbsentUnchecked(final ConcurrentMap<K, V> map,
|
||||
final K key, final ConcurrentInitializer<V> init) {
|
||||
try {
|
||||
return createIfAbsent(map, key, init);
|
||||
} catch (final ConcurrentException cex) {
|
||||
throw new ConcurrentRuntimeException(cex.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an implementation of {@link Future} that is immediately done
|
||||
* and returns the specified constant value.
|
||||
*
|
||||
* <p>
|
||||
* This can be useful to return a simple constant immediately from the
|
||||
* concurrent processing, perhaps as part of avoiding nulls.
|
||||
* A constant future can also be useful in testing.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the type of the value used by this {@link Future} object
|
||||
* @param value the constant value to return, may be null
|
||||
* @return an instance of Future that will return the value, never null
|
||||
*/
|
||||
public static <T> Future<T> constantFuture(final T value) {
|
||||
return new ConstantFuture<>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* A specialized {@link Future} implementation which wraps a constant value.
|
||||
* @param <T> the type of the value wrapped by this class
|
||||
*/
|
||||
static final class ConstantFuture<T> implements Future<T> {
|
||||
/** The constant value. */
|
||||
private final T value;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link ConstantFuture} and initializes it
|
||||
* with the constant value.
|
||||
*
|
||||
* @param value the value (may be <b>null</b>)
|
||||
*/
|
||||
ConstantFuture(final T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc} This implementation always returns <b>true</b> because
|
||||
* the constant object managed by this {@link Future} implementation is
|
||||
* always available.
|
||||
*/
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc} This implementation just returns the constant value.
|
||||
*/
|
||||
@Override
|
||||
public T get() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc} This implementation just returns the constant value; it
|
||||
* does not block, therefore the timeout has no meaning.
|
||||
*/
|
||||
@Override
|
||||
public T get(final long timeout, final TimeUnit unit) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc} This implementation always returns <b>false</b>; there
|
||||
* is no background process which could be cancelled.
|
||||
*/
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc} The cancel operation is not supported. This
|
||||
* implementation always returns <b>false</b>.
|
||||
*/
|
||||
@Override
|
||||
public boolean cancel(final boolean mayInterruptIfRunning) {
|
||||
return false;
|
||||
}
|
||||
private ConcurrentUtils() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,51 +57,6 @@ public class ConstantInitializer<T> implements ConcurrentInitializer<T> {
|
|||
object = obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly returns the object that was passed to the constructor. This is
|
||||
* the same object as returned by {@code get()}. However, this method does
|
||||
* not declare that it throws an exception.
|
||||
*
|
||||
* @return the object managed by this initializer
|
||||
*/
|
||||
public final T getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object managed by this initializer. This implementation just
|
||||
* returns the object passed to the constructor.
|
||||
*
|
||||
* @return the object managed by this initializer
|
||||
* @throws ConcurrentException if an error occurs
|
||||
*/
|
||||
@Override
|
||||
public T get() throws ConcurrentException {
|
||||
return getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* As a {@link ConstantInitializer} is initialized on construction this will
|
||||
* always return true.
|
||||
*
|
||||
* @return true.
|
||||
* @since 3.14.0
|
||||
*/
|
||||
public boolean isInitialized() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code for this object. This implementation returns the hash
|
||||
* code of the managed object.
|
||||
*
|
||||
* @return a hash code for this object
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object with another one. This implementation returns
|
||||
* <b>true</b> if and only if the passed in object is an instance of
|
||||
|
@ -124,6 +79,51 @@ public class ConstantInitializer<T> implements ConcurrentInitializer<T> {
|
|||
return Objects.equals(getObject(), c.getObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object managed by this initializer. This implementation just
|
||||
* returns the object passed to the constructor.
|
||||
*
|
||||
* @return the object managed by this initializer
|
||||
* @throws ConcurrentException if an error occurs
|
||||
*/
|
||||
@Override
|
||||
public T get() throws ConcurrentException {
|
||||
return getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly returns the object that was passed to the constructor. This is
|
||||
* the same object as returned by {@code get()}. However, this method does
|
||||
* not declare that it throws an exception.
|
||||
*
|
||||
* @return the object managed by this initializer
|
||||
*/
|
||||
public final T getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code for this object. This implementation returns the hash
|
||||
* code of the managed object.
|
||||
*
|
||||
* @return a hash code for this object
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* As a {@link ConstantInitializer} is initialized on construction this will
|
||||
* always return true.
|
||||
*
|
||||
* @return true.
|
||||
* @since 3.14.0
|
||||
*/
|
||||
public boolean isInitialized() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation for this object. This string also
|
||||
* contains a string representation of the object managed by this
|
||||
|
|
|
@ -137,9 +137,176 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||
*/
|
||||
public class EventCountCircuitBreaker extends AbstractCircuitBreaker<Integer> {
|
||||
|
||||
/**
|
||||
* An internally used data class holding information about the checks performed by
|
||||
* this class. Basically, the number of received events and the start time of the
|
||||
* current check interval are stored.
|
||||
*/
|
||||
private static final class CheckIntervalData {
|
||||
/** The counter for events. */
|
||||
private final int eventCount;
|
||||
|
||||
/** The start time of the current check interval. */
|
||||
private final long checkIntervalStart;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link CheckIntervalData}.
|
||||
*
|
||||
* @param count the current count value
|
||||
* @param intervalStart the start time of the check interval
|
||||
*/
|
||||
CheckIntervalData(final int count, final long intervalStart) {
|
||||
eventCount = count;
|
||||
checkIntervalStart = intervalStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start time of the current check interval.
|
||||
*
|
||||
* @return the check interval start time
|
||||
*/
|
||||
public long getCheckIntervalStart() {
|
||||
return checkIntervalStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event counter.
|
||||
*
|
||||
* @return the number of received events
|
||||
*/
|
||||
public int getEventCount() {
|
||||
return eventCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of {@link CheckIntervalData} with the event counter
|
||||
* incremented by the given delta. If the delta is 0, this object is returned.
|
||||
*
|
||||
* @param delta the delta
|
||||
* @return the updated instance
|
||||
*/
|
||||
public CheckIntervalData increment(final int delta) {
|
||||
return delta == 0 ? this : new CheckIntervalData(getEventCount() + delta,
|
||||
getCheckIntervalStart());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internally used class for executing check logic based on the current state of the
|
||||
* circuit breaker. Having this logic extracted into special classes avoids complex
|
||||
* if-then-else cascades.
|
||||
*/
|
||||
private abstract static class StateStrategy {
|
||||
/**
|
||||
* Obtains the check interval to applied for the represented state from the given
|
||||
* {@link CircuitBreaker}.
|
||||
*
|
||||
* @param breaker the {@link CircuitBreaker}
|
||||
* @return the check interval to be applied
|
||||
*/
|
||||
protected abstract long fetchCheckInterval(EventCountCircuitBreaker breaker);
|
||||
|
||||
/**
|
||||
* Returns a flag whether the end of the current check interval is reached.
|
||||
*
|
||||
* @param breaker the {@link CircuitBreaker}
|
||||
* @param currentData the current state object
|
||||
* @param now the current time
|
||||
* @return a flag whether the end of the current check interval is reached
|
||||
*/
|
||||
public boolean isCheckIntervalFinished(final EventCountCircuitBreaker breaker,
|
||||
final CheckIntervalData currentData, final long now) {
|
||||
return now - currentData.getCheckIntervalStart() > fetchCheckInterval(breaker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the specified {@link CheckIntervalData} objects indicate that a
|
||||
* state transition should occur. Here the logic which checks for thresholds
|
||||
* depending on the current state is implemented.
|
||||
*
|
||||
* @param breaker the {@link CircuitBreaker}
|
||||
* @param currentData the current {@link CheckIntervalData} object
|
||||
* @param nextData the updated {@link CheckIntervalData} object
|
||||
* @return a flag whether a state transition should be performed
|
||||
*/
|
||||
public abstract boolean isStateTransition(EventCountCircuitBreaker breaker,
|
||||
CheckIntervalData currentData, CheckIntervalData nextData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A specialized {@link StateStrategy} implementation for the state closed.
|
||||
*/
|
||||
private static final class StateStrategyClosed extends StateStrategy {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected long fetchCheckInterval(final EventCountCircuitBreaker breaker) {
|
||||
return breaker.getOpeningInterval();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isStateTransition(final EventCountCircuitBreaker breaker,
|
||||
final CheckIntervalData currentData, final CheckIntervalData nextData) {
|
||||
return nextData.getEventCount() > breaker.getOpeningThreshold();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A specialized {@link StateStrategy} implementation for the state open.
|
||||
*/
|
||||
private static final class StateStrategyOpen extends StateStrategy {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected long fetchCheckInterval(final EventCountCircuitBreaker breaker) {
|
||||
return breaker.getClosingInterval();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isStateTransition(final EventCountCircuitBreaker breaker,
|
||||
final CheckIntervalData currentData, final CheckIntervalData nextData) {
|
||||
return nextData.getCheckIntervalStart() != currentData
|
||||
.getCheckIntervalStart()
|
||||
&& currentData.getEventCount() < breaker.getClosingThreshold();
|
||||
}
|
||||
}
|
||||
|
||||
/** A map for accessing the strategy objects for the different states. */
|
||||
private static final Map<State, StateStrategy> STRATEGY_MAP = createStrategyMap();
|
||||
|
||||
/**
|
||||
* Creates the map with strategy objects. It allows access for a strategy for a given
|
||||
* state.
|
||||
*
|
||||
* @return the strategy map
|
||||
*/
|
||||
private static Map<State, StateStrategy> createStrategyMap() {
|
||||
final Map<State, StateStrategy> map = new EnumMap<>(State.class);
|
||||
map.put(State.CLOSED, new StateStrategyClosed());
|
||||
map.put(State.OPEN, new StateStrategyOpen());
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link StateStrategy} object responsible for the given state.
|
||||
*
|
||||
* @param state the state
|
||||
* @return the corresponding {@link StateStrategy}
|
||||
* @throws CircuitBreakingException if the strategy cannot be resolved
|
||||
*/
|
||||
private static StateStrategy stateStrategy(final State state) {
|
||||
return STRATEGY_MAP.get(state);
|
||||
}
|
||||
|
||||
/** Stores information about the current check interval. */
|
||||
private final AtomicReference<CheckIntervalData> checkIntervalData;
|
||||
|
||||
|
@ -155,6 +322,39 @@ public class EventCountCircuitBreaker extends AbstractCircuitBreaker<Integer> {
|
|||
/** The time interval for closing the circuit breaker. */
|
||||
private final long closingInterval;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link EventCountCircuitBreaker} which uses the same parameters for
|
||||
* opening and closing checks.
|
||||
*
|
||||
* @param threshold the threshold for changing the status of the circuit breaker; if
|
||||
* the number of events received in a check interval is greater than this value, the
|
||||
* circuit breaker is opened; if it is lower than this value, it is closed again
|
||||
* @param checkInterval the check interval for opening or closing the circuit breaker
|
||||
* @param checkUnit the {@link TimeUnit} defining the check interval
|
||||
*/
|
||||
public EventCountCircuitBreaker(final int threshold, final long checkInterval, final TimeUnit checkUnit) {
|
||||
this(threshold, checkInterval, checkUnit, threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link EventCountCircuitBreaker} with the same interval for opening
|
||||
* and closing checks.
|
||||
*
|
||||
* @param openingThreshold the threshold for opening the circuit breaker; if this
|
||||
* number of events is received in the time span determined by the check interval, the
|
||||
* circuit breaker is opened
|
||||
* @param checkInterval the check interval for opening or closing the circuit breaker
|
||||
* @param checkUnit the {@link TimeUnit} defining the check interval
|
||||
* @param closingThreshold the threshold for closing the circuit breaker; if the
|
||||
* number of events received in the time span determined by the check interval goes
|
||||
* below this threshold, the circuit breaker is closed again
|
||||
*/
|
||||
public EventCountCircuitBreaker(final int openingThreshold, final long checkInterval, final TimeUnit checkUnit,
|
||||
final int closingThreshold) {
|
||||
this(openingThreshold, checkInterval, checkUnit, closingThreshold, checkInterval,
|
||||
checkUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link EventCountCircuitBreaker} and initializes all properties for
|
||||
* opening and closing it based on threshold values for events occurring in specific
|
||||
|
@ -182,76 +382,14 @@ public class EventCountCircuitBreaker extends AbstractCircuitBreaker<Integer> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link EventCountCircuitBreaker} with the same interval for opening
|
||||
* and closing checks.
|
||||
* Changes the state of this circuit breaker and also initializes a new
|
||||
* {@link CheckIntervalData} object.
|
||||
*
|
||||
* @param openingThreshold the threshold for opening the circuit breaker; if this
|
||||
* number of events is received in the time span determined by the check interval, the
|
||||
* circuit breaker is opened
|
||||
* @param checkInterval the check interval for opening or closing the circuit breaker
|
||||
* @param checkUnit the {@link TimeUnit} defining the check interval
|
||||
* @param closingThreshold the threshold for closing the circuit breaker; if the
|
||||
* number of events received in the time span determined by the check interval goes
|
||||
* below this threshold, the circuit breaker is closed again
|
||||
* @param newState the new state to be set
|
||||
*/
|
||||
public EventCountCircuitBreaker(final int openingThreshold, final long checkInterval, final TimeUnit checkUnit,
|
||||
final int closingThreshold) {
|
||||
this(openingThreshold, checkInterval, checkUnit, closingThreshold, checkInterval,
|
||||
checkUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link EventCountCircuitBreaker} which uses the same parameters for
|
||||
* opening and closing checks.
|
||||
*
|
||||
* @param threshold the threshold for changing the status of the circuit breaker; if
|
||||
* the number of events received in a check interval is greater than this value, the
|
||||
* circuit breaker is opened; if it is lower than this value, it is closed again
|
||||
* @param checkInterval the check interval for opening or closing the circuit breaker
|
||||
* @param checkUnit the {@link TimeUnit} defining the check interval
|
||||
*/
|
||||
public EventCountCircuitBreaker(final int threshold, final long checkInterval, final TimeUnit checkUnit) {
|
||||
this(threshold, checkInterval, checkUnit, threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the threshold value for opening the circuit breaker. If this number of
|
||||
* events is received in the time span determined by the opening interval, the circuit
|
||||
* breaker is opened.
|
||||
*
|
||||
* @return the opening threshold
|
||||
*/
|
||||
public int getOpeningThreshold() {
|
||||
return openingThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interval (in nanoseconds) for checking for the opening threshold.
|
||||
*
|
||||
* @return the opening check interval
|
||||
*/
|
||||
public long getOpeningInterval() {
|
||||
return openingInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the threshold value for closing the circuit breaker. If the number of
|
||||
* events received in the time span determined by the closing interval goes below this
|
||||
* threshold, the circuit breaker is closed again.
|
||||
*
|
||||
* @return the closing threshold
|
||||
*/
|
||||
public int getClosingThreshold() {
|
||||
return closingThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interval (in nanoseconds) for checking for the closing threshold.
|
||||
*
|
||||
* @return the opening check interval
|
||||
*/
|
||||
public long getClosingInterval() {
|
||||
return closingInterval;
|
||||
private void changeStateAndStartNewCheckInterval(final State newState) {
|
||||
changeState(newState);
|
||||
checkIntervalData.set(new CheckIntervalData(0, nanoTime()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -269,10 +407,57 @@ public class EventCountCircuitBreaker extends AbstractCircuitBreaker<Integer> {
|
|||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
* A new check interval is started. If too many events are received in
|
||||
* this interval, the circuit breaker changes again to state open. If this circuit
|
||||
* breaker is already closed, this method has no effect, except that a new check
|
||||
* interval is started.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public boolean incrementAndCheckState(final Integer increment) {
|
||||
return performStateCheck(increment);
|
||||
public void close() {
|
||||
super.close();
|
||||
checkIntervalData.set(new CheckIntervalData(0, nanoTime()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interval (in nanoseconds) for checking for the closing threshold.
|
||||
*
|
||||
* @return the opening check interval
|
||||
*/
|
||||
public long getClosingInterval() {
|
||||
return closingInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the threshold value for closing the circuit breaker. If the number of
|
||||
* events received in the time span determined by the closing interval goes below this
|
||||
* threshold, the circuit breaker is closed again.
|
||||
*
|
||||
* @return the closing threshold
|
||||
*/
|
||||
public int getClosingThreshold() {
|
||||
return closingThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interval (in nanoseconds) for checking for the opening threshold.
|
||||
*
|
||||
* @return the opening check interval
|
||||
*/
|
||||
public long getOpeningInterval() {
|
||||
return openingInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the threshold value for opening the circuit breaker. If this number of
|
||||
* events is received in the time span determined by the opening interval, the circuit
|
||||
* breaker is opened.
|
||||
*
|
||||
* @return the opening threshold
|
||||
*/
|
||||
public int getOpeningThreshold() {
|
||||
return openingThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -287,6 +472,46 @@ public class EventCountCircuitBreaker extends AbstractCircuitBreaker<Integer> {
|
|||
return incrementAndCheckState(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean incrementAndCheckState(final Integer increment) {
|
||||
return performStateCheck(increment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time in nanoseconds. This method is used to obtain the current
|
||||
* time. This is needed to calculate the check intervals correctly.
|
||||
*
|
||||
* @return the current time in nanoseconds
|
||||
*/
|
||||
long nanoTime() {
|
||||
return System.nanoTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the next {@link CheckIntervalData} object based on the current data and
|
||||
* the current state. The next data object takes the counter increment and the current
|
||||
* time into account.
|
||||
*
|
||||
* @param increment the increment for the internal counter
|
||||
* @param currentData the current check data object
|
||||
* @param currentState the current state of the circuit breaker
|
||||
* @param time the current time
|
||||
* @return the updated {@link CheckIntervalData} object
|
||||
*/
|
||||
private CheckIntervalData nextCheckIntervalData(final int increment,
|
||||
final CheckIntervalData currentData, final State currentState, final long time) {
|
||||
final CheckIntervalData nextData;
|
||||
if (stateStrategy(currentState).isCheckIntervalFinished(this, currentData, time)) {
|
||||
nextData = new CheckIntervalData(increment, time);
|
||||
} else {
|
||||
nextData = currentData.increment(increment);
|
||||
}
|
||||
return nextData;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
|
@ -302,21 +527,6 @@ public class EventCountCircuitBreaker extends AbstractCircuitBreaker<Integer> {
|
|||
checkIntervalData.set(new CheckIntervalData(0, nanoTime()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
* A new check interval is started. If too many events are received in
|
||||
* this interval, the circuit breaker changes again to state open. If this circuit
|
||||
* breaker is already closed, this method has no effect, except that a new check
|
||||
* interval is started.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
super.close();
|
||||
checkIntervalData.set(new CheckIntervalData(0, nanoTime()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually checks the state of this circuit breaker and executes a state transition
|
||||
* if necessary.
|
||||
|
@ -361,214 +571,4 @@ public class EventCountCircuitBreaker extends AbstractCircuitBreaker<Integer> {
|
|||
|| checkIntervalData.compareAndSet(currentData, nextData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the state of this circuit breaker and also initializes a new
|
||||
* {@link CheckIntervalData} object.
|
||||
*
|
||||
* @param newState the new state to be set
|
||||
*/
|
||||
private void changeStateAndStartNewCheckInterval(final State newState) {
|
||||
changeState(newState);
|
||||
checkIntervalData.set(new CheckIntervalData(0, nanoTime()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the next {@link CheckIntervalData} object based on the current data and
|
||||
* the current state. The next data object takes the counter increment and the current
|
||||
* time into account.
|
||||
*
|
||||
* @param increment the increment for the internal counter
|
||||
* @param currentData the current check data object
|
||||
* @param currentState the current state of the circuit breaker
|
||||
* @param time the current time
|
||||
* @return the updated {@link CheckIntervalData} object
|
||||
*/
|
||||
private CheckIntervalData nextCheckIntervalData(final int increment,
|
||||
final CheckIntervalData currentData, final State currentState, final long time) {
|
||||
final CheckIntervalData nextData;
|
||||
if (stateStrategy(currentState).isCheckIntervalFinished(this, currentData, time)) {
|
||||
nextData = new CheckIntervalData(increment, time);
|
||||
} else {
|
||||
nextData = currentData.increment(increment);
|
||||
}
|
||||
return nextData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time in nanoseconds. This method is used to obtain the current
|
||||
* time. This is needed to calculate the check intervals correctly.
|
||||
*
|
||||
* @return the current time in nanoseconds
|
||||
*/
|
||||
long nanoTime() {
|
||||
return System.nanoTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link StateStrategy} object responsible for the given state.
|
||||
*
|
||||
* @param state the state
|
||||
* @return the corresponding {@link StateStrategy}
|
||||
* @throws CircuitBreakingException if the strategy cannot be resolved
|
||||
*/
|
||||
private static StateStrategy stateStrategy(final State state) {
|
||||
return STRATEGY_MAP.get(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the map with strategy objects. It allows access for a strategy for a given
|
||||
* state.
|
||||
*
|
||||
* @return the strategy map
|
||||
*/
|
||||
private static Map<State, StateStrategy> createStrategyMap() {
|
||||
final Map<State, StateStrategy> map = new EnumMap<>(State.class);
|
||||
map.put(State.CLOSED, new StateStrategyClosed());
|
||||
map.put(State.OPEN, new StateStrategyOpen());
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* An internally used data class holding information about the checks performed by
|
||||
* this class. Basically, the number of received events and the start time of the
|
||||
* current check interval are stored.
|
||||
*/
|
||||
private static final class CheckIntervalData {
|
||||
/** The counter for events. */
|
||||
private final int eventCount;
|
||||
|
||||
/** The start time of the current check interval. */
|
||||
private final long checkIntervalStart;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link CheckIntervalData}.
|
||||
*
|
||||
* @param count the current count value
|
||||
* @param intervalStart the start time of the check interval
|
||||
*/
|
||||
CheckIntervalData(final int count, final long intervalStart) {
|
||||
eventCount = count;
|
||||
checkIntervalStart = intervalStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event counter.
|
||||
*
|
||||
* @return the number of received events
|
||||
*/
|
||||
public int getEventCount() {
|
||||
return eventCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start time of the current check interval.
|
||||
*
|
||||
* @return the check interval start time
|
||||
*/
|
||||
public long getCheckIntervalStart() {
|
||||
return checkIntervalStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of {@link CheckIntervalData} with the event counter
|
||||
* incremented by the given delta. If the delta is 0, this object is returned.
|
||||
*
|
||||
* @param delta the delta
|
||||
* @return the updated instance
|
||||
*/
|
||||
public CheckIntervalData increment(final int delta) {
|
||||
return delta == 0 ? this : new CheckIntervalData(getEventCount() + delta,
|
||||
getCheckIntervalStart());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internally used class for executing check logic based on the current state of the
|
||||
* circuit breaker. Having this logic extracted into special classes avoids complex
|
||||
* if-then-else cascades.
|
||||
*/
|
||||
private abstract static class StateStrategy {
|
||||
/**
|
||||
* Returns a flag whether the end of the current check interval is reached.
|
||||
*
|
||||
* @param breaker the {@link CircuitBreaker}
|
||||
* @param currentData the current state object
|
||||
* @param now the current time
|
||||
* @return a flag whether the end of the current check interval is reached
|
||||
*/
|
||||
public boolean isCheckIntervalFinished(final EventCountCircuitBreaker breaker,
|
||||
final CheckIntervalData currentData, final long now) {
|
||||
return now - currentData.getCheckIntervalStart() > fetchCheckInterval(breaker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the specified {@link CheckIntervalData} objects indicate that a
|
||||
* state transition should occur. Here the logic which checks for thresholds
|
||||
* depending on the current state is implemented.
|
||||
*
|
||||
* @param breaker the {@link CircuitBreaker}
|
||||
* @param currentData the current {@link CheckIntervalData} object
|
||||
* @param nextData the updated {@link CheckIntervalData} object
|
||||
* @return a flag whether a state transition should be performed
|
||||
*/
|
||||
public abstract boolean isStateTransition(EventCountCircuitBreaker breaker,
|
||||
CheckIntervalData currentData, CheckIntervalData nextData);
|
||||
|
||||
/**
|
||||
* Obtains the check interval to applied for the represented state from the given
|
||||
* {@link CircuitBreaker}.
|
||||
*
|
||||
* @param breaker the {@link CircuitBreaker}
|
||||
* @return the check interval to be applied
|
||||
*/
|
||||
protected abstract long fetchCheckInterval(EventCountCircuitBreaker breaker);
|
||||
}
|
||||
|
||||
/**
|
||||
* A specialized {@link StateStrategy} implementation for the state closed.
|
||||
*/
|
||||
private static final class StateStrategyClosed extends StateStrategy {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isStateTransition(final EventCountCircuitBreaker breaker,
|
||||
final CheckIntervalData currentData, final CheckIntervalData nextData) {
|
||||
return nextData.getEventCount() > breaker.getOpeningThreshold();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected long fetchCheckInterval(final EventCountCircuitBreaker breaker) {
|
||||
return breaker.getOpeningInterval();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A specialized {@link StateStrategy} implementation for the state open.
|
||||
*/
|
||||
private static final class StateStrategyOpen extends StateStrategy {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isStateTransition(final EventCountCircuitBreaker breaker,
|
||||
final CheckIntervalData currentData, final CheckIntervalData nextData) {
|
||||
return nextData.getCheckIntervalStart() != currentData
|
||||
.getCheckIntervalStart()
|
||||
&& currentData.getEventCount() < breaker.getClosingThreshold();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected long fetchCheckInterval(final EventCountCircuitBreaker breaker) {
|
||||
return breaker.getClosingInterval();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,10 +26,6 @@ import java.util.concurrent.FutureTask;
|
|||
*/
|
||||
public class FutureTasks {
|
||||
|
||||
private FutureTasks() {
|
||||
// No instances needed.
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link FutureTask} and runs the given {@link Callable}.
|
||||
*
|
||||
|
@ -42,4 +38,8 @@ public class FutureTasks {
|
|||
futureTask.run();
|
||||
return futureTask;
|
||||
}
|
||||
|
||||
private FutureTasks() {
|
||||
// No instances needed.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,6 +148,14 @@ public class LazyInitializer<T> extends AbstractConcurrentInitializer<T, Concurr
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected ConcurrentException getTypedException(Exception e) {
|
||||
return new ConcurrentException(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether this instance is initialized. Once initialized, always returns true.
|
||||
*
|
||||
|
@ -159,12 +167,4 @@ public class LazyInitializer<T> extends AbstractConcurrentInitializer<T, Concurr
|
|||
return object != NO_INIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected ConcurrentException getTypedException(Exception e) {
|
||||
return new ConcurrentException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -97,6 +97,142 @@ public class MultiBackgroundInitializer
|
|||
extends
|
||||
BackgroundInitializer<MultiBackgroundInitializer.MultiBackgroundInitializerResults> {
|
||||
|
||||
/**
|
||||
* A data class for storing the results of the background initialization
|
||||
* performed by {@link MultiBackgroundInitializer}. Objects of this inner
|
||||
* class are returned by {@link MultiBackgroundInitializer#initialize()}.
|
||||
* They allow access to all result objects produced by the
|
||||
* {@link BackgroundInitializer} objects managed by the owning instance. It
|
||||
* is also possible to retrieve status information about single
|
||||
* {@link BackgroundInitializer}s, i.e. whether they completed normally or
|
||||
* caused an exception.
|
||||
*/
|
||||
public static class MultiBackgroundInitializerResults {
|
||||
/** A map with the child initializers. */
|
||||
private final Map<String, BackgroundInitializer<?>> initializers;
|
||||
|
||||
/** A map with the result objects. */
|
||||
private final Map<String, Object> resultObjects;
|
||||
|
||||
/** A map with the exceptions. */
|
||||
private final Map<String, ConcurrentException> exceptions;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link MultiBackgroundInitializerResults}
|
||||
* and initializes it with maps for the {@link BackgroundInitializer}
|
||||
* objects, their result objects and the exceptions thrown by them.
|
||||
*
|
||||
* @param inits the {@link BackgroundInitializer} objects
|
||||
* @param results the result objects
|
||||
* @param excepts the exceptions
|
||||
*/
|
||||
private MultiBackgroundInitializerResults(
|
||||
final Map<String, BackgroundInitializer<?>> inits,
|
||||
final Map<String, Object> results,
|
||||
final Map<String, ConcurrentException> excepts) {
|
||||
initializers = inits;
|
||||
resultObjects = results;
|
||||
exceptions = excepts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether an initializer with the given name exists. If not,
|
||||
* throws an exception. If it exists, the associated child initializer
|
||||
* is returned.
|
||||
*
|
||||
* @param name the name to check
|
||||
* @return the initializer with this name
|
||||
* @throws NoSuchElementException if the name is unknown
|
||||
*/
|
||||
private BackgroundInitializer<?> checkName(final String name) {
|
||||
final BackgroundInitializer<?> init = initializers.get(name);
|
||||
if (init == null) {
|
||||
throw new NoSuchElementException(
|
||||
"No child initializer with name " + name);
|
||||
}
|
||||
|
||||
return init;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ConcurrentException} object that was thrown by the
|
||||
* {@link BackgroundInitializer} with the given name. If this
|
||||
* initializer did not throw an exception, the return value is
|
||||
* <b>null</b>. If the name cannot be resolved, an exception is thrown.
|
||||
*
|
||||
* @param name the name of the {@link BackgroundInitializer}
|
||||
* @return the exception thrown by this initializer
|
||||
* @throws NoSuchElementException if the name cannot be resolved
|
||||
*/
|
||||
public ConcurrentException getException(final String name) {
|
||||
checkName(name);
|
||||
return exceptions.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link BackgroundInitializer} with the given name. If the
|
||||
* name cannot be resolved, an exception is thrown.
|
||||
*
|
||||
* @param name the name of the {@link BackgroundInitializer}
|
||||
* @return the {@link BackgroundInitializer} with this name
|
||||
* @throws NoSuchElementException if the name cannot be resolved
|
||||
*/
|
||||
public BackgroundInitializer<?> getInitializer(final String name) {
|
||||
return checkName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result object produced by the {@code
|
||||
* BackgroundInitializer} with the given name. This is the object
|
||||
* returned by the initializer's {@code initialize()} method. If this
|
||||
* {@link BackgroundInitializer} caused an exception, <b>null</b> is
|
||||
* returned. If the name cannot be resolved, an exception is thrown.
|
||||
*
|
||||
* @param name the name of the {@link BackgroundInitializer}
|
||||
* @return the result object produced by this {@code
|
||||
* BackgroundInitializer}
|
||||
* @throws NoSuchElementException if the name cannot be resolved
|
||||
*/
|
||||
public Object getResultObject(final String name) {
|
||||
checkName(name);
|
||||
return resultObjects.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set with the names of all {@link BackgroundInitializer}
|
||||
* objects managed by the {@link MultiBackgroundInitializer}.
|
||||
*
|
||||
* @return an (unmodifiable) set with the names of the managed {@code
|
||||
* BackgroundInitializer} objects
|
||||
*/
|
||||
public Set<String> initializerNames() {
|
||||
return Collections.unmodifiableSet(initializers.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a flag whether the {@link BackgroundInitializer} with the
|
||||
* given name caused an exception.
|
||||
*
|
||||
* @param name the name of the {@link BackgroundInitializer}
|
||||
* @return a flag whether this initializer caused an exception
|
||||
* @throws NoSuchElementException if the name cannot be resolved
|
||||
*/
|
||||
public boolean isException(final String name) {
|
||||
checkName(name);
|
||||
return exceptions.containsKey(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a flag whether the whole initialization was successful. This
|
||||
* is the case if no child initializer has thrown an exception.
|
||||
*
|
||||
* @return a flag whether the initialization was successful
|
||||
*/
|
||||
public boolean isSuccessful() {
|
||||
return exceptions.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
/** A map with the child initializers. */
|
||||
private final Map<String, BackgroundInitializer<?>> childInitializers = new HashMap<>();
|
||||
|
||||
|
@ -142,6 +278,39 @@ public class MultiBackgroundInitializer
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the closer of all child {@code BackgroundInitializer} objects
|
||||
*
|
||||
* @throws ConcurrentException throws an ConcurrentException that will have all other exceptions as suppressed exceptions. ConcurrentException thrown by children will be unwrapped.
|
||||
* @since 3.14.0
|
||||
*/
|
||||
@Override
|
||||
public void close() throws ConcurrentException {
|
||||
ConcurrentException exception = null;
|
||||
|
||||
for (BackgroundInitializer<?> child : childInitializers.values()) {
|
||||
try {
|
||||
child.close();
|
||||
} catch (Exception e) {
|
||||
if (exception == null) {
|
||||
exception = new ConcurrentException();
|
||||
}
|
||||
|
||||
if (e instanceof ConcurrentException) {
|
||||
// Because ConcurrentException is only created by classes in this package
|
||||
// we can safely unwrap it.
|
||||
exception.addSuppressed(e.getCause());
|
||||
} else {
|
||||
exception.addSuppressed(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of tasks needed for executing all child {@code
|
||||
* BackgroundInitializer} objects in parallel. This implementation sums up
|
||||
|
@ -214,173 +383,4 @@ public class MultiBackgroundInitializer
|
|||
|
||||
return childInitializers.values().stream().allMatch(BackgroundInitializer::isInitialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the closer of all child {@code BackgroundInitializer} objects
|
||||
*
|
||||
* @throws ConcurrentException throws an ConcurrentException that will have all other exceptions as suppressed exceptions. ConcurrentException thrown by children will be unwrapped.
|
||||
* @since 3.14.0
|
||||
*/
|
||||
@Override
|
||||
public void close() throws ConcurrentException {
|
||||
ConcurrentException exception = null;
|
||||
|
||||
for (BackgroundInitializer<?> child : childInitializers.values()) {
|
||||
try {
|
||||
child.close();
|
||||
} catch (Exception e) {
|
||||
if (exception == null) {
|
||||
exception = new ConcurrentException();
|
||||
}
|
||||
|
||||
if (e instanceof ConcurrentException) {
|
||||
// Because ConcurrentException is only created by classes in this package
|
||||
// we can safely unwrap it.
|
||||
exception.addSuppressed(e.getCause());
|
||||
} else {
|
||||
exception.addSuppressed(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data class for storing the results of the background initialization
|
||||
* performed by {@link MultiBackgroundInitializer}. Objects of this inner
|
||||
* class are returned by {@link MultiBackgroundInitializer#initialize()}.
|
||||
* They allow access to all result objects produced by the
|
||||
* {@link BackgroundInitializer} objects managed by the owning instance. It
|
||||
* is also possible to retrieve status information about single
|
||||
* {@link BackgroundInitializer}s, i.e. whether they completed normally or
|
||||
* caused an exception.
|
||||
*/
|
||||
public static class MultiBackgroundInitializerResults {
|
||||
/** A map with the child initializers. */
|
||||
private final Map<String, BackgroundInitializer<?>> initializers;
|
||||
|
||||
/** A map with the result objects. */
|
||||
private final Map<String, Object> resultObjects;
|
||||
|
||||
/** A map with the exceptions. */
|
||||
private final Map<String, ConcurrentException> exceptions;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link MultiBackgroundInitializerResults}
|
||||
* and initializes it with maps for the {@link BackgroundInitializer}
|
||||
* objects, their result objects and the exceptions thrown by them.
|
||||
*
|
||||
* @param inits the {@link BackgroundInitializer} objects
|
||||
* @param results the result objects
|
||||
* @param excepts the exceptions
|
||||
*/
|
||||
private MultiBackgroundInitializerResults(
|
||||
final Map<String, BackgroundInitializer<?>> inits,
|
||||
final Map<String, Object> results,
|
||||
final Map<String, ConcurrentException> excepts) {
|
||||
initializers = inits;
|
||||
resultObjects = results;
|
||||
exceptions = excepts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link BackgroundInitializer} with the given name. If the
|
||||
* name cannot be resolved, an exception is thrown.
|
||||
*
|
||||
* @param name the name of the {@link BackgroundInitializer}
|
||||
* @return the {@link BackgroundInitializer} with this name
|
||||
* @throws NoSuchElementException if the name cannot be resolved
|
||||
*/
|
||||
public BackgroundInitializer<?> getInitializer(final String name) {
|
||||
return checkName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result object produced by the {@code
|
||||
* BackgroundInitializer} with the given name. This is the object
|
||||
* returned by the initializer's {@code initialize()} method. If this
|
||||
* {@link BackgroundInitializer} caused an exception, <b>null</b> is
|
||||
* returned. If the name cannot be resolved, an exception is thrown.
|
||||
*
|
||||
* @param name the name of the {@link BackgroundInitializer}
|
||||
* @return the result object produced by this {@code
|
||||
* BackgroundInitializer}
|
||||
* @throws NoSuchElementException if the name cannot be resolved
|
||||
*/
|
||||
public Object getResultObject(final String name) {
|
||||
checkName(name);
|
||||
return resultObjects.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a flag whether the {@link BackgroundInitializer} with the
|
||||
* given name caused an exception.
|
||||
*
|
||||
* @param name the name of the {@link BackgroundInitializer}
|
||||
* @return a flag whether this initializer caused an exception
|
||||
* @throws NoSuchElementException if the name cannot be resolved
|
||||
*/
|
||||
public boolean isException(final String name) {
|
||||
checkName(name);
|
||||
return exceptions.containsKey(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ConcurrentException} object that was thrown by the
|
||||
* {@link BackgroundInitializer} with the given name. If this
|
||||
* initializer did not throw an exception, the return value is
|
||||
* <b>null</b>. If the name cannot be resolved, an exception is thrown.
|
||||
*
|
||||
* @param name the name of the {@link BackgroundInitializer}
|
||||
* @return the exception thrown by this initializer
|
||||
* @throws NoSuchElementException if the name cannot be resolved
|
||||
*/
|
||||
public ConcurrentException getException(final String name) {
|
||||
checkName(name);
|
||||
return exceptions.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set with the names of all {@link BackgroundInitializer}
|
||||
* objects managed by the {@link MultiBackgroundInitializer}.
|
||||
*
|
||||
* @return an (unmodifiable) set with the names of the managed {@code
|
||||
* BackgroundInitializer} objects
|
||||
*/
|
||||
public Set<String> initializerNames() {
|
||||
return Collections.unmodifiableSet(initializers.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a flag whether the whole initialization was successful. This
|
||||
* is the case if no child initializer has thrown an exception.
|
||||
*
|
||||
* @return a flag whether the initialization was successful
|
||||
*/
|
||||
public boolean isSuccessful() {
|
||||
return exceptions.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether an initializer with the given name exists. If not,
|
||||
* throws an exception. If it exists, the associated child initializer
|
||||
* is returned.
|
||||
*
|
||||
* @param name the name to check
|
||||
* @return the initializer with this name
|
||||
* @throws NoSuchElementException if the name is unknown
|
||||
*/
|
||||
private BackgroundInitializer<?> checkName(final String name) {
|
||||
final BackgroundInitializer<?> init = initializers.get(name);
|
||||
if (init == null) {
|
||||
throw new NoSuchElementException(
|
||||
"No child initializer with name " + name);
|
||||
}
|
||||
|
||||
return init;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,15 +75,6 @@ public class ThresholdCircuitBreaker extends AbstractCircuitBreaker<Long> {
|
|||
this.threshold = threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the threshold.
|
||||
*
|
||||
* @return the threshold
|
||||
*/
|
||||
public long getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
@ -103,6 +94,15 @@ public class ThresholdCircuitBreaker extends AbstractCircuitBreaker<Long> {
|
|||
this.used.set(INITIAL_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the threshold.
|
||||
*
|
||||
* @return the threshold
|
||||
*/
|
||||
public long getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
|
|
@ -230,63 +230,6 @@ public class TimedSemaphore {
|
|||
setLimit(limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the limit enforced by this semaphore. The limit determines how
|
||||
* many invocations of {@link #acquire()} are allowed within the monitored
|
||||
* period.
|
||||
*
|
||||
* @return the limit
|
||||
*/
|
||||
public final synchronized int getLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the limit. This is the number of times the {@link #acquire()} method
|
||||
* can be called within the time period specified. If this limit is reached,
|
||||
* further invocations of {@link #acquire()} will block. Setting the limit
|
||||
* to a value <= {@link #NO_LIMIT} will cause the limit to be disabled,
|
||||
* i.e. an arbitrary number of{@link #acquire()} invocations is allowed in
|
||||
* the time period.
|
||||
*
|
||||
* @param limit the limit
|
||||
*/
|
||||
public final synchronized void setLimit(final int limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a shutdown. After that the object cannot be used anymore.
|
||||
* This method can be invoked an arbitrary number of times. All invocations
|
||||
* after the first one do not have any effect.
|
||||
*/
|
||||
public synchronized void shutdown() {
|
||||
if (!shutdown) {
|
||||
|
||||
if (ownExecutor) {
|
||||
// if the executor was created by this instance, it has
|
||||
// to be shutdown
|
||||
getExecutorService().shutdownNow();
|
||||
}
|
||||
if (task != null) {
|
||||
task.cancel(false);
|
||||
}
|
||||
|
||||
shutdown = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the {@link #shutdown()} method has been called on this
|
||||
* object. If this method returns <b>true</b>, this instance cannot be used
|
||||
* any longer.
|
||||
*
|
||||
* @return a flag whether a shutdown has been performed
|
||||
*/
|
||||
public synchronized boolean isShutdown() {
|
||||
return shutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires a permit from this semaphore. This method will block if
|
||||
* the limit for the current period has already been reached. If
|
||||
|
@ -311,33 +254,32 @@ public class TimedSemaphore {
|
|||
}
|
||||
|
||||
/**
|
||||
* Tries to acquire a permit from this semaphore. If the limit of this semaphore has
|
||||
* not yet been reached, a permit is acquired, and this method returns
|
||||
* <strong>true</strong>. Otherwise, this method returns immediately with the result
|
||||
* <strong>false</strong>.
|
||||
* Internal helper method for acquiring a permit. This method checks whether currently
|
||||
* a permit can be acquired and - if so - increases the internal counter. The return
|
||||
* value indicates whether a permit could be acquired. This method must be called with
|
||||
* the lock of this object held.
|
||||
*
|
||||
* @return <strong>true</strong> if a permit could be acquired; <strong>false</strong>
|
||||
* otherwise
|
||||
* @throws IllegalStateException if this semaphore is already shut down
|
||||
* @since 3.5
|
||||
* @return a flag whether a permit could be acquired
|
||||
*/
|
||||
public synchronized boolean tryAcquire() {
|
||||
prepareAcquire();
|
||||
return acquirePermit();
|
||||
private boolean acquirePermit() {
|
||||
if (getLimit() <= NO_LIMIT || acquireCount < getLimit()) {
|
||||
acquireCount++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of (successful) acquire invocations during the last
|
||||
* period. This is the number of times the {@link #acquire()} method was
|
||||
* called without blocking. This can be useful for testing or debugging
|
||||
* purposes or to determine a meaningful threshold value. If a limit is set,
|
||||
* the value returned by this method won't be greater than this limit.
|
||||
*
|
||||
* @return the number of non-blocking invocations of the {@link #acquire()}
|
||||
* method
|
||||
* The current time period is finished. This method is called by the timer
|
||||
* used internally to monitor the time period. It resets the counter and
|
||||
* releases the threads waiting for this barrier.
|
||||
*/
|
||||
public synchronized int getLastAcquiresPerPeriod() {
|
||||
return lastCallsPerPeriod;
|
||||
synchronized void endOfPeriod() {
|
||||
lastCallsPerPeriod = acquireCount;
|
||||
totalAcquireCount += acquireCount;
|
||||
periodCount++;
|
||||
acquireCount = 0;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -379,6 +321,40 @@ public class TimedSemaphore {
|
|||
/ (double) periodCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the executor service used by this instance.
|
||||
*
|
||||
* @return the executor service
|
||||
*/
|
||||
protected ScheduledExecutorService getExecutorService() {
|
||||
return executorService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of (successful) acquire invocations during the last
|
||||
* period. This is the number of times the {@link #acquire()} method was
|
||||
* called without blocking. This can be useful for testing or debugging
|
||||
* purposes or to determine a meaningful threshold value. If a limit is set,
|
||||
* the value returned by this method won't be greater than this limit.
|
||||
*
|
||||
* @return the number of non-blocking invocations of the {@link #acquire()}
|
||||
* method
|
||||
*/
|
||||
public synchronized int getLastAcquiresPerPeriod() {
|
||||
return lastCallsPerPeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the limit enforced by this semaphore. The limit determines how
|
||||
* many invocations of {@link #acquire()} are allowed within the monitored
|
||||
* period.
|
||||
*
|
||||
* @return the limit
|
||||
*/
|
||||
public final synchronized int getLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time period. This is the time monitored by this semaphore.
|
||||
* Only a given number of invocations of the {@link #acquire()} method is
|
||||
|
@ -400,36 +376,14 @@ public class TimedSemaphore {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the executor service used by this instance.
|
||||
* Tests whether the {@link #shutdown()} method has been called on this
|
||||
* object. If this method returns <b>true</b>, this instance cannot be used
|
||||
* any longer.
|
||||
*
|
||||
* @return the executor service
|
||||
* @return a flag whether a shutdown has been performed
|
||||
*/
|
||||
protected ScheduledExecutorService getExecutorService() {
|
||||
return executorService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the timer. This method is called when {@link #acquire()} is called
|
||||
* for the first time. It schedules a task to be executed at fixed rate to
|
||||
* monitor the time period specified.
|
||||
*
|
||||
* @return a future object representing the task scheduled
|
||||
*/
|
||||
protected ScheduledFuture<?> startTimer() {
|
||||
return getExecutorService().scheduleAtFixedRate(this::endOfPeriod, getPeriod(), getPeriod(), getUnit());
|
||||
}
|
||||
|
||||
/**
|
||||
* The current time period is finished. This method is called by the timer
|
||||
* used internally to monitor the time period. It resets the counter and
|
||||
* releases the threads waiting for this barrier.
|
||||
*/
|
||||
synchronized void endOfPeriod() {
|
||||
lastCallsPerPeriod = acquireCount;
|
||||
totalAcquireCount += acquireCount;
|
||||
periodCount++;
|
||||
acquireCount = 0;
|
||||
notifyAll();
|
||||
public synchronized boolean isShutdown() {
|
||||
return shutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -447,18 +401,64 @@ public class TimedSemaphore {
|
|||
}
|
||||
|
||||
/**
|
||||
* Internal helper method for acquiring a permit. This method checks whether currently
|
||||
* a permit can be acquired and - if so - increases the internal counter. The return
|
||||
* value indicates whether a permit could be acquired. This method must be called with
|
||||
* the lock of this object held.
|
||||
* Sets the limit. This is the number of times the {@link #acquire()} method
|
||||
* can be called within the time period specified. If this limit is reached,
|
||||
* further invocations of {@link #acquire()} will block. Setting the limit
|
||||
* to a value <= {@link #NO_LIMIT} will cause the limit to be disabled,
|
||||
* i.e. an arbitrary number of{@link #acquire()} invocations is allowed in
|
||||
* the time period.
|
||||
*
|
||||
* @return a flag whether a permit could be acquired
|
||||
* @param limit the limit
|
||||
*/
|
||||
private boolean acquirePermit() {
|
||||
if (getLimit() <= NO_LIMIT || acquireCount < getLimit()) {
|
||||
acquireCount++;
|
||||
return true;
|
||||
public final synchronized void setLimit(final int limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a shutdown. After that the object cannot be used anymore.
|
||||
* This method can be invoked an arbitrary number of times. All invocations
|
||||
* after the first one do not have any effect.
|
||||
*/
|
||||
public synchronized void shutdown() {
|
||||
if (!shutdown) {
|
||||
|
||||
if (ownExecutor) {
|
||||
// if the executor was created by this instance, it has
|
||||
// to be shutdown
|
||||
getExecutorService().shutdownNow();
|
||||
}
|
||||
if (task != null) {
|
||||
task.cancel(false);
|
||||
}
|
||||
|
||||
shutdown = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the timer. This method is called when {@link #acquire()} is called
|
||||
* for the first time. It schedules a task to be executed at fixed rate to
|
||||
* monitor the time period specified.
|
||||
*
|
||||
* @return a future object representing the task scheduled
|
||||
*/
|
||||
protected ScheduledFuture<?> startTimer() {
|
||||
return getExecutorService().scheduleAtFixedRate(this::endOfPeriod, getPeriod(), getPeriod(), getUnit());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to acquire a permit from this semaphore. If the limit of this semaphore has
|
||||
* not yet been reached, a permit is acquired, and this method returns
|
||||
* <strong>true</strong>. Otherwise, this method returns immediately with the result
|
||||
* <strong>false</strong>.
|
||||
*
|
||||
* @return <strong>true</strong> if a permit could be acquired; <strong>false</strong>
|
||||
* otherwise
|
||||
* @throws IllegalStateException if this semaphore is already shut down
|
||||
* @since 3.5
|
||||
*/
|
||||
public synchronized boolean tryAcquire() {
|
||||
prepareAcquire();
|
||||
return acquirePermit();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,9 +69,55 @@ import org.apache.commons.lang3.Validate;
|
|||
*/
|
||||
public class EventListenerSupport<L> implements Serializable {
|
||||
|
||||
/**
|
||||
* An invocation handler used to dispatch the event(s) to all the listeners.
|
||||
*/
|
||||
protected class ProxyInvocationHandler implements InvocationHandler {
|
||||
|
||||
/**
|
||||
* Propagates the method call to all registered listeners in place of the proxy listener object.
|
||||
*
|
||||
* @param unusedProxy the proxy object representing a listener on which the invocation was called; not used
|
||||
* @param method the listener method that will be called on all of the listeners.
|
||||
* @param args event arguments to propagate to the listeners.
|
||||
* @return the result of the method call
|
||||
* @throws InvocationTargetException if an error occurs
|
||||
* @throws IllegalArgumentException if an error occurs
|
||||
* @throws IllegalAccessException if an error occurs
|
||||
*/
|
||||
@Override
|
||||
public Object invoke(final Object unusedProxy, final Method method, final Object[] args)
|
||||
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||
for (final L listener : listeners) {
|
||||
method.invoke(listener, args);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Serialization version */
|
||||
private static final long serialVersionUID = 3593265990380473632L;
|
||||
|
||||
/**
|
||||
* Creates an EventListenerSupport object which supports the specified
|
||||
* listener type.
|
||||
*
|
||||
* @param <T> the type of the listener interface
|
||||
* @param listenerInterface the type of listener interface that will receive
|
||||
* events posted using this class.
|
||||
*
|
||||
* @return an EventListenerSupport object which supports the specified
|
||||
* listener type.
|
||||
*
|
||||
* @throws NullPointerException if {@code listenerInterface} is
|
||||
* {@code null}.
|
||||
* @throws IllegalArgumentException if {@code listenerInterface} is
|
||||
* not an interface.
|
||||
*/
|
||||
public static <T> EventListenerSupport<T> create(final Class<T> listenerInterface) {
|
||||
return new EventListenerSupport<>(listenerInterface);
|
||||
}
|
||||
|
||||
/**
|
||||
* The list used to hold the registered listeners. This list is
|
||||
* intentionally a thread-safe copy-on-write-array so that traversals over
|
||||
|
@ -91,23 +137,10 @@ public class EventListenerSupport<L> implements Serializable {
|
|||
private transient L[] prototypeArray;
|
||||
|
||||
/**
|
||||
* Creates an EventListenerSupport object which supports the specified
|
||||
* listener type.
|
||||
*
|
||||
* @param <T> the type of the listener interface
|
||||
* @param listenerInterface the type of listener interface that will receive
|
||||
* events posted using this class.
|
||||
*
|
||||
* @return an EventListenerSupport object which supports the specified
|
||||
* listener type.
|
||||
*
|
||||
* @throws NullPointerException if {@code listenerInterface} is
|
||||
* {@code null}.
|
||||
* @throws IllegalArgumentException if {@code listenerInterface} is
|
||||
* not an interface.
|
||||
* Create a new EventListenerSupport instance.
|
||||
* Serialization-friendly constructor.
|
||||
*/
|
||||
public static <T> EventListenerSupport<T> create(final Class<T> listenerInterface) {
|
||||
return new EventListenerSupport<>(listenerInterface);
|
||||
private EventListenerSupport() {
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -148,25 +181,6 @@ public class EventListenerSupport<L> implements Serializable {
|
|||
initializeTransientFields(listenerInterface, classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new EventListenerSupport instance.
|
||||
* Serialization-friendly constructor.
|
||||
*/
|
||||
private EventListenerSupport() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a proxy object which can be used to call listener methods on all
|
||||
* of the registered event listeners. All calls made to this proxy will be
|
||||
* forwarded to all registered listeners.
|
||||
*
|
||||
* @return a proxy object which can be used to call listener methods on all
|
||||
* of the registered event listeners
|
||||
*/
|
||||
public L fire() {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
//**********************************************************************************************************************
|
||||
// Other Methods
|
||||
//**********************************************************************************************************************
|
||||
|
@ -201,6 +215,37 @@ public class EventListenerSupport<L> implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link InvocationHandler} responsible for broadcasting calls
|
||||
* to the managed listeners. Subclasses can override to provide custom behavior.
|
||||
* @return ProxyInvocationHandler
|
||||
*/
|
||||
protected InvocationHandler createInvocationHandler() {
|
||||
return new ProxyInvocationHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the proxy object.
|
||||
* @param listenerInterface the class of the listener interface
|
||||
* @param classLoader the class loader to be used
|
||||
*/
|
||||
private void createProxy(final Class<L> listenerInterface, final ClassLoader classLoader) {
|
||||
proxy = listenerInterface.cast(Proxy.newProxyInstance(classLoader,
|
||||
new Class[] { listenerInterface }, createInvocationHandler()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a proxy object which can be used to call listener methods on all
|
||||
* of the registered event listeners. All calls made to this proxy will be
|
||||
* forwarded to all registered listeners.
|
||||
*
|
||||
* @return a proxy object which can be used to call listener methods on all
|
||||
* of the registered event listeners
|
||||
*/
|
||||
public L fire() {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of registered listeners.
|
||||
*
|
||||
|
@ -210,6 +255,44 @@ public class EventListenerSupport<L> implements Serializable {
|
|||
return listeners.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array containing the currently registered listeners.
|
||||
* Modification to this array's elements will have no effect on the
|
||||
* {@link EventListenerSupport} instance.
|
||||
* @return L[]
|
||||
*/
|
||||
public L[] getListeners() {
|
||||
return listeners.toArray(prototypeArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize transient fields.
|
||||
* @param listenerInterface the class of the listener interface
|
||||
* @param classLoader the class loader to be used
|
||||
*/
|
||||
private void initializeTransientFields(final Class<L> listenerInterface, final ClassLoader classLoader) {
|
||||
// Will throw CCE here if not correct
|
||||
this.prototypeArray = ArrayUtils.newInstance(listenerInterface, 0);
|
||||
createProxy(listenerInterface, classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize.
|
||||
* @param objectInputStream the input stream
|
||||
* @throws IOException if an IO error occurs
|
||||
* @throws ClassNotFoundException if the class cannot be resolved
|
||||
*/
|
||||
private void readObject(final ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
||||
@SuppressWarnings("unchecked") // Will throw CCE here if not correct
|
||||
final L[] srcListeners = (L[]) objectInputStream.readObject();
|
||||
|
||||
this.listeners = new CopyOnWriteArrayList<>(srcListeners);
|
||||
|
||||
final Class<L> listenerInterface = ArrayUtils.getComponentType(srcListeners);
|
||||
|
||||
initializeTransientFields(listenerInterface, Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters an event listener.
|
||||
*
|
||||
|
@ -223,16 +306,6 @@ public class EventListenerSupport<L> implements Serializable {
|
|||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array containing the currently registered listeners.
|
||||
* Modification to this array's elements will have no effect on the
|
||||
* {@link EventListenerSupport} instance.
|
||||
* @return L[]
|
||||
*/
|
||||
public L[] getListeners() {
|
||||
return listeners.toArray(prototypeArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize.
|
||||
* @param objectOutputStream the output stream
|
||||
|
@ -258,77 +331,4 @@ public class EventListenerSupport<L> implements Serializable {
|
|||
*/
|
||||
objectOutputStream.writeObject(serializableListeners.toArray(prototypeArray));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize.
|
||||
* @param objectInputStream the input stream
|
||||
* @throws IOException if an IO error occurs
|
||||
* @throws ClassNotFoundException if the class cannot be resolved
|
||||
*/
|
||||
private void readObject(final ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
||||
@SuppressWarnings("unchecked") // Will throw CCE here if not correct
|
||||
final L[] srcListeners = (L[]) objectInputStream.readObject();
|
||||
|
||||
this.listeners = new CopyOnWriteArrayList<>(srcListeners);
|
||||
|
||||
final Class<L> listenerInterface = ArrayUtils.getComponentType(srcListeners);
|
||||
|
||||
initializeTransientFields(listenerInterface, Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize transient fields.
|
||||
* @param listenerInterface the class of the listener interface
|
||||
* @param classLoader the class loader to be used
|
||||
*/
|
||||
private void initializeTransientFields(final Class<L> listenerInterface, final ClassLoader classLoader) {
|
||||
// Will throw CCE here if not correct
|
||||
this.prototypeArray = ArrayUtils.newInstance(listenerInterface, 0);
|
||||
createProxy(listenerInterface, classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the proxy object.
|
||||
* @param listenerInterface the class of the listener interface
|
||||
* @param classLoader the class loader to be used
|
||||
*/
|
||||
private void createProxy(final Class<L> listenerInterface, final ClassLoader classLoader) {
|
||||
proxy = listenerInterface.cast(Proxy.newProxyInstance(classLoader,
|
||||
new Class[] { listenerInterface }, createInvocationHandler()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link InvocationHandler} responsible for broadcasting calls
|
||||
* to the managed listeners. Subclasses can override to provide custom behavior.
|
||||
* @return ProxyInvocationHandler
|
||||
*/
|
||||
protected InvocationHandler createInvocationHandler() {
|
||||
return new ProxyInvocationHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* An invocation handler used to dispatch the event(s) to all the listeners.
|
||||
*/
|
||||
protected class ProxyInvocationHandler implements InvocationHandler {
|
||||
|
||||
/**
|
||||
* Propagates the method call to all registered listeners in place of the proxy listener object.
|
||||
*
|
||||
* @param unusedProxy the proxy object representing a listener on which the invocation was called; not used
|
||||
* @param method the listener method that will be called on all of the listeners.
|
||||
* @param args event arguments to propagate to the listeners.
|
||||
* @return the result of the method call
|
||||
* @throws InvocationTargetException if an error occurs
|
||||
* @throws IllegalArgumentException if an error occurs
|
||||
* @throws IllegalAccessException if an error occurs
|
||||
*/
|
||||
@Override
|
||||
public Object invoke(final Object unusedProxy, final Method method, final Object[] args)
|
||||
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||
for (final L listener : listeners) {
|
||||
method.invoke(listener, args);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,55 @@ import org.apache.commons.lang3.reflect.MethodUtils;
|
|||
*/
|
||||
public class EventUtils {
|
||||
|
||||
private static final class EventBindingInvocationHandler implements InvocationHandler {
|
||||
private final Object target;
|
||||
private final String methodName;
|
||||
private final Set<String> eventTypes;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link EventBindingInvocationHandler}.
|
||||
*
|
||||
* @param target the target object for method invocations
|
||||
* @param methodName the name of the method to be invoked
|
||||
* @param eventTypes the names of the supported event types
|
||||
*/
|
||||
EventBindingInvocationHandler(final Object target, final String methodName, final String[] eventTypes) {
|
||||
this.target = target;
|
||||
this.methodName = methodName;
|
||||
this.eventTypes = new HashSet<>(Arrays.asList(eventTypes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a method for the passed in parameters can be found.
|
||||
*
|
||||
* @param method the listener method invoked
|
||||
* @return a flag whether the parameters could be matched
|
||||
*/
|
||||
private boolean hasMatchingParametersMethod(final Method method) {
|
||||
return MethodUtils.getAccessibleMethod(target.getClass(), methodName, method.getParameterTypes()) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a method invocation on the proxy object.
|
||||
*
|
||||
* @param proxy the proxy instance
|
||||
* @param method the method to be invoked
|
||||
* @param parameters the parameters for the method invocation
|
||||
* @return the result of the method call
|
||||
* @throws Throwable if an error occurs
|
||||
*/
|
||||
@Override
|
||||
public Object invoke(final Object proxy, final Method method, final Object[] parameters) throws Throwable {
|
||||
if (eventTypes.isEmpty() || eventTypes.contains(method.getName())) {
|
||||
if (hasMatchingParametersMethod(method)) {
|
||||
return MethodUtils.invokeMethod(target, methodName, parameters);
|
||||
}
|
||||
return MethodUtils.invokeMethod(target, methodName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an event listener to the specified source. This looks for an "add" method corresponding to the event
|
||||
* type (addActionListener, for example).
|
||||
|
@ -77,53 +126,4 @@ public class EventUtils {
|
|||
new Class[] { listenerType }, new EventBindingInvocationHandler(target, methodName, eventTypes)));
|
||||
addEventListener(eventSource, listenerType, listener);
|
||||
}
|
||||
|
||||
private static final class EventBindingInvocationHandler implements InvocationHandler {
|
||||
private final Object target;
|
||||
private final String methodName;
|
||||
private final Set<String> eventTypes;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link EventBindingInvocationHandler}.
|
||||
*
|
||||
* @param target the target object for method invocations
|
||||
* @param methodName the name of the method to be invoked
|
||||
* @param eventTypes the names of the supported event types
|
||||
*/
|
||||
EventBindingInvocationHandler(final Object target, final String methodName, final String[] eventTypes) {
|
||||
this.target = target;
|
||||
this.methodName = methodName;
|
||||
this.eventTypes = new HashSet<>(Arrays.asList(eventTypes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a method invocation on the proxy object.
|
||||
*
|
||||
* @param proxy the proxy instance
|
||||
* @param method the method to be invoked
|
||||
* @param parameters the parameters for the method invocation
|
||||
* @return the result of the method call
|
||||
* @throws Throwable if an error occurs
|
||||
*/
|
||||
@Override
|
||||
public Object invoke(final Object proxy, final Method method, final Object[] parameters) throws Throwable {
|
||||
if (eventTypes.isEmpty() || eventTypes.contains(method.getName())) {
|
||||
if (hasMatchingParametersMethod(method)) {
|
||||
return MethodUtils.invokeMethod(target, methodName, parameters);
|
||||
}
|
||||
return MethodUtils.invokeMethod(target, methodName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a method for the passed in parameters can be found.
|
||||
*
|
||||
* @param method the listener method invoked
|
||||
* @return a flag whether the parameters could be matched
|
||||
*/
|
||||
private boolean hasMatchingParametersMethod(final Method method) {
|
||||
return MethodUtils.getAccessibleMethod(target.getClass(), methodName, method.getParameterTypes()) != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,15 +35,6 @@ public class CloneFailedException extends RuntimeException {
|
|||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a CloneFailedException.
|
||||
*
|
||||
* @param cause cause of the exception
|
||||
*/
|
||||
public CloneFailedException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a CloneFailedException.
|
||||
*
|
||||
|
@ -53,4 +44,13 @@ public class CloneFailedException extends RuntimeException {
|
|||
public CloneFailedException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a CloneFailedException.
|
||||
*
|
||||
* @param cause cause of the exception
|
||||
*/
|
||||
public CloneFailedException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,18 +111,6 @@ public class ContextedException extends Exception implements ExceptionContext {
|
|||
exceptionContext = new DefaultExceptionContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates ContextedException with cause, but without message.
|
||||
* <p>
|
||||
* The context information is stored using a default implementation.
|
||||
*
|
||||
* @param cause the underlying cause of the exception, may be null
|
||||
*/
|
||||
public ContextedException(final Throwable cause) {
|
||||
super(cause);
|
||||
exceptionContext = new DefaultExceptionContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates ContextedException with cause and message.
|
||||
* <p>
|
||||
|
@ -151,6 +139,18 @@ public class ContextedException extends Exception implements ExceptionContext {
|
|||
exceptionContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates ContextedException with cause, but without message.
|
||||
* <p>
|
||||
* The context information is stored using a default implementation.
|
||||
*
|
||||
* @param cause the underlying cause of the exception, may be null
|
||||
*/
|
||||
public ContextedException(final Throwable cause) {
|
||||
super(cause);
|
||||
exceptionContext = new DefaultExceptionContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds information helpful to a developer in diagnosing and correcting the problem.
|
||||
* For the information to be meaningful, the value passed should have a reasonable
|
||||
|
@ -171,22 +171,19 @@ public class ContextedException extends Exception implements ExceptionContext {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets information helpful to a developer in diagnosing and correcting the problem.
|
||||
* For the information to be meaningful, the value passed should have a reasonable
|
||||
* toString() implementation.
|
||||
* Any existing values with the same labels are removed before the new one is added.
|
||||
* <p>
|
||||
* Note: This exception is only serializable if the object added as value is serializable.
|
||||
* </p>
|
||||
*
|
||||
* @param label a textual label associated with information, {@code null} not recommended
|
||||
* @param value information needed to understand exception, may be {@code null}
|
||||
* @return {@code this}, for method chaining, not {@code null}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public ContextedException setContextValue(final String label, final Object value) {
|
||||
exceptionContext.setContextValue(label, value);
|
||||
return this;
|
||||
public List<Pair<String, Object>> getContextEntries() {
|
||||
return this.exceptionContext.getContextEntries();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getContextLabels() {
|
||||
return exceptionContext.getContextLabels();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -209,16 +206,8 @@ public class ContextedException extends Exception implements ExceptionContext {
|
|||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public List<Pair<String, Object>> getContextEntries() {
|
||||
return this.exceptionContext.getContextEntries();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getContextLabels() {
|
||||
return exceptionContext.getContextLabels();
|
||||
public String getFormattedExceptionMessage(final String baseMessage) {
|
||||
return exceptionContext.getFormattedExceptionMessage(baseMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -244,10 +233,21 @@ public class ContextedException extends Exception implements ExceptionContext {
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* Sets information helpful to a developer in diagnosing and correcting the problem.
|
||||
* For the information to be meaningful, the value passed should have a reasonable
|
||||
* toString() implementation.
|
||||
* Any existing values with the same labels are removed before the new one is added.
|
||||
* <p>
|
||||
* Note: This exception is only serializable if the object added as value is serializable.
|
||||
* </p>
|
||||
*
|
||||
* @param label a textual label associated with information, {@code null} not recommended
|
||||
* @param value information needed to understand exception, may be {@code null}
|
||||
* @return {@code this}, for method chaining, not {@code null}
|
||||
*/
|
||||
@Override
|
||||
public String getFormattedExceptionMessage(final String baseMessage) {
|
||||
return exceptionContext.getFormattedExceptionMessage(baseMessage);
|
||||
public ContextedException setContextValue(final String label, final Object value) {
|
||||
exceptionContext.setContextValue(label, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,18 +111,6 @@ public class ContextedRuntimeException extends RuntimeException implements Excep
|
|||
exceptionContext = new DefaultExceptionContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates ContextedRuntimeException with cause, but without message.
|
||||
* <p>
|
||||
* The context information is stored using a default implementation.
|
||||
*
|
||||
* @param cause the underlying cause of the exception, may be null
|
||||
*/
|
||||
public ContextedRuntimeException(final Throwable cause) {
|
||||
super(cause);
|
||||
exceptionContext = new DefaultExceptionContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates ContextedRuntimeException with cause and message.
|
||||
* <p>
|
||||
|
@ -151,6 +139,18 @@ public class ContextedRuntimeException extends RuntimeException implements Excep
|
|||
exceptionContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates ContextedRuntimeException with cause, but without message.
|
||||
* <p>
|
||||
* The context information is stored using a default implementation.
|
||||
*
|
||||
* @param cause the underlying cause of the exception, may be null
|
||||
*/
|
||||
public ContextedRuntimeException(final Throwable cause) {
|
||||
super(cause);
|
||||
exceptionContext = new DefaultExceptionContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds information helpful to a developer in diagnosing and correcting the problem.
|
||||
* For the information to be meaningful, the value passed should have a reasonable
|
||||
|
@ -171,22 +171,19 @@ public class ContextedRuntimeException extends RuntimeException implements Excep
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets information helpful to a developer in diagnosing and correcting the problem.
|
||||
* For the information to be meaningful, the value passed should have a reasonable
|
||||
* toString() implementation.
|
||||
* Any existing values with the same labels are removed before the new one is added.
|
||||
* <p>
|
||||
* Note: This exception is only serializable if the object added as value is serializable.
|
||||
* </p>
|
||||
*
|
||||
* @param label a textual label associated with information, {@code null} not recommended
|
||||
* @param value information needed to understand exception, may be {@code null}
|
||||
* @return {@code this}, for method chaining, not {@code null}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public ContextedRuntimeException setContextValue(final String label, final Object value) {
|
||||
exceptionContext.setContextValue(label, value);
|
||||
return this;
|
||||
public List<Pair<String, Object>> getContextEntries() {
|
||||
return this.exceptionContext.getContextEntries();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getContextLabels() {
|
||||
return exceptionContext.getContextLabels();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -209,16 +206,8 @@ public class ContextedRuntimeException extends RuntimeException implements Excep
|
|||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public List<Pair<String, Object>> getContextEntries() {
|
||||
return this.exceptionContext.getContextEntries();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getContextLabels() {
|
||||
return exceptionContext.getContextLabels();
|
||||
public String getFormattedExceptionMessage(final String baseMessage) {
|
||||
return exceptionContext.getFormattedExceptionMessage(baseMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -244,11 +233,22 @@ public class ContextedRuntimeException extends RuntimeException implements Excep
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* Sets information helpful to a developer in diagnosing and correcting the problem.
|
||||
* For the information to be meaningful, the value passed should have a reasonable
|
||||
* toString() implementation.
|
||||
* Any existing values with the same labels are removed before the new one is added.
|
||||
* <p>
|
||||
* Note: This exception is only serializable if the object added as value is serializable.
|
||||
* </p>
|
||||
*
|
||||
* @param label a textual label associated with information, {@code null} not recommended
|
||||
* @param value information needed to understand exception, may be {@code null}
|
||||
* @return {@code this}, for method chaining, not {@code null}
|
||||
*/
|
||||
@Override
|
||||
public String getFormattedExceptionMessage(final String baseMessage) {
|
||||
return exceptionContext.getFormattedExceptionMessage(baseMessage);
|
||||
public ContextedRuntimeException setContextValue(final String label, final Object value) {
|
||||
exceptionContext.setContextValue(label, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,10 +31,6 @@ public class Consumers {
|
|||
@SuppressWarnings("rawtypes")
|
||||
private static final Consumer NOP = Function.identity()::apply;
|
||||
|
||||
private Consumers() {
|
||||
// No instances.
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the NOP Consumer singleton.
|
||||
*
|
||||
|
@ -46,4 +42,8 @@ public class Consumers {
|
|||
return NOP;
|
||||
}
|
||||
|
||||
private Consumers() {
|
||||
// No instances.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,17 @@ public class Suppliers {
|
|||
@SuppressWarnings("rawtypes")
|
||||
private static Supplier NUL = () -> null;
|
||||
|
||||
/**
|
||||
* Null-safe call to {@link Supplier#get()}.
|
||||
*
|
||||
* @param <T> the type of results supplied by this supplier.
|
||||
* @param supplier the supplier or null.
|
||||
* @return Result of {@link Supplier#get()} or null.
|
||||
*/
|
||||
public static <T> T get(final Supplier<T> supplier) {
|
||||
return supplier == null ? null : supplier.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the singleton supplier that always returns null.
|
||||
* <p>
|
||||
|
@ -50,15 +61,4 @@ public class Suppliers {
|
|||
return NUL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe call to {@link Supplier#get()}.
|
||||
*
|
||||
* @param <T> the type of results supplied by this supplier.
|
||||
* @param supplier the supplier or null.
|
||||
* @return Result of {@link Supplier#get()} or null.
|
||||
*/
|
||||
public static <T> T get(final Supplier<T> supplier) {
|
||||
return supplier == null ? null : supplier.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,16 +39,6 @@ import java.util.function.Function;
|
|||
@FunctionalInterface
|
||||
public interface TriFunction<T, U, V, R> {
|
||||
|
||||
/**
|
||||
* Applies this function to the given arguments.
|
||||
*
|
||||
* @param t the first function argument
|
||||
* @param u the second function argument
|
||||
* @param v the third function argument
|
||||
* @return the function result
|
||||
*/
|
||||
R apply(T t, U u, V v);
|
||||
|
||||
/**
|
||||
* Returns a composed function that first applies this function to its input, and then applies the {@code after}
|
||||
* function to the result. If evaluation of either function throws an exception, it is relayed to the caller of the
|
||||
|
@ -63,4 +53,14 @@ public interface TriFunction<T, U, V, R> {
|
|||
Objects.requireNonNull(after);
|
||||
return (final T t, final U u, final V v) -> after.apply(apply(t, u, v));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies this function to the given arguments.
|
||||
*
|
||||
* @param t the first function argument
|
||||
* @param u the second function argument
|
||||
* @param v the third function argument
|
||||
* @return the function result
|
||||
*/
|
||||
R apply(T t, U u, V v);
|
||||
}
|
||||
|
|
|
@ -92,143 +92,21 @@ public final class Fraction extends Number implements Comparable<Fraction> {
|
|||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* Cached output toString (class is immutable).
|
||||
*/
|
||||
private transient String toString;
|
||||
/**
|
||||
* Cached output toProperString (class is immutable).
|
||||
*/
|
||||
private transient String toProperString;
|
||||
|
||||
/**
|
||||
* Constructs a {@link Fraction} instance with the 2 parts
|
||||
* of a fraction Y/Z.
|
||||
* Add two integers, checking for overflow.
|
||||
*
|
||||
* @param numerator the numerator, for example the three in 'three sevenths'
|
||||
* @param denominator the denominator, for example the seven in 'three sevenths'
|
||||
* @param x an addend
|
||||
* @param y an addend
|
||||
* @return the sum {@code x+y}
|
||||
* @throws ArithmeticException if the result can not be represented as
|
||||
* an int
|
||||
*/
|
||||
private Fraction(final int numerator, final int denominator) {
|
||||
this.numerator = numerator;
|
||||
this.denominator = denominator;
|
||||
private static int addAndCheck(final int x, final int y) {
|
||||
final long s = (long) x + (long) y;
|
||||
if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) {
|
||||
throw new ArithmeticException("overflow: add");
|
||||
}
|
||||
return (int) s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Fraction} instance with the 2 parts
|
||||
* of a fraction Y/Z.
|
||||
*
|
||||
* <p>Any negative signs are resolved to be on the numerator.</p>
|
||||
*
|
||||
* @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 denominator is {@code zero}
|
||||
* or the denominator is {@code negative} and the numerator is {@code Integer#MIN_VALUE}
|
||||
*/
|
||||
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 {@link Fraction} instance with the 3 parts
|
||||
* of a fraction X Y/Z.
|
||||
*
|
||||
* <p>The negative sign must be passed in on the whole number part.</p>
|
||||
*
|
||||
* @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 denominator is {@code zero}
|
||||
* @throws ArithmeticException if the denominator is negative
|
||||
* @throws ArithmeticException if the numerator is negative
|
||||
* @throws ArithmeticException if the resulting numerator exceeds
|
||||
* {@code Integer.MAX_VALUE}
|
||||
*/
|
||||
public static Fraction getFraction(final int whole, final int numerator, final 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");
|
||||
}
|
||||
final 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 {@link Fraction} instance with the 2 parts
|
||||
* of a fraction Y/Z.
|
||||
*
|
||||
* <p>For example, if the input parameters represent 2/4, then the created
|
||||
* fraction will be 1/2.</p>
|
||||
*
|
||||
* <p>Any negative signs are resolved to be on the numerator.</p>
|
||||
*
|
||||
* @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 {@code 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.
|
||||
final int gcd = greatestCommonDivisor(numerator, denominator);
|
||||
numerator /= gcd;
|
||||
denominator /= gcd;
|
||||
return new Fraction(numerator, denominator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Fraction} instance from a {@code double} value.
|
||||
*
|
||||
|
@ -291,6 +169,68 @@ public final class Fraction extends Number implements Comparable<Fraction> {
|
|||
return getReducedFraction((numer0 + wholeNumber * denom0) * sign, denom0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Fraction} instance with the 2 parts
|
||||
* of a fraction Y/Z.
|
||||
*
|
||||
* <p>Any negative signs are resolved to be on the numerator.</p>
|
||||
*
|
||||
* @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 denominator is {@code zero}
|
||||
* or the denominator is {@code negative} and the numerator is {@code Integer#MIN_VALUE}
|
||||
*/
|
||||
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 {@link Fraction} instance with the 3 parts
|
||||
* of a fraction X Y/Z.
|
||||
*
|
||||
* <p>The negative sign must be passed in on the whole number part.</p>
|
||||
*
|
||||
* @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 denominator is {@code zero}
|
||||
* @throws ArithmeticException if the denominator is negative
|
||||
* @throws ArithmeticException if the numerator is negative
|
||||
* @throws ArithmeticException if the resulting numerator exceeds
|
||||
* {@code Integer.MAX_VALUE}
|
||||
*/
|
||||
public static Fraction getFraction(final int whole, final int numerator, final 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");
|
||||
}
|
||||
final 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 Fraction from a {@link String}.
|
||||
*
|
||||
|
@ -343,203 +283,43 @@ public final class Fraction extends Number implements Comparable<Fraction> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the numerator part of the fraction.
|
||||
* Creates a reduced {@link Fraction} instance with the 2 parts
|
||||
* of a fraction Y/Z.
|
||||
*
|
||||
* <p>This method may return a value greater than the denominator, an
|
||||
* improper fraction, such as the seven in 7/4.</p>
|
||||
* <p>For example, if the input parameters represent 2/4, then the created
|
||||
* fraction will be 1/2.</p>
|
||||
*
|
||||
* @return the numerator fraction part
|
||||
* <p>Any negative signs are resolved to be on the numerator.</p>
|
||||
*
|
||||
* @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 {@code zero}
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* <p>An improper fraction 7/4 can be resolved into a proper one, 1 3/4.
|
||||
* This method returns the 3 from the proper fraction.</p>
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* <p>An improper fraction 7/4 can be resolved into a proper one, 1 3/4.
|
||||
* This method returns the 1 from the proper fraction.</p>
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* @return the whole fraction part of a proper fraction, that includes the sign
|
||||
*/
|
||||
public int getProperWhole() {
|
||||
return numerator / denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as an {@code int}. This returns the whole number
|
||||
* part of the fraction.
|
||||
*
|
||||
* @return the whole number fraction part
|
||||
*/
|
||||
@Override
|
||||
public int intValue() {
|
||||
return numerator / denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as a {@code long}. This returns the whole number
|
||||
* part of the fraction.
|
||||
*
|
||||
* @return the whole number fraction part
|
||||
*/
|
||||
@Override
|
||||
public long longValue() {
|
||||
return (long) numerator / denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as a {@code float}. This calculates the fraction
|
||||
* as the numerator divided by denominator.
|
||||
*
|
||||
* @return the fraction as a {@code float}
|
||||
*/
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return (float) numerator / (float) denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as a {@code double}. This calculates the fraction
|
||||
* as the numerator divided by denominator.
|
||||
*
|
||||
* @return the fraction as a {@code double}
|
||||
*/
|
||||
@Override
|
||||
public double doubleValue() {
|
||||
return (double) numerator / (double) denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce the fraction to the smallest values for the numerator and
|
||||
* denominator, returning the result.
|
||||
*
|
||||
* <p>For example, if this fraction represents 2/4, then the result
|
||||
* will be 1/2.</p>
|
||||
*
|
||||
* @return a new reduced fraction instance, or this if no simplification possible
|
||||
*/
|
||||
public Fraction reduce() {
|
||||
public static Fraction getReducedFraction(int numerator, int denominator) {
|
||||
if (denominator == 0) {
|
||||
throw new ArithmeticException("The denominator must not be zero");
|
||||
}
|
||||
if (numerator == 0) {
|
||||
return equals(ZERO) ? this : ZERO;
|
||||
return ZERO; // normalize zero.
|
||||
}
|
||||
final int gcd = greatestCommonDivisor(Math.abs(numerator), denominator);
|
||||
if (gcd == 1) {
|
||||
return this;
|
||||
// allow 2^k/-2^31 as a valid fraction (where k>0)
|
||||
if (denominator == Integer.MIN_VALUE && (numerator & 1) == 0) {
|
||||
numerator /= 2;
|
||||
denominator /= 2;
|
||||
}
|
||||
return getFraction(numerator / gcd, denominator / gcd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a fraction that is the inverse (1/fraction) of this one.
|
||||
*
|
||||
* <p>The returned fraction is not reduced.</p>
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
return new Fraction(denominator, numerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a fraction that is the negative (-fraction) of this one.
|
||||
*
|
||||
* <p>The returned fraction is not reduced.</p>
|
||||
*
|
||||
* @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.
|
||||
* <p>More precisely: {@code (fraction >= 0 ? this : -fraction)}</p>
|
||||
*
|
||||
* <p>The returned fraction is not reduced.</p>
|
||||
*
|
||||
* @return {@code 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.
|
||||
*
|
||||
* <p>The returned fraction is in reduced form.</p>
|
||||
*
|
||||
* @param power the power to raise the fraction to
|
||||
* @return {@code this} if the power is one, {@link #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
|
||||
* {@code Integer.MAX_VALUE}
|
||||
*/
|
||||
public Fraction pow(final int power) {
|
||||
if (power == 1) {
|
||||
return this;
|
||||
}
|
||||
if (power == 0) {
|
||||
return ONE;
|
||||
}
|
||||
if (power < 0) {
|
||||
if (power == Integer.MIN_VALUE) { // MIN_VALUE can't be negated.
|
||||
return this.invert().pow(2).pow(-(power / 2));
|
||||
if (denominator < 0) {
|
||||
if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) {
|
||||
throw new ArithmeticException("overflow: can't negate");
|
||||
}
|
||||
return this.invert().pow(-power);
|
||||
numerator = -numerator;
|
||||
denominator = -denominator;
|
||||
}
|
||||
final Fraction f = this.multiplyBy(this);
|
||||
if (power % 2 == 0) { // if even...
|
||||
return f.pow(power / 2);
|
||||
}
|
||||
return f.pow(power / 2).multiplyBy(this);
|
||||
// simplify fraction.
|
||||
final int gcd = greatestCommonDivisor(numerator, denominator);
|
||||
numerator /= gcd;
|
||||
denominator /= gcd;
|
||||
return new Fraction(numerator, denominator);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -644,23 +424,6 @@ public final class Fraction extends Number implements Comparable<Fraction> {
|
|||
return (int) m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add two integers, checking for overflow.
|
||||
*
|
||||
* @param x an addend
|
||||
* @param y an addend
|
||||
* @return the sum {@code x+y}
|
||||
* @throws ArithmeticException if the result can not be represented as
|
||||
* an int
|
||||
*/
|
||||
private static int addAndCheck(final int x, final int y) {
|
||||
final 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.
|
||||
*
|
||||
|
@ -678,6 +441,59 @@ public final class Fraction extends Number implements Comparable<Fraction> {
|
|||
return (int) s;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Cached output toString (class is immutable).
|
||||
*/
|
||||
private transient String toString;
|
||||
|
||||
/**
|
||||
* Cached output toProperString (class is immutable).
|
||||
*/
|
||||
private transient String toProperString;
|
||||
|
||||
/**
|
||||
* Constructs a {@link 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(final int numerator, final int denominator) {
|
||||
this.numerator = numerator;
|
||||
this.denominator = denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a fraction that is the positive equivalent of this one.
|
||||
* <p>More precisely: {@code (fraction >= 0 ? this : -fraction)}</p>
|
||||
*
|
||||
* <p>The returned fraction is not reduced.</p>
|
||||
*
|
||||
* @return {@code 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the value of this fraction to another, returning the result in reduced form.
|
||||
* The algorithm follows Knuth, 4.5.1.
|
||||
|
@ -692,20 +508,6 @@ public final class Fraction extends Number implements Comparable<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 {@code null}
|
||||
* @return a {@link Fraction} instance with the resulting values
|
||||
* @throws NullPointerException if the fraction is {@code null}
|
||||
* @throws ArithmeticException if the resulting numerator or denominator
|
||||
* cannot be represented in an {@code int}.
|
||||
*/
|
||||
public Fraction subtract(final Fraction fraction) {
|
||||
return addSub(fraction, false /* subtract */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement add and subtract using algorithm described in Knuth 4.5.1.
|
||||
*
|
||||
|
@ -754,81 +556,6 @@ public final class Fraction extends Number implements Comparable<Fraction> {
|
|||
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 {@code null}
|
||||
* @return a {@link Fraction} instance with the resulting values
|
||||
* @throws NullPointerException if the fraction is {@code null}
|
||||
* @throws ArithmeticException if the resulting numerator or denominator exceeds
|
||||
* {@code Integer.MAX_VALUE}
|
||||
*/
|
||||
public Fraction multiplyBy(final Fraction fraction) {
|
||||
Objects.requireNonNull(fraction, "fraction");
|
||||
if (numerator == 0 || fraction.numerator == 0) {
|
||||
return ZERO;
|
||||
}
|
||||
// knuth 4.5.1
|
||||
// make sure we don't overflow unless the result *must* overflow.
|
||||
final int d1 = greatestCommonDivisor(numerator, fraction.denominator);
|
||||
final 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 {@code null}
|
||||
* @return a {@link Fraction} instance with the resulting values
|
||||
* @throws NullPointerException if the fraction is {@code null}
|
||||
* @throws ArithmeticException if the fraction to divide by is zero
|
||||
* @throws ArithmeticException if the resulting numerator or denominator exceeds
|
||||
* {@code Integer.MAX_VALUE}
|
||||
*/
|
||||
public Fraction divideBy(final Fraction fraction) {
|
||||
Objects.requireNonNull(fraction, "fraction");
|
||||
if (fraction.numerator == 0) {
|
||||
throw new ArithmeticException("The fraction to divide by must not be zero");
|
||||
}
|
||||
return multiplyBy(fraction.invert());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this fraction to another object to test if they are equal..
|
||||
*
|
||||
* <p>To be equal, both values must be equal. Thus 2/4 is not equal to 1/2.</p>
|
||||
*
|
||||
* @param obj the reference object with which to compare
|
||||
* @return {@code true} if this object is equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Fraction)) {
|
||||
return false;
|
||||
}
|
||||
final 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
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (hashCode == 0) {
|
||||
// hash code update should be atomic.
|
||||
hashCode = 37 * (37 * 17 + getNumerator()) + getDenominator();
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object to another based on size.
|
||||
*
|
||||
|
@ -857,18 +584,276 @@ public final class Fraction extends Number implements Comparable<Fraction> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as a {@link String}.
|
||||
* Divide the value of this fraction by another.
|
||||
*
|
||||
* <p>The format used is '<i>numerator</i>/<i>denominator</i>' always.
|
||||
* @param fraction the fraction to divide by, must not be {@code null}
|
||||
* @return a {@link Fraction} instance with the resulting values
|
||||
* @throws NullPointerException if the fraction is {@code null}
|
||||
* @throws ArithmeticException if the fraction to divide by is zero
|
||||
* @throws ArithmeticException if the resulting numerator or denominator exceeds
|
||||
* {@code Integer.MAX_VALUE}
|
||||
*/
|
||||
public Fraction divideBy(final Fraction fraction) {
|
||||
Objects.requireNonNull(fraction, "fraction");
|
||||
if (fraction.numerator == 0) {
|
||||
throw new ArithmeticException("The fraction to divide by must not be zero");
|
||||
}
|
||||
return multiplyBy(fraction.invert());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as a {@code double}. This calculates the fraction
|
||||
* as the numerator divided by denominator.
|
||||
*
|
||||
* @return a {@link String} form of the fraction
|
||||
* @return the fraction as a {@code double}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
if (toString == null) {
|
||||
toString = getNumerator() + "/" + getDenominator();
|
||||
public double doubleValue() {
|
||||
return (double) numerator / (double) denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this fraction to another object to test if they are equal..
|
||||
*
|
||||
* <p>To be equal, both values must be equal. Thus 2/4 is not equal to 1/2.</p>
|
||||
*
|
||||
* @param obj the reference object with which to compare
|
||||
* @return {@code true} if this object is equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
return toString;
|
||||
if (!(obj instanceof Fraction)) {
|
||||
return false;
|
||||
}
|
||||
final Fraction other = (Fraction) obj;
|
||||
return getNumerator() == other.getNumerator() && getDenominator() == other.getDenominator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as a {@code float}. This calculates the fraction
|
||||
* as the numerator divided by denominator.
|
||||
*
|
||||
* @return the fraction as a {@code float}
|
||||
*/
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return (float) numerator / (float) denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the denominator part of the fraction.
|
||||
*
|
||||
* @return the denominator fraction part
|
||||
*/
|
||||
public int getDenominator() {
|
||||
return denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the numerator part of the fraction.
|
||||
*
|
||||
* <p>This method may return a value greater than the denominator, an
|
||||
* improper fraction, such as the seven in 7/4.</p>
|
||||
*
|
||||
* @return the numerator fraction part
|
||||
*/
|
||||
public int getNumerator() {
|
||||
return numerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the proper numerator, always positive.
|
||||
*
|
||||
* <p>An improper fraction 7/4 can be resolved into a proper one, 1 3/4.
|
||||
* This method returns the 3 from the proper fraction.</p>
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* <p>An improper fraction 7/4 can be resolved into a proper one, 1 3/4.
|
||||
* This method returns the 1 from the proper fraction.</p>
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* @return the whole fraction part of a proper fraction, that includes the sign
|
||||
*/
|
||||
public int getProperWhole() {
|
||||
return numerator / denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a hashCode for the fraction.
|
||||
*
|
||||
* @return a hash code value for this object
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (hashCode == 0) {
|
||||
// hash code update should be atomic.
|
||||
hashCode = 37 * (37 * 17 + getNumerator()) + getDenominator();
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as an {@code int}. This returns the whole number
|
||||
* part of the fraction.
|
||||
*
|
||||
* @return the whole number fraction part
|
||||
*/
|
||||
@Override
|
||||
public int intValue() {
|
||||
return numerator / denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a fraction that is the inverse (1/fraction) of this one.
|
||||
*
|
||||
* <p>The returned fraction is not reduced.</p>
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
return new Fraction(denominator, numerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as a {@code long}. This returns the whole number
|
||||
* part of the fraction.
|
||||
*
|
||||
* @return the whole number fraction part
|
||||
*/
|
||||
@Override
|
||||
public long longValue() {
|
||||
return (long) numerator / denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies the value of this fraction by another, returning the
|
||||
* result in reduced form.
|
||||
*
|
||||
* @param fraction the fraction to multiply by, must not be {@code null}
|
||||
* @return a {@link Fraction} instance with the resulting values
|
||||
* @throws NullPointerException if the fraction is {@code null}
|
||||
* @throws ArithmeticException if the resulting numerator or denominator exceeds
|
||||
* {@code Integer.MAX_VALUE}
|
||||
*/
|
||||
public Fraction multiplyBy(final Fraction fraction) {
|
||||
Objects.requireNonNull(fraction, "fraction");
|
||||
if (numerator == 0 || fraction.numerator == 0) {
|
||||
return ZERO;
|
||||
}
|
||||
// knuth 4.5.1
|
||||
// make sure we don't overflow unless the result *must* overflow.
|
||||
final int d1 = greatestCommonDivisor(numerator, fraction.denominator);
|
||||
final int d2 = greatestCommonDivisor(fraction.numerator, denominator);
|
||||
return getReducedFraction(mulAndCheck(numerator / d1, fraction.numerator / d2),
|
||||
mulPosAndCheck(denominator / d2, fraction.denominator / d1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a fraction that is the negative (-fraction) of this one.
|
||||
*
|
||||
* <p>The returned fraction is not reduced.</p>
|
||||
*
|
||||
* @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 raised to the passed in power.
|
||||
*
|
||||
* <p>The returned fraction is in reduced form.</p>
|
||||
*
|
||||
* @param power the power to raise the fraction to
|
||||
* @return {@code this} if the power is one, {@link #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
|
||||
* {@code Integer.MAX_VALUE}
|
||||
*/
|
||||
public Fraction pow(final int power) {
|
||||
if (power == 1) {
|
||||
return this;
|
||||
}
|
||||
if (power == 0) {
|
||||
return ONE;
|
||||
}
|
||||
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);
|
||||
}
|
||||
final Fraction f = this.multiplyBy(this);
|
||||
if (power % 2 == 0) { // if even...
|
||||
return f.pow(power / 2);
|
||||
}
|
||||
return f.pow(power / 2).multiplyBy(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce the fraction to the smallest values for the numerator and
|
||||
* denominator, returning the result.
|
||||
*
|
||||
* <p>For example, if this fraction represents 2/4, then the result
|
||||
* will be 1/2.</p>
|
||||
*
|
||||
* @return a new reduced fraction instance, or this if no simplification possible
|
||||
*/
|
||||
public Fraction reduce() {
|
||||
if (numerator == 0) {
|
||||
return equals(ZERO) ? this : ZERO;
|
||||
}
|
||||
final int gcd = greatestCommonDivisor(Math.abs(numerator), denominator);
|
||||
if (gcd == 1) {
|
||||
return this;
|
||||
}
|
||||
return getFraction(numerator / gcd, denominator / gcd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {@code null}
|
||||
* @return a {@link Fraction} instance with the resulting values
|
||||
* @throws NullPointerException if the fraction is {@code null}
|
||||
* @throws ArithmeticException if the resulting numerator or denominator
|
||||
* cannot be represented in an {@code int}.
|
||||
*/
|
||||
public Fraction subtract(final Fraction fraction) {
|
||||
return addSub(fraction, false /* subtract */);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -905,4 +890,19 @@ public final class Fraction extends Number implements Comparable<Fraction> {
|
|||
}
|
||||
return toProperString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fraction as a {@link String}.
|
||||
*
|
||||
* <p>The format used is '<i>numerator</i>/<i>denominator</i>' always.
|
||||
*
|
||||
* @return a {@link String} form of the fraction
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
if (toString == null) {
|
||||
toString = getNumerator() + "/" + getDenominator();
|
||||
}
|
||||
return toString;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,116 +30,6 @@ import org.apache.commons.lang3.Validate;
|
|||
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 NullPointerException if {@code array} is {@code null}
|
||||
* @throws IllegalArgumentException if {@code array} is empty
|
||||
* @since 3.4 Changed signature from min(double[]) to min(double...)
|
||||
*/
|
||||
public static double min(final double... array) {
|
||||
Objects.requireNonNull(array, "array");
|
||||
Validate.isTrue(array.length != 0, "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 NullPointerException if {@code array} is {@code null}
|
||||
* @throws IllegalArgumentException if {@code array} is empty
|
||||
* @since 3.4 Changed signature from min(float[]) to min(float...)
|
||||
*/
|
||||
public static float min(final float... array) {
|
||||
Objects.requireNonNull(array, "array");
|
||||
Validate.isTrue(array.length != 0, "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 {@code double} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @param c value 3
|
||||
* @return the smallest of the values
|
||||
*/
|
||||
public static double min(final double a, final double b, final double c) {
|
||||
return min(min(a, b), c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum of two {@code double} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @return the smallest of the values
|
||||
*/
|
||||
public static double min(final double a, final double b) {
|
||||
if (Double.isNaN(a)) {
|
||||
return b;
|
||||
}
|
||||
if (Double.isNaN(b)) {
|
||||
return a;
|
||||
}
|
||||
return Math.min(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum of three {@code float} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @param c value 3
|
||||
* @return the smallest of the values
|
||||
*/
|
||||
public static float min(final float a, final float b, final float c) {
|
||||
return min(min(a, b), c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum of two {@code float} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @return the smallest of the values
|
||||
*/
|
||||
public static float min(final float a, final float b) {
|
||||
if (Float.isNaN(a)) {
|
||||
return b;
|
||||
}
|
||||
if (Float.isNaN(b)) {
|
||||
return a;
|
||||
}
|
||||
return Math.min(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum value in an array.
|
||||
*
|
||||
* @param array an array, must not be null or empty
|
||||
|
@ -161,6 +51,39 @@ public class IEEE754rUtils {
|
|||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum of two {@code double} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @return the largest of the values
|
||||
*/
|
||||
public static double max(final double a, final double b) {
|
||||
if (Double.isNaN(a)) {
|
||||
return b;
|
||||
}
|
||||
if (Double.isNaN(b)) {
|
||||
return a;
|
||||
}
|
||||
return Math.max(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum of three {@code double} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @param c value 3
|
||||
* @return the largest of the values
|
||||
*/
|
||||
public static double max(final double a, final double b, final double c) {
|
||||
return max(max(a, b), c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum value in an array.
|
||||
*
|
||||
|
@ -184,21 +107,7 @@ public class IEEE754rUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum of three {@code double} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @param c value 3
|
||||
* @return the largest of the values
|
||||
*/
|
||||
public static double max(final double a, final double b, final double c) {
|
||||
return max(max(a, b), c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum of two {@code double} values.
|
||||
* Gets the maximum of two {@code float} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
|
@ -206,11 +115,11 @@ public class IEEE754rUtils {
|
|||
* @param b value 2
|
||||
* @return the largest of the values
|
||||
*/
|
||||
public static double max(final double a, final double b) {
|
||||
if (Double.isNaN(a)) {
|
||||
public static float max(final float a, final float b) {
|
||||
if (Float.isNaN(a)) {
|
||||
return b;
|
||||
}
|
||||
if (Double.isNaN(b)) {
|
||||
if (Float.isNaN(b)) {
|
||||
return a;
|
||||
}
|
||||
return Math.max(a, b);
|
||||
|
@ -231,22 +140,113 @@ public class IEEE754rUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum of two {@code float} values.
|
||||
* 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 NullPointerException if {@code array} is {@code null}
|
||||
* @throws IllegalArgumentException if {@code array} is empty
|
||||
* @since 3.4 Changed signature from min(double[]) to min(double...)
|
||||
*/
|
||||
public static double min(final double... array) {
|
||||
Objects.requireNonNull(array, "array");
|
||||
Validate.isTrue(array.length != 0, "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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum of two {@code double} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @return the largest of the values
|
||||
* @return the smallest of the values
|
||||
*/
|
||||
public static float max(final float a, final float b) {
|
||||
public static double min(final double a, final double b) {
|
||||
if (Double.isNaN(a)) {
|
||||
return b;
|
||||
}
|
||||
if (Double.isNaN(b)) {
|
||||
return a;
|
||||
}
|
||||
return Math.min(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum of three {@code double} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @param c value 3
|
||||
* @return the smallest of the values
|
||||
*/
|
||||
public static double min(final double a, final double b, final double c) {
|
||||
return min(min(a, b), c);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 NullPointerException if {@code array} is {@code null}
|
||||
* @throws IllegalArgumentException if {@code array} is empty
|
||||
* @since 3.4 Changed signature from min(float[]) to min(float...)
|
||||
*/
|
||||
public static float min(final float... array) {
|
||||
Objects.requireNonNull(array, "array");
|
||||
Validate.isTrue(array.length != 0, "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 two {@code float} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @return the smallest of the values
|
||||
*/
|
||||
public static float min(final float a, final float b) {
|
||||
if (Float.isNaN(a)) {
|
||||
return b;
|
||||
}
|
||||
if (Float.isNaN(b)) {
|
||||
return a;
|
||||
}
|
||||
return Math.max(a, b);
|
||||
return Math.min(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum of three {@code float} values.
|
||||
*
|
||||
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
|
||||
*
|
||||
* @param a value 1
|
||||
* @param b value 2
|
||||
* @param c value 3
|
||||
* @return the smallest of the values
|
||||
*/
|
||||
public static float min(final float a, final float b, final float c) {
|
||||
return min(min(a, b), c);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -67,6 +67,43 @@ public class MutableBoolean implements Mutable<Boolean>, Serializable, Comparabl
|
|||
this.value = value.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableBoolean as a boolean.
|
||||
*
|
||||
* @return the boolean value represented by this object.
|
||||
*/
|
||||
public boolean booleanValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this mutable to another in ascending order.
|
||||
*
|
||||
* @param other the other mutable to compare to, not null
|
||||
* @return negative if this is less, zero if equal, positive if greater
|
||||
* where false is less than true
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableBoolean other) {
|
||||
return BooleanUtils.compare(this.value, other.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object to the specified object. The result is {@code true} if and only if the argument is
|
||||
* not {@code null} and is an {@link MutableBoolean} object that contains the same
|
||||
* {@code boolean} value as this object.
|
||||
*
|
||||
* @param obj the object to compare with, null returns false
|
||||
* @return {@code true} if the objects are the same; {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj instanceof MutableBoolean) {
|
||||
return value == ((MutableBoolean) obj).booleanValue();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value as a Boolean instance.
|
||||
*
|
||||
|
@ -78,12 +115,33 @@ public class MutableBoolean implements Mutable<Boolean>, Serializable, Comparabl
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
* Returns a suitable hash code for this mutable.
|
||||
*
|
||||
* @param value the value to set
|
||||
* @return the hash code returned by {@code Boolean.TRUE} or {@code Boolean.FALSE}
|
||||
*/
|
||||
public void setValue(final boolean value) {
|
||||
this.value = value;
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value ? Boolean.TRUE.hashCode() : Boolean.FALSE.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current value is {@code false}.
|
||||
*
|
||||
* @return {@code true} if the current value is {@code false}
|
||||
* @since 2.5
|
||||
*/
|
||||
public boolean isFalse() {
|
||||
return !value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current value is {@code true}.
|
||||
*
|
||||
* @return {@code true} if the current value is {@code true}
|
||||
* @since 2.5
|
||||
*/
|
||||
public boolean isTrue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -104,6 +162,15 @@ public class MutableBoolean implements Mutable<Boolean>, Serializable, Comparabl
|
|||
this.value = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void setValue(final boolean value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value from any Boolean instance.
|
||||
*
|
||||
|
@ -115,35 +182,6 @@ public class MutableBoolean implements Mutable<Boolean>, Serializable, Comparabl
|
|||
this.value = value.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current value is {@code true}.
|
||||
*
|
||||
* @return {@code true} if the current value is {@code true}
|
||||
* @since 2.5
|
||||
*/
|
||||
public boolean isTrue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current value is {@code false}.
|
||||
*
|
||||
* @return {@code true} if the current value is {@code false}
|
||||
* @since 2.5
|
||||
*/
|
||||
public boolean isFalse() {
|
||||
return !value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -154,44 +192,6 @@ public class MutableBoolean implements Mutable<Boolean>, Serializable, Comparabl
|
|||
return Boolean.valueOf(booleanValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object to the specified object. The result is {@code true} if and only if the argument is
|
||||
* not {@code null} and is an {@link MutableBoolean} object that contains the same
|
||||
* {@code boolean} value as this object.
|
||||
*
|
||||
* @param obj the object to compare with, null returns false
|
||||
* @return {@code true} if the objects are the same; {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final 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 {@code Boolean.TRUE} or {@code Boolean.FALSE}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value ? Boolean.TRUE.hashCode() : Boolean.FALSE.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this mutable to another in ascending order.
|
||||
*
|
||||
* @param other the other mutable to compare to, not null
|
||||
* @return negative if this is less, zero if equal, positive if greater
|
||||
* where false is less than true
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableBoolean other) {
|
||||
return BooleanUtils.compare(this.value, other.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the String value of this mutable.
|
||||
*
|
||||
|
|
|
@ -75,104 +75,6 @@ public class MutableByte extends Number implements Comparable<MutableByte>, Muta
|
|||
this.value = Byte.parseByte(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value as a Byte instance.
|
||||
*
|
||||
* @return the value as a Byte, never null
|
||||
*/
|
||||
@Override
|
||||
public Byte getValue() {
|
||||
return Byte.valueOf(this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void setValue(final 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
|
||||
*/
|
||||
@Override
|
||||
public void setValue(final Number value) {
|
||||
this.value = value.byteValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void increment() {
|
||||
value++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public byte getAndIncrement() {
|
||||
final byte last = value;
|
||||
value++;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public byte incrementAndGet() {
|
||||
value++;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void decrement() {
|
||||
value--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public byte getAndDecrement() {
|
||||
final byte last = value;
|
||||
value--;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public byte decrementAndGet() {
|
||||
value--;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to the value of this instance.
|
||||
*
|
||||
|
@ -194,27 +96,6 @@ public class MutableByte extends Number implements Comparable<MutableByte>, Muta
|
|||
this.value += operand.byteValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a value from the value of this instance.
|
||||
*
|
||||
* @param operand the value to subtract, not null
|
||||
* @since 2.2
|
||||
*/
|
||||
public void subtract(final 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 2.2
|
||||
*/
|
||||
public void subtract(final Number operand) {
|
||||
this.value -= operand.byteValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately after the addition operation. This method is not thread safe.
|
||||
|
@ -242,6 +123,85 @@ public class MutableByte extends Number implements Comparable<MutableByte>, Muta
|
|||
return value;
|
||||
}
|
||||
|
||||
// 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.
|
||||
*/
|
||||
@Override
|
||||
public byte byteValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this mutable to another in ascending order.
|
||||
*
|
||||
* @param other the other mutable to compare to, not null
|
||||
* @return negative if this is less, zero if equal, positive if greater
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableByte other) {
|
||||
return NumberUtils.compare(this.value, other.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void decrement() {
|
||||
value--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public byte decrementAndGet() {
|
||||
value--;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableByte as a double.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type double.
|
||||
*/
|
||||
@Override
|
||||
public double doubleValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object to the specified object. The result is {@code true} if and only if the argument is
|
||||
* not {@code null} and is a {@link MutableByte} object that contains the same {@code byte} value
|
||||
* as this object.
|
||||
*
|
||||
* @param obj the object to compare with, null returns false
|
||||
* @return {@code true} if the objects are the same; {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj instanceof MutableByte) {
|
||||
return value == ((MutableByte) obj).byteValue();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableByte as a float.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type float.
|
||||
*/
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately prior to the addition operation. This method is not thread safe.
|
||||
|
@ -271,14 +231,70 @@ public class MutableByte extends Number implements Comparable<MutableByte>, Muta
|
|||
return last;
|
||||
}
|
||||
|
||||
// shortValue relies on Number implementation
|
||||
/**
|
||||
* Returns the value of this MutableByte as a byte.
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type byte.
|
||||
* @return the value associated with the instance before it was decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public byte getAndDecrement() {
|
||||
final byte last = value;
|
||||
value--;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public byte getAndIncrement() {
|
||||
final byte last = value;
|
||||
value++;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value as a Byte instance.
|
||||
*
|
||||
* @return the value as a Byte, never null
|
||||
*/
|
||||
@Override
|
||||
public byte byteValue() {
|
||||
public Byte getValue() {
|
||||
return Byte.valueOf(this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a suitable hash code for this mutable.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void increment() {
|
||||
value++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public byte incrementAndGet() {
|
||||
value++;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -303,23 +319,44 @@ public class MutableByte extends Number implements Comparable<MutableByte>, Muta
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableByte as a float.
|
||||
* Sets the value.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type float.
|
||||
* @param value the value to set
|
||||
*/
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return value;
|
||||
public void setValue(final byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableByte as a double.
|
||||
* Sets the value from any Number instance.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type double.
|
||||
* @param value the value to set, not null
|
||||
* @throws NullPointerException if the object is null
|
||||
*/
|
||||
@Override
|
||||
public double doubleValue() {
|
||||
return value;
|
||||
public void setValue(final Number value) {
|
||||
this.value = value.byteValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a value from the value of this instance.
|
||||
*
|
||||
* @param operand the value to subtract, not null
|
||||
* @since 2.2
|
||||
*/
|
||||
public void subtract(final 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 2.2
|
||||
*/
|
||||
public void subtract(final Number operand) {
|
||||
this.value -= operand.byteValue();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -331,43 +368,6 @@ public class MutableByte extends Number implements Comparable<MutableByte>, Muta
|
|||
return Byte.valueOf(byteValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object to the specified object. The result is {@code true} if and only if the argument is
|
||||
* not {@code null} and is a {@link MutableByte} object that contains the same {@code byte} value
|
||||
* as this object.
|
||||
*
|
||||
* @param obj the object to compare with, null returns false
|
||||
* @return {@code true} if the objects are the same; {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj instanceof MutableByte) {
|
||||
return value == ((MutableByte) obj).byteValue();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a suitable hash code for this mutable.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this mutable to another in ascending order.
|
||||
*
|
||||
* @param other the other mutable to compare to, not null
|
||||
* @return negative if this is less, zero if equal, positive if greater
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableByte other) {
|
||||
return NumberUtils.compare(this.value, other.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the String value of this mutable.
|
||||
*
|
||||
|
|
|
@ -73,122 +73,6 @@ public class MutableDouble extends Number implements Comparable<MutableDouble>,
|
|||
this.value = Double.parseDouble(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value as a Double instance.
|
||||
*
|
||||
* @return the value as a Double, never null
|
||||
*/
|
||||
@Override
|
||||
public Double getValue() {
|
||||
return Double.valueOf(this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void setValue(final 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
|
||||
*/
|
||||
@Override
|
||||
public void setValue(final Number value) {
|
||||
this.value = 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 2.2
|
||||
*/
|
||||
public void increment() {
|
||||
value++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public double getAndIncrement() {
|
||||
final double last = value;
|
||||
value++;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public double incrementAndGet() {
|
||||
value++;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void decrement() {
|
||||
value--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public double getAndDecrement() {
|
||||
final double last = value;
|
||||
value--;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public double decrementAndGet() {
|
||||
value--;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to the value of this instance.
|
||||
*
|
||||
|
@ -210,27 +94,6 @@ public class MutableDouble extends Number implements Comparable<MutableDouble>,
|
|||
this.value += operand.doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a value from the value of this instance.
|
||||
*
|
||||
* @param operand the value to subtract, not null
|
||||
* @since 2.2
|
||||
*/
|
||||
public void subtract(final 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 2.2
|
||||
*/
|
||||
public void subtract(final Number operand) {
|
||||
this.value -= operand.doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately after the addition operation. This method is not thread safe.
|
||||
|
@ -259,63 +122,35 @@ public class MutableDouble extends Number implements Comparable<MutableDouble>,
|
|||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately prior to the addition operation. This method is not thread safe.
|
||||
* Compares this mutable to another in ascending order.
|
||||
*
|
||||
* @param operand the quantity to add, not null
|
||||
* @return the value associated with this instance immediately before the operand was added
|
||||
* @param other the other mutable to compare to, not null
|
||||
* @return negative if this is less, zero if equal, positive if greater
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableDouble other) {
|
||||
return Double.compare(this.value, other.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void decrement() {
|
||||
value--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public double getAndAdd(final double operand) {
|
||||
final double last = value;
|
||||
this.value += operand;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately prior to the addition operation. This method is not thread safe.
|
||||
*
|
||||
* @param operand the quantity to add, not null
|
||||
* @throws NullPointerException if {@code operand} is null
|
||||
* @return the value associated with this instance immediately before the operand was added
|
||||
* @since 3.5
|
||||
*/
|
||||
public double getAndAdd(final Number operand) {
|
||||
final double last = value;
|
||||
this.value += operand.doubleValue();
|
||||
return last;
|
||||
}
|
||||
|
||||
// shortValue and byteValue 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.
|
||||
*/
|
||||
@Override
|
||||
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.
|
||||
*/
|
||||
@Override
|
||||
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.
|
||||
*/
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return (float) value;
|
||||
public double decrementAndGet() {
|
||||
value--;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -328,15 +163,6 @@ public class MutableDouble extends Number implements Comparable<MutableDouble>,
|
|||
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 Double.valueOf(doubleValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object against the specified object. The result is {@code true} if and only if the argument
|
||||
* is not {@code null} and is a {@link Double} object that represents a double that has the identical
|
||||
|
@ -372,6 +198,81 @@ public class MutableDouble extends Number implements Comparable<MutableDouble>,
|
|||
&& Double.doubleToLongBits(((MutableDouble) obj).value) == Double.doubleToLongBits(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableDouble as a float.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type float.
|
||||
*/
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return (float) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately prior to the addition operation. This method is not thread safe.
|
||||
*
|
||||
* @param operand the quantity to add, not null
|
||||
* @return the value associated with this instance immediately before the operand was added
|
||||
* @since 3.5
|
||||
*/
|
||||
public double getAndAdd(final double operand) {
|
||||
final double last = value;
|
||||
this.value += operand;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately prior to the addition operation. This method is not thread safe.
|
||||
*
|
||||
* @param operand the quantity to add, not null
|
||||
* @throws NullPointerException if {@code operand} is null
|
||||
* @return the value associated with this instance immediately before the operand was added
|
||||
* @since 3.5
|
||||
*/
|
||||
public double getAndAdd(final Number operand) {
|
||||
final double last = value;
|
||||
this.value += operand.doubleValue();
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public double getAndDecrement() {
|
||||
final double last = value;
|
||||
value--;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public double getAndIncrement() {
|
||||
final double last = value;
|
||||
value++;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value as a Double instance.
|
||||
*
|
||||
* @return the value as a Double, never null
|
||||
*/
|
||||
@Override
|
||||
public Double getValue() {
|
||||
return Double.valueOf(this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a suitable hash code for this mutable.
|
||||
*
|
||||
|
@ -384,14 +285,113 @@ public class MutableDouble extends Number implements Comparable<MutableDouble>,
|
|||
}
|
||||
|
||||
/**
|
||||
* Compares this mutable to another in ascending order.
|
||||
* Increments the value.
|
||||
*
|
||||
* @param other the other mutable to compare to, not null
|
||||
* @return negative if this is less, zero if equal, positive if greater
|
||||
* @since 2.2
|
||||
*/
|
||||
public void increment() {
|
||||
value++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public double incrementAndGet() {
|
||||
value++;
|
||||
return value;
|
||||
}
|
||||
|
||||
// shortValue and byteValue 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.
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableDouble other) {
|
||||
return Double.compare(this.value, other.value);
|
||||
public int intValue() {
|
||||
return (int) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the double value is infinite.
|
||||
*
|
||||
* @return true if infinite
|
||||
*/
|
||||
public boolean isInfinite() {
|
||||
return Double.isInfinite(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the double value is the special NaN value.
|
||||
*
|
||||
* @return true if NaN
|
||||
*/
|
||||
public boolean isNaN() {
|
||||
return Double.isNaN(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableDouble as a long.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type long.
|
||||
*/
|
||||
@Override
|
||||
public long longValue() {
|
||||
return (long) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void setValue(final 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
|
||||
*/
|
||||
@Override
|
||||
public void setValue(final Number value) {
|
||||
this.value = value.doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a value from the value of this instance.
|
||||
*
|
||||
* @param operand the value to subtract, not null
|
||||
* @since 2.2
|
||||
*/
|
||||
public void subtract(final 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 2.2
|
||||
*/
|
||||
public void subtract(final Number operand) {
|
||||
this.value -= operand.doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this mutable as an instance of Double.
|
||||
*
|
||||
* @return a Double instance containing the value from this mutable, never null
|
||||
*/
|
||||
public Double toDouble() {
|
||||
return Double.valueOf(doubleValue());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -73,122 +73,6 @@ public class MutableFloat extends Number implements Comparable<MutableFloat>, Mu
|
|||
this.value = Float.parseFloat(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value as a Float instance.
|
||||
*
|
||||
* @return the value as a Float, never null
|
||||
*/
|
||||
@Override
|
||||
public Float getValue() {
|
||||
return Float.valueOf(this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void setValue(final 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
|
||||
*/
|
||||
@Override
|
||||
public void setValue(final Number value) {
|
||||
this.value = 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 2.2
|
||||
*/
|
||||
public void increment() {
|
||||
value++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public float getAndIncrement() {
|
||||
final float last = value;
|
||||
value++;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public float incrementAndGet() {
|
||||
value++;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void decrement() {
|
||||
value--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public float getAndDecrement() {
|
||||
final float last = value;
|
||||
value--;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public float decrementAndGet() {
|
||||
value--;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to the value of this instance.
|
||||
*
|
||||
|
@ -210,27 +94,6 @@ public class MutableFloat extends Number implements Comparable<MutableFloat>, Mu
|
|||
this.value += operand.floatValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a value from the value of this instance.
|
||||
*
|
||||
* @param operand the value to subtract
|
||||
* @since 2.2
|
||||
*/
|
||||
public void subtract(final 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 2.2
|
||||
*/
|
||||
public void subtract(final Number operand) {
|
||||
this.value -= operand.floatValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately after the addition operation. This method is not thread safe.
|
||||
|
@ -259,62 +122,34 @@ public class MutableFloat extends Number implements Comparable<MutableFloat>, Mu
|
|||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately prior to the addition operation. This method is not thread safe.
|
||||
* Compares this mutable to another in ascending order.
|
||||
*
|
||||
* @param operand the quantity to add, not null
|
||||
* @return the value associated with this instance immediately before the operand was added
|
||||
* @param other the other mutable to compare to, not null
|
||||
* @return negative if this is less, zero if equal, positive if greater
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableFloat other) {
|
||||
return Float.compare(this.value, other.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void decrement() {
|
||||
value--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public float getAndAdd(final float operand) {
|
||||
final float last = value;
|
||||
this.value += operand;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately prior to the addition operation. This method is not thread safe.
|
||||
*
|
||||
* @param operand the quantity to add, not null
|
||||
* @throws NullPointerException if {@code operand} is null
|
||||
* @return the value associated with this instance immediately before the operand was added
|
||||
* @since 3.5
|
||||
*/
|
||||
public float getAndAdd(final Number operand) {
|
||||
final float last = value;
|
||||
this.value += operand.floatValue();
|
||||
return last;
|
||||
}
|
||||
|
||||
// shortValue and byteValue 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.
|
||||
*/
|
||||
@Override
|
||||
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.
|
||||
*/
|
||||
@Override
|
||||
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.
|
||||
*/
|
||||
@Override
|
||||
public float floatValue() {
|
||||
public float decrementAndGet() {
|
||||
value--;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -328,15 +163,6 @@ public class MutableFloat extends Number implements Comparable<MutableFloat>, Mu
|
|||
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 Float.valueOf(floatValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object against some other object. The result is {@code true} if and only if the argument is
|
||||
* not {@code null} and is a {@link Float} object that represents a {@code float} that has the
|
||||
|
@ -374,6 +200,81 @@ public class MutableFloat extends Number implements Comparable<MutableFloat>, Mu
|
|||
&& Float.floatToIntBits(((MutableFloat) obj).value) == Float.floatToIntBits(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableFloat as a float.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type float.
|
||||
*/
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately prior to the addition operation. This method is not thread safe.
|
||||
*
|
||||
* @param operand the quantity to add, not null
|
||||
* @return the value associated with this instance immediately before the operand was added
|
||||
* @since 3.5
|
||||
*/
|
||||
public float getAndAdd(final float operand) {
|
||||
final float last = value;
|
||||
this.value += operand;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately prior to the addition operation. This method is not thread safe.
|
||||
*
|
||||
* @param operand the quantity to add, not null
|
||||
* @throws NullPointerException if {@code operand} is null
|
||||
* @return the value associated with this instance immediately before the operand was added
|
||||
* @since 3.5
|
||||
*/
|
||||
public float getAndAdd(final Number operand) {
|
||||
final float last = value;
|
||||
this.value += operand.floatValue();
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public float getAndDecrement() {
|
||||
final float last = value;
|
||||
value--;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public float getAndIncrement() {
|
||||
final float last = value;
|
||||
value++;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value as a Float instance.
|
||||
*
|
||||
* @return the value as a Float, never null
|
||||
*/
|
||||
@Override
|
||||
public Float getValue() {
|
||||
return Float.valueOf(this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a suitable hash code for this mutable.
|
||||
*
|
||||
|
@ -385,14 +286,113 @@ public class MutableFloat extends Number implements Comparable<MutableFloat>, Mu
|
|||
}
|
||||
|
||||
/**
|
||||
* Compares this mutable to another in ascending order.
|
||||
* Increments the value.
|
||||
*
|
||||
* @param other the other mutable to compare to, not null
|
||||
* @return negative if this is less, zero if equal, positive if greater
|
||||
* @since 2.2
|
||||
*/
|
||||
public void increment() {
|
||||
value++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public float incrementAndGet() {
|
||||
value++;
|
||||
return value;
|
||||
}
|
||||
|
||||
// shortValue and byteValue 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.
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableFloat other) {
|
||||
return Float.compare(this.value, other.value);
|
||||
public int intValue() {
|
||||
return (int) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the float value is infinite.
|
||||
*
|
||||
* @return true if infinite
|
||||
*/
|
||||
public boolean isInfinite() {
|
||||
return Float.isInfinite(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the float value is the special NaN value.
|
||||
*
|
||||
* @return true if NaN
|
||||
*/
|
||||
public boolean isNaN() {
|
||||
return Float.isNaN(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableFloat as a long.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type long.
|
||||
*/
|
||||
@Override
|
||||
public long longValue() {
|
||||
return (long) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void setValue(final 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
|
||||
*/
|
||||
@Override
|
||||
public void setValue(final Number value) {
|
||||
this.value = value.floatValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a value from the value of this instance.
|
||||
*
|
||||
* @param operand the value to subtract
|
||||
* @since 2.2
|
||||
*/
|
||||
public void subtract(final 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 2.2
|
||||
*/
|
||||
public void subtract(final Number operand) {
|
||||
this.value -= operand.floatValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this mutable as an instance of Float.
|
||||
*
|
||||
* @return a Float instance containing the value from this mutable, never null
|
||||
*/
|
||||
public Float toFloat() {
|
||||
return Float.valueOf(floatValue());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -75,104 +75,6 @@ public class MutableInt extends Number implements Comparable<MutableInt>, Mutabl
|
|||
this.value = Integer.parseInt(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value as a Integer instance.
|
||||
*
|
||||
* @return the value as a Integer, never null
|
||||
*/
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return Integer.valueOf(this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void setValue(final 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
|
||||
*/
|
||||
@Override
|
||||
public void setValue(final Number value) {
|
||||
this.value = value.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void increment() {
|
||||
value++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public int getAndIncrement() {
|
||||
final int last = value;
|
||||
value++;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public int incrementAndGet() {
|
||||
value++;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void decrement() {
|
||||
value--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public int getAndDecrement() {
|
||||
final int last = value;
|
||||
value--;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public int decrementAndGet() {
|
||||
value--;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to the value of this instance.
|
||||
*
|
||||
|
@ -194,27 +96,6 @@ public class MutableInt extends Number implements Comparable<MutableInt>, Mutabl
|
|||
this.value += operand.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a value from the value of this instance.
|
||||
*
|
||||
* @param operand the value to subtract, not null
|
||||
* @since 2.2
|
||||
*/
|
||||
public void subtract(final 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 2.2
|
||||
*/
|
||||
public void subtract(final Number operand) {
|
||||
this.value -= operand.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately after the addition operation. This method is not thread safe.
|
||||
|
@ -242,6 +123,74 @@ public class MutableInt extends Number implements Comparable<MutableInt>, Mutabl
|
|||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this mutable to another in ascending order.
|
||||
*
|
||||
* @param other the other mutable to compare to, not null
|
||||
* @return negative if this is less, zero if equal, positive if greater
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableInt other) {
|
||||
return NumberUtils.compare(this.value, other.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void decrement() {
|
||||
value--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public int decrementAndGet() {
|
||||
value--;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableInt as a double.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type double.
|
||||
*/
|
||||
@Override
|
||||
public double doubleValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object to the specified object. The result is {@code true} if and only if the argument is
|
||||
* not {@code null} and is a {@link MutableInt} object that contains the same {@code int} value
|
||||
* as this object.
|
||||
*
|
||||
* @param obj the object to compare with, null returns false
|
||||
* @return {@code true} if the objects are the same; {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj instanceof MutableInt) {
|
||||
return value == ((MutableInt) obj).intValue();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableInt as a float.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type float.
|
||||
*/
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately prior to the addition operation. This method is not thread safe.
|
||||
|
@ -271,6 +220,73 @@ public class MutableInt extends Number implements Comparable<MutableInt>, Mutabl
|
|||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public int getAndDecrement() {
|
||||
final int last = value;
|
||||
value--;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public int getAndIncrement() {
|
||||
final int last = value;
|
||||
value++;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value as a Integer instance.
|
||||
*
|
||||
* @return the value as a Integer, never null
|
||||
*/
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return Integer.valueOf(this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a suitable hash code for this mutable.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void increment() {
|
||||
value++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public int incrementAndGet() {
|
||||
value++;
|
||||
return value;
|
||||
}
|
||||
|
||||
// shortValue and byteValue rely on Number implementation
|
||||
/**
|
||||
* Returns the value of this MutableInt as an int.
|
||||
|
@ -293,23 +309,44 @@ public class MutableInt extends Number implements Comparable<MutableInt>, Mutabl
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableInt as a float.
|
||||
* Sets the value.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type float.
|
||||
* @param value the value to set
|
||||
*/
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return value;
|
||||
public void setValue(final int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableInt as a double.
|
||||
* Sets the value from any Number instance.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type double.
|
||||
* @param value the value to set, not null
|
||||
* @throws NullPointerException if the object is null
|
||||
*/
|
||||
@Override
|
||||
public double doubleValue() {
|
||||
return value;
|
||||
public void setValue(final Number value) {
|
||||
this.value = value.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a value from the value of this instance.
|
||||
*
|
||||
* @param operand the value to subtract, not null
|
||||
* @since 2.2
|
||||
*/
|
||||
public void subtract(final 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 2.2
|
||||
*/
|
||||
public void subtract(final Number operand) {
|
||||
this.value -= operand.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -321,43 +358,6 @@ public class MutableInt extends Number implements Comparable<MutableInt>, Mutabl
|
|||
return Integer.valueOf(intValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object to the specified object. The result is {@code true} if and only if the argument is
|
||||
* not {@code null} and is a {@link MutableInt} object that contains the same {@code int} value
|
||||
* as this object.
|
||||
*
|
||||
* @param obj the object to compare with, null returns false
|
||||
* @return {@code true} if the objects are the same; {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final 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
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this mutable to another in ascending order.
|
||||
*
|
||||
* @param other the other mutable to compare to, not null
|
||||
* @return negative if this is less, zero if equal, positive if greater
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableInt other) {
|
||||
return NumberUtils.compare(this.value, other.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the String value of this mutable.
|
||||
*
|
||||
|
|
|
@ -75,104 +75,6 @@ public class MutableLong extends Number implements Comparable<MutableLong>, Muta
|
|||
this.value = Long.parseLong(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value as a Long instance.
|
||||
*
|
||||
* @return the value as a Long, never null
|
||||
*/
|
||||
@Override
|
||||
public Long getValue() {
|
||||
return Long.valueOf(this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void setValue(final 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
|
||||
*/
|
||||
@Override
|
||||
public void setValue(final Number value) {
|
||||
this.value = value.longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void increment() {
|
||||
value++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public long getAndIncrement() {
|
||||
final long last = value;
|
||||
value++;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public long incrementAndGet() {
|
||||
value++;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void decrement() {
|
||||
value--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public long getAndDecrement() {
|
||||
final long last = value;
|
||||
value--;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public long decrementAndGet() {
|
||||
value--;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to the value of this instance.
|
||||
*
|
||||
|
@ -194,27 +96,6 @@ public class MutableLong extends Number implements Comparable<MutableLong>, Muta
|
|||
this.value += operand.longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a value from the value of this instance.
|
||||
*
|
||||
* @param operand the value to subtract, not null
|
||||
* @since 2.2
|
||||
*/
|
||||
public void subtract(final 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 2.2
|
||||
*/
|
||||
public void subtract(final Number operand) {
|
||||
this.value -= operand.longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately after the addition operation. This method is not thread safe.
|
||||
|
@ -242,6 +123,74 @@ public class MutableLong extends Number implements Comparable<MutableLong>, Muta
|
|||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this mutable to another in ascending order.
|
||||
*
|
||||
* @param other the other mutable to compare to, not null
|
||||
* @return negative if this is less, zero if equal, positive if greater
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableLong other) {
|
||||
return NumberUtils.compare(this.value, other.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void decrement() {
|
||||
value--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public long decrementAndGet() {
|
||||
value--;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableLong as a double.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type double.
|
||||
*/
|
||||
@Override
|
||||
public double doubleValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object to the specified object. The result is {@code true} if and only if the argument
|
||||
* is not {@code null} and is a {@link MutableLong} object that contains the same {@code long}
|
||||
* value as this object.
|
||||
*
|
||||
* @param obj the object to compare with, null returns false
|
||||
* @return {@code true} if the objects are the same; {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj instanceof MutableLong) {
|
||||
return value == ((MutableLong) obj).longValue();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableLong as a float.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type float.
|
||||
*/
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately prior to the addition operation. This method is not thread safe.
|
||||
|
@ -271,6 +220,73 @@ public class MutableLong extends Number implements Comparable<MutableLong>, Muta
|
|||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public long getAndDecrement() {
|
||||
final long last = value;
|
||||
value--;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public long getAndIncrement() {
|
||||
final long last = value;
|
||||
value++;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value as a Long instance.
|
||||
*
|
||||
* @return the value as a Long, never null
|
||||
*/
|
||||
@Override
|
||||
public Long getValue() {
|
||||
return Long.valueOf(this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a suitable hash code for this mutable.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int) (value ^ (value >>> 32));
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void increment() {
|
||||
value++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public long incrementAndGet() {
|
||||
value++;
|
||||
return value;
|
||||
}
|
||||
|
||||
// shortValue and byteValue rely on Number implementation
|
||||
/**
|
||||
* Returns the value of this MutableLong as an int.
|
||||
|
@ -293,23 +309,44 @@ public class MutableLong extends Number implements Comparable<MutableLong>, Muta
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableLong as a float.
|
||||
* Sets the value.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type float.
|
||||
* @param value the value to set
|
||||
*/
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return value;
|
||||
public void setValue(final long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableLong as a double.
|
||||
* Sets the value from any Number instance.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type double.
|
||||
* @param value the value to set, not null
|
||||
* @throws NullPointerException if the object is null
|
||||
*/
|
||||
@Override
|
||||
public double doubleValue() {
|
||||
return value;
|
||||
public void setValue(final Number value) {
|
||||
this.value = value.longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a value from the value of this instance.
|
||||
*
|
||||
* @param operand the value to subtract, not null
|
||||
* @since 2.2
|
||||
*/
|
||||
public void subtract(final 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 2.2
|
||||
*/
|
||||
public void subtract(final Number operand) {
|
||||
this.value -= operand.longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -321,43 +358,6 @@ public class MutableLong extends Number implements Comparable<MutableLong>, Muta
|
|||
return Long.valueOf(longValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object to the specified object. The result is {@code true} if and only if the argument
|
||||
* is not {@code null} and is a {@link MutableLong} object that contains the same {@code long}
|
||||
* value as this object.
|
||||
*
|
||||
* @param obj the object to compare with, null returns false
|
||||
* @return {@code true} if the objects are the same; {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final 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
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int) (value ^ (value >>> 32));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this mutable to another in ascending order.
|
||||
*
|
||||
* @param other the other mutable to compare to, not null
|
||||
* @return negative if this is less, zero if equal, positive if greater
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableLong other) {
|
||||
return NumberUtils.compare(this.value, other.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the String value of this mutable.
|
||||
*
|
||||
|
|
|
@ -53,26 +53,6 @@ public class MutableObject<T> implements Mutable<T>, Serializable {
|
|||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value.
|
||||
*
|
||||
* @return the value, may be null
|
||||
*/
|
||||
@Override
|
||||
public T getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
@Override
|
||||
public void setValue(final T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object against the specified object. The result is {@code true} if and only if the argument
|
||||
* is not {@code null} and is a {@link MutableObject} object that contains the same {@link T}
|
||||
|
@ -98,6 +78,16 @@ public class MutableObject<T> implements Mutable<T>, Serializable {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value.
|
||||
*
|
||||
* @return the value, may be null
|
||||
*/
|
||||
@Override
|
||||
public T getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value's hash code or {@code 0} if the value is {@code null}.
|
||||
*
|
||||
|
@ -108,6 +98,16 @@ public class MutableObject<T> implements Mutable<T>, Serializable {
|
|||
return Objects.hashCode(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
@Override
|
||||
public void setValue(final T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the String value of this mutable.
|
||||
*
|
||||
|
|
|
@ -45,15 +45,6 @@ public class MutableShort extends Number implements Comparable<MutableShort>, Mu
|
|||
public MutableShort() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new MutableShort with the specified value.
|
||||
*
|
||||
* @param value the initial value to store
|
||||
*/
|
||||
public MutableShort(final short value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new MutableShort with the specified value.
|
||||
*
|
||||
|
@ -64,6 +55,15 @@ public class MutableShort extends Number implements Comparable<MutableShort>, Mu
|
|||
this.value = value.shortValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new MutableShort with the specified value.
|
||||
*
|
||||
* @param value the initial value to store
|
||||
*/
|
||||
public MutableShort(final short value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new MutableShort parsing the given string.
|
||||
*
|
||||
|
@ -75,114 +75,6 @@ public class MutableShort extends Number implements Comparable<MutableShort>, Mu
|
|||
this.value = Short.parseShort(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value as a Short instance.
|
||||
*
|
||||
* @return the value as a Short, never null
|
||||
*/
|
||||
@Override
|
||||
public Short getValue() {
|
||||
return Short.valueOf(this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void setValue(final 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
|
||||
*/
|
||||
@Override
|
||||
public void setValue(final Number value) {
|
||||
this.value = value.shortValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void increment() {
|
||||
value++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public short getAndIncrement() {
|
||||
final short last = value;
|
||||
value++;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public short incrementAndGet() {
|
||||
value++;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void decrement() {
|
||||
value--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public short getAndDecrement() {
|
||||
final short last = value;
|
||||
value--;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public short decrementAndGet() {
|
||||
value--;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to the value of this instance.
|
||||
*
|
||||
* @param operand the value to add, not null
|
||||
* @since 2.2
|
||||
*/
|
||||
public void add(final short operand) {
|
||||
this.value += operand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to the value of this instance.
|
||||
*
|
||||
|
@ -195,37 +87,13 @@ public class MutableShort extends Number implements Comparable<MutableShort>, Mu
|
|||
}
|
||||
|
||||
/**
|
||||
* Subtracts a value from the value of this instance.
|
||||
* Adds a value to the value of this instance.
|
||||
*
|
||||
* @param operand the value to subtract, not null
|
||||
* @param operand the value to add, not null
|
||||
* @since 2.2
|
||||
*/
|
||||
public void subtract(final 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 2.2
|
||||
*/
|
||||
public void subtract(final Number operand) {
|
||||
this.value -= operand.shortValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately after the addition operation. This method is not thread safe.
|
||||
*
|
||||
* @param operand the quantity to add, not null
|
||||
* @return the value associated with this instance after adding the operand
|
||||
* @since 3.5
|
||||
*/
|
||||
public short addAndGet(final short operand) {
|
||||
public void add(final short operand) {
|
||||
this.value += operand;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -244,16 +112,83 @@ public class MutableShort extends Number implements Comparable<MutableShort>, Mu
|
|||
|
||||
/**
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately prior to the addition operation. This method is not thread safe.
|
||||
* immediately after the addition operation. This method is not thread safe.
|
||||
*
|
||||
* @param operand the quantity to add, not null
|
||||
* @return the value associated with this instance immediately before the operand was added
|
||||
* @return the value associated with this instance after adding the operand
|
||||
* @since 3.5
|
||||
*/
|
||||
public short getAndAdd(final short operand) {
|
||||
final short last = value;
|
||||
public short addAndGet(final short operand) {
|
||||
this.value += operand;
|
||||
return last;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this mutable to another in ascending order.
|
||||
*
|
||||
* @param other the other mutable to compare to, not null
|
||||
* @return negative if this is less, zero if equal, positive if greater
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableShort other) {
|
||||
return NumberUtils.compare(this.value, other.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void decrement() {
|
||||
value--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public short decrementAndGet() {
|
||||
value--;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableShort as a double.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type double.
|
||||
*/
|
||||
@Override
|
||||
public double doubleValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object to the specified object. The result is {@code true} if and only if the argument
|
||||
* is not {@code null} and is a {@link MutableShort} object that contains the same {@code short}
|
||||
* value as this object.
|
||||
*
|
||||
* @param obj the object to compare with, null returns false
|
||||
* @return {@code true} if the objects are the same; {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj instanceof MutableShort) {
|
||||
return value == ((MutableShort) obj).shortValue();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableShort as a float.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type float.
|
||||
*/
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -271,14 +206,84 @@ public class MutableShort extends Number implements Comparable<MutableShort>, Mu
|
|||
return last;
|
||||
}
|
||||
|
||||
// byteValue relies on Number implementation
|
||||
/**
|
||||
* Returns the value of this MutableShort as a short.
|
||||
* Increments this instance's value by {@code operand}; this method returns the value associated with the instance
|
||||
* immediately prior to the addition operation. This method is not thread safe.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type short.
|
||||
* @param operand the quantity to add, not null
|
||||
* @return the value associated with this instance immediately before the operand was added
|
||||
* @since 3.5
|
||||
*/
|
||||
public short getAndAdd(final short operand) {
|
||||
final short last = value;
|
||||
this.value += operand;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the decrement operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was decremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public short getAndDecrement() {
|
||||
final short last = value;
|
||||
value--;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately prior to the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance before it was incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public short getAndIncrement() {
|
||||
final short last = value;
|
||||
value++;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value as a Short instance.
|
||||
*
|
||||
* @return the value as a Short, never null
|
||||
*/
|
||||
@Override
|
||||
public short shortValue() {
|
||||
public Short getValue() {
|
||||
return Short.valueOf(this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a suitable hash code for this mutable.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the value.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void increment() {
|
||||
value++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this instance's value by 1; this method returns the value associated with the instance
|
||||
* immediately after the increment operation. This method is not thread safe.
|
||||
*
|
||||
* @return the value associated with the instance after it is incremented
|
||||
* @since 3.5
|
||||
*/
|
||||
public short incrementAndGet() {
|
||||
value++;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -303,23 +308,55 @@ public class MutableShort extends Number implements Comparable<MutableShort>, Mu
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableShort as a float.
|
||||
* Sets the value from any Number instance.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type float.
|
||||
* @param value the value to set, not null
|
||||
* @throws NullPointerException if the object is null
|
||||
*/
|
||||
@Override
|
||||
public float floatValue() {
|
||||
public void setValue(final Number value) {
|
||||
this.value = value.shortValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void setValue(final short value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
// byteValue 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.
|
||||
*/
|
||||
@Override
|
||||
public short shortValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this MutableShort as a double.
|
||||
* Subtracts a value from the value of this instance.
|
||||
*
|
||||
* @return the numeric value represented by this object after conversion to type double.
|
||||
* @param operand the value to subtract, not null
|
||||
* @throws NullPointerException if the object is null
|
||||
* @since 2.2
|
||||
*/
|
||||
@Override
|
||||
public double doubleValue() {
|
||||
return value;
|
||||
public void subtract(final Number operand) {
|
||||
this.value -= operand.shortValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a value from the value of this instance.
|
||||
*
|
||||
* @param operand the value to subtract, not null
|
||||
* @since 2.2
|
||||
*/
|
||||
public void subtract(final short operand) {
|
||||
this.value -= operand;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -331,43 +368,6 @@ public class MutableShort extends Number implements Comparable<MutableShort>, Mu
|
|||
return Short.valueOf(shortValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object to the specified object. The result is {@code true} if and only if the argument
|
||||
* is not {@code null} and is a {@link MutableShort} object that contains the same {@code short}
|
||||
* value as this object.
|
||||
*
|
||||
* @param obj the object to compare with, null returns false
|
||||
* @return {@code true} if the objects are the same; {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final 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
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this mutable to another in ascending order.
|
||||
*
|
||||
* @param other the other mutable to compare to, not null
|
||||
* @return negative if this is less, zero if equal, positive if greater
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final MutableShort other) {
|
||||
return NumberUtils.compare(this.value, other.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the String value of this mutable.
|
||||
*
|
||||
|
|
|
@ -46,14 +46,99 @@ import org.apache.commons.lang3.ClassUtils;
|
|||
public class ConstructorUtils {
|
||||
|
||||
/**
|
||||
* ConstructorUtils instances should NOT be constructed in standard
|
||||
* programming. Instead, the class should be used as
|
||||
* {@code ConstructorUtils.invokeConstructor(cls, args)}.
|
||||
* Finds a constructor given a class and signature, checking accessibility.
|
||||
*
|
||||
* <p>This constructor is {@code public} to permit tools that require a JavaBean
|
||||
* instance to operate.</p>
|
||||
* <p>This finds the constructor and ensures that it is accessible.
|
||||
* The constructor signature must match the parameter types exactly.</p>
|
||||
*
|
||||
* @param <T> the constructor type
|
||||
* @param cls the class to find a constructor for, not {@code null}
|
||||
* @param parameterTypes the array of parameter types, {@code null} treated as empty
|
||||
* @return the constructor, {@code null} if no matching accessible constructor found
|
||||
* @see Class#getConstructor
|
||||
* @see #getAccessibleConstructor(java.lang.reflect.Constructor)
|
||||
* @throws NullPointerException if {@code cls} is {@code null}
|
||||
*/
|
||||
public ConstructorUtils() {
|
||||
public static <T> Constructor<T> getAccessibleConstructor(final Class<T> cls,
|
||||
final Class<?>... parameterTypes) {
|
||||
Objects.requireNonNull(cls, "cls");
|
||||
try {
|
||||
return getAccessibleConstructor(cls.getConstructor(parameterTypes));
|
||||
} catch (final NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified constructor is accessible.
|
||||
*
|
||||
* <p>This simply ensures that the constructor is accessible.</p>
|
||||
*
|
||||
* @param <T> the constructor type
|
||||
* @param ctor the prototype constructor object, not {@code null}
|
||||
* @return the constructor, {@code null} if no matching accessible constructor found
|
||||
* @see SecurityManager
|
||||
* @throws NullPointerException if {@code ctor} is {@code null}
|
||||
*/
|
||||
public static <T> Constructor<T> getAccessibleConstructor(final Constructor<T> ctor) {
|
||||
Objects.requireNonNull(ctor, "ctor");
|
||||
return MemberUtils.isAccessible(ctor)
|
||||
&& isAccessible(ctor.getDeclaringClass()) ? ctor : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an accessible constructor with compatible parameters.
|
||||
*
|
||||
* <p>This checks all the constructor and finds one with compatible parameters
|
||||
* This requires that every parameter is assignable from the given parameter types.
|
||||
* This is a more flexible search than the normal exact matching algorithm.</p>
|
||||
*
|
||||
* <p>First it checks if there is a constructor matching the exact signature.
|
||||
* If not then all the constructors of the class are checked to see if their
|
||||
* signatures are assignment-compatible with the parameter types.
|
||||
* The first assignment-compatible matching constructor is returned.</p>
|
||||
*
|
||||
* @param <T> the constructor type
|
||||
* @param cls the class to find a constructor for, not {@code null}
|
||||
* @param parameterTypes find method with compatible parameters
|
||||
* @return the constructor, null if no matching accessible constructor found
|
||||
* @throws NullPointerException if {@code cls} is {@code null}
|
||||
*/
|
||||
public static <T> Constructor<T> getMatchingAccessibleConstructor(final Class<T> cls,
|
||||
final Class<?>... parameterTypes) {
|
||||
Objects.requireNonNull(cls, "cls");
|
||||
// see if we can find the constructor directly
|
||||
// most of the time this works and it's much faster
|
||||
try {
|
||||
return MemberUtils.setAccessibleWorkaround(cls.getConstructor(parameterTypes));
|
||||
} catch (final NoSuchMethodException ignored) {
|
||||
// ignore
|
||||
}
|
||||
Constructor<T> result = null;
|
||||
/*
|
||||
* (1) Class.getConstructors() is documented to return Constructor<T> so as
|
||||
* long as the array is not subsequently modified, everything's fine.
|
||||
*/
|
||||
final Constructor<?>[] ctors = cls.getConstructors();
|
||||
|
||||
// return best match:
|
||||
for (Constructor<?> ctor : ctors) {
|
||||
// compare parameters
|
||||
if (MemberUtils.isMatchingConstructor(ctor, parameterTypes)) {
|
||||
// get accessible version of constructor
|
||||
ctor = getAccessibleConstructor(ctor);
|
||||
if (ctor != null) {
|
||||
MemberUtils.setAccessibleWorkaround(ctor);
|
||||
if (result == null || MemberUtils.compareConstructorFit(ctor, result, parameterTypes) < 0) {
|
||||
// temporary variable for annotation, see comment above (1)
|
||||
@SuppressWarnings("unchecked")
|
||||
final Constructor<T> constructor = (Constructor<T>) ctor;
|
||||
result = constructor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -178,102 +263,6 @@ public class ConstructorUtils {
|
|||
return ctor.newInstance(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a constructor given a class and signature, checking accessibility.
|
||||
*
|
||||
* <p>This finds the constructor and ensures that it is accessible.
|
||||
* The constructor signature must match the parameter types exactly.</p>
|
||||
*
|
||||
* @param <T> the constructor type
|
||||
* @param cls the class to find a constructor for, not {@code null}
|
||||
* @param parameterTypes the array of parameter types, {@code null} treated as empty
|
||||
* @return the constructor, {@code null} if no matching accessible constructor found
|
||||
* @see Class#getConstructor
|
||||
* @see #getAccessibleConstructor(java.lang.reflect.Constructor)
|
||||
* @throws NullPointerException if {@code cls} is {@code null}
|
||||
*/
|
||||
public static <T> Constructor<T> getAccessibleConstructor(final Class<T> cls,
|
||||
final Class<?>... parameterTypes) {
|
||||
Objects.requireNonNull(cls, "cls");
|
||||
try {
|
||||
return getAccessibleConstructor(cls.getConstructor(parameterTypes));
|
||||
} catch (final NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified constructor is accessible.
|
||||
*
|
||||
* <p>This simply ensures that the constructor is accessible.</p>
|
||||
*
|
||||
* @param <T> the constructor type
|
||||
* @param ctor the prototype constructor object, not {@code null}
|
||||
* @return the constructor, {@code null} if no matching accessible constructor found
|
||||
* @see SecurityManager
|
||||
* @throws NullPointerException if {@code ctor} is {@code null}
|
||||
*/
|
||||
public static <T> Constructor<T> getAccessibleConstructor(final Constructor<T> ctor) {
|
||||
Objects.requireNonNull(ctor, "ctor");
|
||||
return MemberUtils.isAccessible(ctor)
|
||||
&& isAccessible(ctor.getDeclaringClass()) ? ctor : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an accessible constructor with compatible parameters.
|
||||
*
|
||||
* <p>This checks all the constructor and finds one with compatible parameters
|
||||
* This requires that every parameter is assignable from the given parameter types.
|
||||
* This is a more flexible search than the normal exact matching algorithm.</p>
|
||||
*
|
||||
* <p>First it checks if there is a constructor matching the exact signature.
|
||||
* If not then all the constructors of the class are checked to see if their
|
||||
* signatures are assignment-compatible with the parameter types.
|
||||
* The first assignment-compatible matching constructor is returned.</p>
|
||||
*
|
||||
* @param <T> the constructor type
|
||||
* @param cls the class to find a constructor for, not {@code null}
|
||||
* @param parameterTypes find method with compatible parameters
|
||||
* @return the constructor, null if no matching accessible constructor found
|
||||
* @throws NullPointerException if {@code cls} is {@code null}
|
||||
*/
|
||||
public static <T> Constructor<T> getMatchingAccessibleConstructor(final Class<T> cls,
|
||||
final Class<?>... parameterTypes) {
|
||||
Objects.requireNonNull(cls, "cls");
|
||||
// see if we can find the constructor directly
|
||||
// most of the time this works and it's much faster
|
||||
try {
|
||||
return MemberUtils.setAccessibleWorkaround(cls.getConstructor(parameterTypes));
|
||||
} catch (final NoSuchMethodException ignored) {
|
||||
// ignore
|
||||
}
|
||||
Constructor<T> result = null;
|
||||
/*
|
||||
* (1) Class.getConstructors() is documented to return Constructor<T> so as
|
||||
* long as the array is not subsequently modified, everything's fine.
|
||||
*/
|
||||
final Constructor<?>[] ctors = cls.getConstructors();
|
||||
|
||||
// return best match:
|
||||
for (Constructor<?> ctor : ctors) {
|
||||
// compare parameters
|
||||
if (MemberUtils.isMatchingConstructor(ctor, parameterTypes)) {
|
||||
// get accessible version of constructor
|
||||
ctor = getAccessibleConstructor(ctor);
|
||||
if (ctor != null) {
|
||||
MemberUtils.setAccessibleWorkaround(ctor);
|
||||
if (result == null || MemberUtils.compareConstructorFit(ctor, result, parameterTypes) < 0) {
|
||||
// temporary variable for annotation, see comment above (1)
|
||||
@SuppressWarnings("unchecked")
|
||||
final Constructor<T> constructor = (Constructor<T>) ctor;
|
||||
result = constructor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the specified class is generally accessible, i.e. is
|
||||
* declared in an entirely {@code public} manner.
|
||||
|
@ -292,4 +281,15 @@ public class ConstructorUtils {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ConstructorUtils instances should NOT be constructed in standard
|
||||
* programming. Instead, the class should be used as
|
||||
* {@code ConstructorUtils.invokeConstructor(cls, args)}.
|
||||
*
|
||||
* <p>This constructor is {@code public} to permit tools that require a JavaBean
|
||||
* instance to operate.</p>
|
||||
*/
|
||||
public ConstructorUtils() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,12 +44,93 @@ import org.apache.commons.lang3.Validate;
|
|||
public class FieldUtils {
|
||||
|
||||
/**
|
||||
* {@link FieldUtils} instances should NOT be constructed in standard programming.
|
||||
* <p>
|
||||
* This constructor is {@code public} to permit tools that require a JavaBean instance to operate.
|
||||
* </p>
|
||||
* Gets all fields of the given class and its parents (if any).
|
||||
*
|
||||
* @param cls
|
||||
* the {@link Class} to query
|
||||
* @return an array of Fields (possibly empty).
|
||||
* @throws NullPointerException
|
||||
* if the class is {@code null}
|
||||
* @since 3.2
|
||||
*/
|
||||
public FieldUtils() {
|
||||
public static Field[] getAllFields(final Class<?> cls) {
|
||||
return getAllFieldsList(cls).toArray(ArrayUtils.EMPTY_FIELD_ARRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all fields of the given class and its parents (if any).
|
||||
*
|
||||
* @param cls
|
||||
* the {@link Class} to query
|
||||
* @return a list of Fields (possibly empty).
|
||||
* @throws NullPointerException
|
||||
* if the class is {@code null}
|
||||
* @since 3.2
|
||||
*/
|
||||
public static List<Field> getAllFieldsList(final Class<?> cls) {
|
||||
Objects.requireNonNull(cls, "cls");
|
||||
final List<Field> allFields = new ArrayList<>();
|
||||
Class<?> currentClass = cls;
|
||||
while (currentClass != null) {
|
||||
final Field[] declaredFields = currentClass.getDeclaredFields();
|
||||
Collections.addAll(allFields, declaredFields);
|
||||
currentClass = currentClass.getSuperclass();
|
||||
}
|
||||
return allFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an accessible {@link Field} by name respecting scope. Only the specified class will be considered.
|
||||
*
|
||||
* @param cls
|
||||
* the {@link Class} to reflect, must not be {@code null}
|
||||
* @param fieldName
|
||||
* the field name to obtain
|
||||
* @return the Field object
|
||||
* @throws NullPointerException
|
||||
* if the class is {@code null}
|
||||
* @throws IllegalArgumentException
|
||||
* if the field name is {@code null}, blank, or empty
|
||||
*/
|
||||
public static Field getDeclaredField(final Class<?> cls, final String fieldName) {
|
||||
return getDeclaredField(cls, fieldName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an accessible {@link Field} by name, breaking scope if requested. Only the specified class will be
|
||||
* considered.
|
||||
*
|
||||
* @param cls
|
||||
* the {@link Class} to reflect, must not be {@code null}
|
||||
* @param fieldName
|
||||
* the field name to obtain
|
||||
* @param forceAccess
|
||||
* whether to break scope restrictions using the
|
||||
* {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
|
||||
* match {@code public} fields.
|
||||
* @return the Field object
|
||||
* @throws NullPointerException
|
||||
* if the class is {@code null}
|
||||
* @throws IllegalArgumentException
|
||||
* if the field name is {@code null}, blank, or empty
|
||||
*/
|
||||
public static Field getDeclaredField(final Class<?> cls, final String fieldName, final boolean forceAccess) {
|
||||
Objects.requireNonNull(cls, "cls");
|
||||
Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty");
|
||||
try {
|
||||
// only consider the specified class by using getDeclaredField()
|
||||
final Field field = cls.getDeclaredField(fieldName);
|
||||
if (!MemberUtils.isAccessible(field)) {
|
||||
if (!forceAccess) {
|
||||
return null;
|
||||
}
|
||||
field.setAccessible(true);
|
||||
}
|
||||
return field;
|
||||
} catch (final NoSuchFieldException ignored) {
|
||||
// ignore
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -138,93 +219,19 @@ public class FieldUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets an accessible {@link Field} by name respecting scope. Only the specified class will be considered.
|
||||
*
|
||||
* @param cls
|
||||
* the {@link Class} to reflect, must not be {@code null}
|
||||
* @param fieldName
|
||||
* the field name to obtain
|
||||
* @return the Field object
|
||||
* @throws NullPointerException
|
||||
* if the class is {@code null}
|
||||
* @throws IllegalArgumentException
|
||||
* if the field name is {@code null}, blank, or empty
|
||||
*/
|
||||
public static Field getDeclaredField(final Class<?> cls, final String fieldName) {
|
||||
return getDeclaredField(cls, fieldName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an accessible {@link Field} by name, breaking scope if requested. Only the specified class will be
|
||||
* considered.
|
||||
*
|
||||
* @param cls
|
||||
* the {@link Class} to reflect, must not be {@code null}
|
||||
* @param fieldName
|
||||
* the field name to obtain
|
||||
* @param forceAccess
|
||||
* whether to break scope restrictions using the
|
||||
* {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
|
||||
* match {@code public} fields.
|
||||
* @return the Field object
|
||||
* @throws NullPointerException
|
||||
* if the class is {@code null}
|
||||
* @throws IllegalArgumentException
|
||||
* if the field name is {@code null}, blank, or empty
|
||||
*/
|
||||
public static Field getDeclaredField(final Class<?> cls, final String fieldName, final boolean forceAccess) {
|
||||
Objects.requireNonNull(cls, "cls");
|
||||
Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty");
|
||||
try {
|
||||
// only consider the specified class by using getDeclaredField()
|
||||
final Field field = cls.getDeclaredField(fieldName);
|
||||
if (!MemberUtils.isAccessible(field)) {
|
||||
if (!forceAccess) {
|
||||
return null;
|
||||
}
|
||||
field.setAccessible(true);
|
||||
}
|
||||
return field;
|
||||
} catch (final NoSuchFieldException ignored) {
|
||||
// ignore
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all fields of the given class and its parents (if any).
|
||||
*
|
||||
* @param cls
|
||||
* the {@link Class} to query
|
||||
* @return an array of Fields (possibly empty).
|
||||
* @throws NullPointerException
|
||||
* if the class is {@code null}
|
||||
* @since 3.2
|
||||
*/
|
||||
public static Field[] getAllFields(final Class<?> cls) {
|
||||
return getAllFieldsList(cls).toArray(ArrayUtils.EMPTY_FIELD_ARRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all fields of the given class and its parents (if any).
|
||||
*
|
||||
* Gets all fields of the given class and its parents (if any) that are annotated with the given annotation.
|
||||
* @param cls
|
||||
* the {@link Class} to query
|
||||
* @param annotationCls
|
||||
* the {@link Annotation} that must be present on a field to be matched
|
||||
* @return a list of Fields (possibly empty).
|
||||
* @throws NullPointerException
|
||||
* if the class is {@code null}
|
||||
* @since 3.2
|
||||
* if the class or annotation are {@code null}
|
||||
* @since 3.4
|
||||
*/
|
||||
public static List<Field> getAllFieldsList(final Class<?> cls) {
|
||||
Objects.requireNonNull(cls, "cls");
|
||||
final List<Field> allFields = new ArrayList<>();
|
||||
Class<?> currentClass = cls;
|
||||
while (currentClass != null) {
|
||||
final Field[] declaredFields = currentClass.getDeclaredFields();
|
||||
Collections.addAll(allFields, declaredFields);
|
||||
currentClass = currentClass.getSuperclass();
|
||||
}
|
||||
return allFields;
|
||||
public static List<Field> getFieldsListWithAnnotation(final Class<?> cls, final Class<? extends Annotation> annotationCls) {
|
||||
Objects.requireNonNull(annotationCls, "annotationCls");
|
||||
return getAllFieldsList(cls).stream().filter(field -> field.getAnnotation(annotationCls) != null).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -243,103 +250,50 @@ public class FieldUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets all fields of the given class and its parents (if any) that are annotated with the given annotation.
|
||||
* @param cls
|
||||
* the {@link Class} to query
|
||||
* @param annotationCls
|
||||
* the {@link Annotation} that must be present on a field to be matched
|
||||
* @return a list of Fields (possibly empty).
|
||||
* @throws NullPointerException
|
||||
* if the class or annotation are {@code null}
|
||||
* @since 3.4
|
||||
*/
|
||||
public static List<Field> getFieldsListWithAnnotation(final Class<?> cls, final Class<? extends Annotation> annotationCls) {
|
||||
Objects.requireNonNull(annotationCls, "annotationCls");
|
||||
return getAllFieldsList(cls).stream().filter(field -> field.getAnnotation(annotationCls) != null).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an accessible {@code static} {@link Field}.
|
||||
* Reads the named {@code public} {@link Field}. Only the class of the specified object will be considered.
|
||||
*
|
||||
* @param field
|
||||
* to read
|
||||
* @return the field value
|
||||
* @throws NullPointerException
|
||||
* if the field is {@code null}
|
||||
* @throws IllegalArgumentException
|
||||
* if the field is not {@code static}
|
||||
* @throws IllegalAccessException
|
||||
* if the field is not accessible
|
||||
*/
|
||||
public static Object readStaticField(final Field field) throws IllegalAccessException {
|
||||
return readStaticField(field, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a static {@link Field}.
|
||||
*
|
||||
* @param field
|
||||
* to read
|
||||
* @param forceAccess
|
||||
* whether to break scope restrictions using the
|
||||
* {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method.
|
||||
* @return the field value
|
||||
* @throws NullPointerException
|
||||
* if the field is {@code null}
|
||||
* @throws IllegalArgumentException
|
||||
* if the field is not {@code static}
|
||||
* @throws IllegalAccessException
|
||||
* if the field is not made accessible
|
||||
*/
|
||||
public static Object readStaticField(final Field field, final boolean forceAccess) throws IllegalAccessException {
|
||||
Objects.requireNonNull(field, "field");
|
||||
Validate.isTrue(MemberUtils.isStatic(field), "The field '%s' is not static", field.getName());
|
||||
return readField(field, (Object) null, forceAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the named {@code public static} {@link Field}. Superclasses will be considered.
|
||||
*
|
||||
* @param cls
|
||||
* the {@link Class} to reflect, must not be {@code null}
|
||||
* @param target
|
||||
* the object to reflect, must not be {@code null}
|
||||
* @param fieldName
|
||||
* the field name to obtain
|
||||
* @return the value of the field
|
||||
* @throws NullPointerException
|
||||
* if the class is {@code null}, or the field could not be found
|
||||
* if {@code target} is @{code null}
|
||||
* @throws IllegalArgumentException
|
||||
* if the field name is {@code null}, blank or empty, or is not {@code static}
|
||||
* if {@code fieldName} is {@code null}, blank or empty, or could not be found
|
||||
* @throws IllegalAccessException
|
||||
* if the field is not accessible
|
||||
* if the named field is not {@code public}
|
||||
*/
|
||||
public static Object readStaticField(final Class<?> cls, final String fieldName) throws IllegalAccessException {
|
||||
return readStaticField(cls, fieldName, false);
|
||||
public static Object readDeclaredField(final Object target, final String fieldName) throws IllegalAccessException {
|
||||
return readDeclaredField(target, fieldName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the named {@code static} {@link Field}. Superclasses will be considered.
|
||||
* Gets a {@link Field} value by name. Only the class of the specified object will be considered.
|
||||
*
|
||||
* @param cls
|
||||
* the {@link Class} to reflect, must not be {@code null}
|
||||
* @param target
|
||||
* the object to reflect, must not be {@code null}
|
||||
* @param fieldName
|
||||
* the field name to obtain
|
||||
* @param forceAccess
|
||||
* whether to break scope restrictions using the
|
||||
* {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
|
||||
* match {@code public} fields.
|
||||
* match public fields.
|
||||
* @return the Field object
|
||||
* @throws NullPointerException
|
||||
* if the class is {@code null}, or the field could not be found
|
||||
* if {@code target} is @{code null}
|
||||
* @throws IllegalArgumentException
|
||||
* if the field name is {@code null}, blank or empty, or is not {@code static}
|
||||
* if {@code fieldName} is {@code null}, blank or empty, or could not be found
|
||||
* @throws IllegalAccessException
|
||||
* if the field is not made accessible
|
||||
*/
|
||||
public static Object readStaticField(final Class<?> cls, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
|
||||
final Field field = getField(cls, fieldName, forceAccess);
|
||||
Validate.notNull(field, "Cannot locate field '%s' on %s", fieldName, cls);
|
||||
public static Object readDeclaredField(final Object target, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
|
||||
Objects.requireNonNull(target, "target");
|
||||
final Class<?> cls = target.getClass();
|
||||
final Field field = getDeclaredField(cls, fieldName, forceAccess);
|
||||
Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls, fieldName);
|
||||
// already forced access above, don't repeat it here:
|
||||
return readStaticField(field, false);
|
||||
return readField(field, target, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -479,142 +433,197 @@ public class FieldUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Reads the named {@code public} {@link Field}. Only the class of the specified object will be considered.
|
||||
* Reads the named {@code public static} {@link Field}. Superclasses will be considered.
|
||||
*
|
||||
* @param target
|
||||
* the object to reflect, must not be {@code null}
|
||||
* @param cls
|
||||
* the {@link Class} to reflect, must not be {@code null}
|
||||
* @param fieldName
|
||||
* the field name to obtain
|
||||
* @return the value of the field
|
||||
* @throws NullPointerException
|
||||
* if {@code target} is @{code null}
|
||||
* if the class is {@code null}, or the field could not be found
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code fieldName} is {@code null}, blank or empty, or could not be found
|
||||
* if the field name is {@code null}, blank or empty, or is not {@code static}
|
||||
* @throws IllegalAccessException
|
||||
* if the named field is not {@code public}
|
||||
* if the field is not accessible
|
||||
*/
|
||||
public static Object readDeclaredField(final Object target, final String fieldName) throws IllegalAccessException {
|
||||
return readDeclaredField(target, fieldName, false);
|
||||
public static Object readStaticField(final Class<?> cls, final String fieldName) throws IllegalAccessException {
|
||||
return readStaticField(cls, fieldName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link Field} value by name. Only the class of the specified object will be considered.
|
||||
* Reads the named {@code static} {@link Field}. Superclasses will be considered.
|
||||
*
|
||||
* @param target
|
||||
* the object to reflect, must not be {@code null}
|
||||
* @param cls
|
||||
* the {@link Class} to reflect, must not be {@code null}
|
||||
* @param fieldName
|
||||
* the field name to obtain
|
||||
* @param forceAccess
|
||||
* whether to break scope restrictions using the
|
||||
* {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
|
||||
* match public fields.
|
||||
* match {@code public} fields.
|
||||
* @return the Field object
|
||||
* @throws NullPointerException
|
||||
* if {@code target} is @{code null}
|
||||
* if the class is {@code null}, or the field could not be found
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code fieldName} is {@code null}, blank or empty, or could not be found
|
||||
* if the field name is {@code null}, blank or empty, or is not {@code static}
|
||||
* @throws IllegalAccessException
|
||||
* if the field is not made accessible
|
||||
*/
|
||||
public static Object readDeclaredField(final Object target, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
|
||||
Objects.requireNonNull(target, "target");
|
||||
final Class<?> cls = target.getClass();
|
||||
final Field field = getDeclaredField(cls, fieldName, forceAccess);
|
||||
Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls, fieldName);
|
||||
public static Object readStaticField(final Class<?> cls, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
|
||||
final Field field = getField(cls, fieldName, forceAccess);
|
||||
Validate.notNull(field, "Cannot locate field '%s' on %s", fieldName, cls);
|
||||
// already forced access above, don't repeat it here:
|
||||
return readField(field, target, false);
|
||||
return readStaticField(field, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a {@code public static} {@link Field}.
|
||||
* Reads an accessible {@code static} {@link Field}.
|
||||
*
|
||||
* @param field
|
||||
* to write
|
||||
* @param value
|
||||
* to set
|
||||
* to read
|
||||
* @return the field value
|
||||
* @throws NullPointerException
|
||||
* if the field is {@code null}
|
||||
* if the field is {@code null}
|
||||
* @throws IllegalArgumentException
|
||||
* if the field is not {@code static}, or {@code value} is not assignable
|
||||
* if the field is not {@code static}
|
||||
* @throws IllegalAccessException
|
||||
* if the field is not {@code public} or is {@code final}
|
||||
* if the field is not accessible
|
||||
*/
|
||||
public static void writeStaticField(final Field field, final Object value) throws IllegalAccessException {
|
||||
writeStaticField(field, value, false);
|
||||
public static Object readStaticField(final Field field) throws IllegalAccessException {
|
||||
return readStaticField(field, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a static {@link Field}.
|
||||
* Reads a static {@link Field}.
|
||||
*
|
||||
* @param field
|
||||
* to write
|
||||
* @param value
|
||||
* to set
|
||||
* to read
|
||||
* @param forceAccess
|
||||
* whether to break scope restrictions using the
|
||||
* {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method.
|
||||
* @return the field value
|
||||
* @throws NullPointerException
|
||||
* if the field is {@code null}
|
||||
* @throws IllegalArgumentException
|
||||
* if the field is not {@code static}
|
||||
* @throws IllegalAccessException
|
||||
* if the field is not made accessible
|
||||
*/
|
||||
public static Object readStaticField(final Field field, final boolean forceAccess) throws IllegalAccessException {
|
||||
Objects.requireNonNull(field, "field");
|
||||
Validate.isTrue(MemberUtils.isStatic(field), "The field '%s' is not static", field.getName());
|
||||
return readField(field, (Object) null, forceAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the final modifier from a {@link Field}.
|
||||
*
|
||||
* @param field
|
||||
* to remove the final modifier
|
||||
* @throws NullPointerException
|
||||
* if the field is {@code null}
|
||||
* @since 3.2
|
||||
*/
|
||||
public static void removeFinalModifier(final Field field) {
|
||||
removeFinalModifier(field, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the final modifier from a {@link Field}.
|
||||
*
|
||||
* @param field
|
||||
* to remove the final modifier
|
||||
* @param forceAccess
|
||||
* whether to break scope restrictions using the
|
||||
* {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
|
||||
* match {@code public} fields.
|
||||
* @throws NullPointerException
|
||||
* if the field is {@code null}
|
||||
* @throws IllegalArgumentException
|
||||
* if the field is not {@code static}, or {@code value} is not assignable
|
||||
* @throws IllegalAccessException
|
||||
* if the field is not made accessible or is {@code final}
|
||||
* if the field is {@code null}
|
||||
* @deprecated As of Java 12, we can no longer drop the {@code final} modifier, thus
|
||||
* rendering this method obsolete. The JDK discussion about this change can be found
|
||||
* here: https://mail.openjdk.java.net/pipermail/core-libs-dev/2018-November/056486.html
|
||||
* @since 3.3
|
||||
*/
|
||||
public static void writeStaticField(final Field field, final Object value, final boolean forceAccess) throws IllegalAccessException {
|
||||
@Deprecated
|
||||
public static void removeFinalModifier(final Field field, final boolean forceAccess) {
|
||||
Objects.requireNonNull(field, "field");
|
||||
Validate.isTrue(MemberUtils.isStatic(field), "The field %s.%s is not static", field.getDeclaringClass().getName(),
|
||||
field.getName());
|
||||
writeField(field, (Object) null, value, forceAccess);
|
||||
|
||||
try {
|
||||
if (Modifier.isFinal(field.getModifiers())) {
|
||||
// Do all JREs implement Field with a private ivar called "modifiers"?
|
||||
final Field modifiersField = Field.class.getDeclaredField("modifiers");
|
||||
final boolean doForceAccess = forceAccess && !modifiersField.isAccessible();
|
||||
if (doForceAccess) {
|
||||
modifiersField.setAccessible(true);
|
||||
}
|
||||
try {
|
||||
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
|
||||
} finally {
|
||||
if (doForceAccess) {
|
||||
modifiersField.setAccessible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final NoSuchFieldException | IllegalAccessException e) {
|
||||
if (SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_12)) {
|
||||
throw new UnsupportedOperationException(
|
||||
"In java 12+ final cannot be removed.",
|
||||
e
|
||||
);
|
||||
}
|
||||
// else no exception is thrown because we can modify final.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a named {@code public static} {@link Field}. Superclasses will be considered.
|
||||
* Writes a {@code public} {@link Field}. Only the specified class will be considered.
|
||||
*
|
||||
* @param cls
|
||||
* {@link Class} on which the field is to be found
|
||||
* @param target
|
||||
* the object to reflect, must not be {@code null}
|
||||
* @param fieldName
|
||||
* to write
|
||||
* the field name to obtain
|
||||
* @param value
|
||||
* to set
|
||||
* @throws NullPointerException
|
||||
* if {@code target} is @{code null}
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code fieldName} is {@code null}, blank or empty, the field cannot be located or is
|
||||
* not {@code static}, or {@code value} is not assignable
|
||||
* if {@code fieldName} is {@code null}, blank or empty, or could not be found,
|
||||
* or {@code value} is not assignable
|
||||
* @throws IllegalAccessException
|
||||
* if the field is not {@code public} or is {@code final}
|
||||
* if the field is not made accessible
|
||||
*/
|
||||
public static void writeStaticField(final Class<?> cls, final String fieldName, final Object value) throws IllegalAccessException {
|
||||
writeStaticField(cls, fieldName, value, false);
|
||||
public static void writeDeclaredField(final Object target, final String fieldName, final Object value) throws IllegalAccessException {
|
||||
writeDeclaredField(target, fieldName, value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a named {@code static} {@link Field}. Superclasses will be considered.
|
||||
* Writes a {@code public} {@link Field}. Only the specified class will be considered.
|
||||
*
|
||||
* @param cls
|
||||
* {@link Class} on which the field is to be found
|
||||
* @param target
|
||||
* the object to reflect, must not be {@code null}
|
||||
* @param fieldName
|
||||
* to write
|
||||
* the field name to obtain
|
||||
* @param value
|
||||
* to set
|
||||
* @param forceAccess
|
||||
* whether to break scope restrictions using the
|
||||
* {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
|
||||
* match {@code public} fields.
|
||||
* @throws NullPointerException
|
||||
* if {@code cls} is {@code null} or the field cannot be located
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code fieldName} is {@code null}, blank or empty, the field not {@code static}, or {@code value} is not assignable
|
||||
* if {@code fieldName} is {@code null}, blank or empty, or could not be found,
|
||||
* or {@code value} is not assignable
|
||||
* @throws IllegalAccessException
|
||||
* if the field is not made accessible or is {@code final}
|
||||
* if the field is not made accessible
|
||||
*/
|
||||
public static void writeStaticField(final Class<?> cls, final String fieldName, final Object value, final boolean forceAccess)
|
||||
public static void writeDeclaredField(final Object target, final String fieldName, final Object value, final boolean forceAccess)
|
||||
throws IllegalAccessException {
|
||||
final Field field = getField(cls, fieldName, forceAccess);
|
||||
Validate.notNull(field, "Cannot locate field %s on %s", fieldName, cls);
|
||||
Objects.requireNonNull(target, "target");
|
||||
final Class<?> cls = target.getClass();
|
||||
final Field field = getDeclaredField(cls, fieldName, forceAccess);
|
||||
Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
|
||||
// already forced access above, don't repeat it here:
|
||||
writeStaticField(field, value, false);
|
||||
writeField(field, target, value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -715,66 +724,6 @@ public class FieldUtils {
|
|||
field.set(target, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the final modifier from a {@link Field}.
|
||||
*
|
||||
* @param field
|
||||
* to remove the final modifier
|
||||
* @throws NullPointerException
|
||||
* if the field is {@code null}
|
||||
* @since 3.2
|
||||
*/
|
||||
public static void removeFinalModifier(final Field field) {
|
||||
removeFinalModifier(field, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the final modifier from a {@link Field}.
|
||||
*
|
||||
* @param field
|
||||
* to remove the final modifier
|
||||
* @param forceAccess
|
||||
* whether to break scope restrictions using the
|
||||
* {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
|
||||
* match {@code public} fields.
|
||||
* @throws NullPointerException
|
||||
* if the field is {@code null}
|
||||
* @deprecated As of Java 12, we can no longer drop the {@code final} modifier, thus
|
||||
* rendering this method obsolete. The JDK discussion about this change can be found
|
||||
* here: https://mail.openjdk.java.net/pipermail/core-libs-dev/2018-November/056486.html
|
||||
* @since 3.3
|
||||
*/
|
||||
@Deprecated
|
||||
public static void removeFinalModifier(final Field field, final boolean forceAccess) {
|
||||
Objects.requireNonNull(field, "field");
|
||||
|
||||
try {
|
||||
if (Modifier.isFinal(field.getModifiers())) {
|
||||
// Do all JREs implement Field with a private ivar called "modifiers"?
|
||||
final Field modifiersField = Field.class.getDeclaredField("modifiers");
|
||||
final boolean doForceAccess = forceAccess && !modifiersField.isAccessible();
|
||||
if (doForceAccess) {
|
||||
modifiersField.setAccessible(true);
|
||||
}
|
||||
try {
|
||||
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
|
||||
} finally {
|
||||
if (doForceAccess) {
|
||||
modifiersField.setAccessible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final NoSuchFieldException | IllegalAccessException e) {
|
||||
if (SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_12)) {
|
||||
throw new UnsupportedOperationException(
|
||||
"In java 12+ final cannot be removed.",
|
||||
e
|
||||
);
|
||||
}
|
||||
// else no exception is thrown because we can modify final.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a {@code public} {@link Field}. Superclasses will be considered.
|
||||
*
|
||||
|
@ -828,52 +777,103 @@ public class FieldUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Writes a {@code public} {@link Field}. Only the specified class will be considered.
|
||||
* Writes a named {@code public static} {@link Field}. Superclasses will be considered.
|
||||
*
|
||||
* @param target
|
||||
* the object to reflect, must not be {@code null}
|
||||
* @param cls
|
||||
* {@link Class} on which the field is to be found
|
||||
* @param fieldName
|
||||
* the field name to obtain
|
||||
* to write
|
||||
* @param value
|
||||
* to set
|
||||
* @throws NullPointerException
|
||||
* if {@code target} is @{code null}
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code fieldName} is {@code null}, blank or empty, or could not be found,
|
||||
* or {@code value} is not assignable
|
||||
* if {@code fieldName} is {@code null}, blank or empty, the field cannot be located or is
|
||||
* not {@code static}, or {@code value} is not assignable
|
||||
* @throws IllegalAccessException
|
||||
* if the field is not made accessible
|
||||
* if the field is not {@code public} or is {@code final}
|
||||
*/
|
||||
public static void writeDeclaredField(final Object target, final String fieldName, final Object value) throws IllegalAccessException {
|
||||
writeDeclaredField(target, fieldName, value, false);
|
||||
public static void writeStaticField(final Class<?> cls, final String fieldName, final Object value) throws IllegalAccessException {
|
||||
writeStaticField(cls, fieldName, value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a {@code public} {@link Field}. Only the specified class will be considered.
|
||||
* Writes a named {@code static} {@link Field}. Superclasses will be considered.
|
||||
*
|
||||
* @param target
|
||||
* the object to reflect, must not be {@code null}
|
||||
* @param cls
|
||||
* {@link Class} on which the field is to be found
|
||||
* @param fieldName
|
||||
* the field name to obtain
|
||||
* to write
|
||||
* @param value
|
||||
* to set
|
||||
* @param forceAccess
|
||||
* whether to break scope restrictions using the
|
||||
* {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
|
||||
* match {@code public} fields.
|
||||
* @throws NullPointerException
|
||||
* if {@code cls} is {@code null} or the field cannot be located
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code fieldName} is {@code null}, blank or empty, or could not be found,
|
||||
* or {@code value} is not assignable
|
||||
* if {@code fieldName} is {@code null}, blank or empty, the field not {@code static}, or {@code value} is not assignable
|
||||
* @throws IllegalAccessException
|
||||
* if the field is not made accessible
|
||||
* if the field is not made accessible or is {@code final}
|
||||
*/
|
||||
public static void writeDeclaredField(final Object target, final String fieldName, final Object value, final boolean forceAccess)
|
||||
public static void writeStaticField(final Class<?> cls, final String fieldName, final Object value, final boolean forceAccess)
|
||||
throws IllegalAccessException {
|
||||
Objects.requireNonNull(target, "target");
|
||||
final Class<?> cls = target.getClass();
|
||||
final Field field = getDeclaredField(cls, fieldName, forceAccess);
|
||||
Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
|
||||
final Field field = getField(cls, fieldName, forceAccess);
|
||||
Validate.notNull(field, "Cannot locate field %s on %s", fieldName, cls);
|
||||
// already forced access above, don't repeat it here:
|
||||
writeField(field, target, value, false);
|
||||
writeStaticField(field, value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a {@code public static} {@link Field}.
|
||||
*
|
||||
* @param field
|
||||
* to write
|
||||
* @param value
|
||||
* to set
|
||||
* @throws NullPointerException
|
||||
* if the field is {@code null}
|
||||
* @throws IllegalArgumentException
|
||||
* if the field is not {@code static}, or {@code value} is not assignable
|
||||
* @throws IllegalAccessException
|
||||
* if the field is not {@code public} or is {@code final}
|
||||
*/
|
||||
public static void writeStaticField(final Field field, final Object value) throws IllegalAccessException {
|
||||
writeStaticField(field, value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a static {@link Field}.
|
||||
*
|
||||
* @param field
|
||||
* to write
|
||||
* @param value
|
||||
* to set
|
||||
* @param forceAccess
|
||||
* whether to break scope restrictions using the
|
||||
* {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
|
||||
* match {@code public} fields.
|
||||
* @throws NullPointerException
|
||||
* if the field is {@code null}
|
||||
* @throws IllegalArgumentException
|
||||
* if the field is not {@code static}, or {@code value} is not assignable
|
||||
* @throws IllegalAccessException
|
||||
* if the field is not made accessible or is {@code final}
|
||||
*/
|
||||
public static void writeStaticField(final Field field, final Object value, final boolean forceAccess) throws IllegalAccessException {
|
||||
Objects.requireNonNull(field, "field");
|
||||
Validate.isTrue(MemberUtils.isStatic(field), "The field %s.%s is not static", field.getDeclaringClass().getName(),
|
||||
field.getName());
|
||||
writeField(field, (Object) null, value, forceAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FieldUtils} instances should NOT be constructed in standard programming.
|
||||
* <p>
|
||||
* This constructor is {@code public} to permit tools that require a JavaBean instance to operate.
|
||||
* </p>
|
||||
*/
|
||||
public FieldUtils() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,17 +25,6 @@ import org.apache.commons.lang3.BooleanUtils;
|
|||
*/
|
||||
public class InheritanceUtils {
|
||||
|
||||
/**
|
||||
* {@link InheritanceUtils} instances should NOT be constructed in standard programming.
|
||||
* Instead, the class should be used as
|
||||
* {@code MethodUtils.getAccessibleMethod(method)}.
|
||||
*
|
||||
* <p>This constructor is {@code public} to permit tools that require a JavaBean
|
||||
* instance to operate.</p>
|
||||
*/
|
||||
public InheritanceUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of inheritance hops between two classes.
|
||||
*
|
||||
|
@ -63,4 +52,15 @@ public class InheritanceUtils {
|
|||
d += distance(cParent, parent);
|
||||
return d > 0 ? d + 1 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link InheritanceUtils} instances should NOT be constructed in standard programming.
|
||||
* Instead, the class should be used as
|
||||
* {@code MethodUtils.getAccessibleMethod(method)}.
|
||||
*
|
||||
* <p>This constructor is {@code public} to permit tools that require a JavaBean
|
||||
* instance to operate.</p>
|
||||
*/
|
||||
public InheritanceUtils() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,77 +33,47 @@ import org.apache.commons.lang3.ClassUtils;
|
|||
final class MemberUtils {
|
||||
// TODO extract an interface to implement compareParameterSets(...)?
|
||||
|
||||
/**
|
||||
* A class providing a subset of the API of java.lang.reflect.Executable in Java 1.8,
|
||||
* providing a common representation for function signatures for Constructors and Methods.
|
||||
*/
|
||||
private static final class Executable {
|
||||
private static Executable of(final Constructor<?> constructor) {
|
||||
return new Executable(constructor);
|
||||
}
|
||||
private static Executable of(final Method method) {
|
||||
return new Executable(method);
|
||||
}
|
||||
|
||||
private final Class<?>[] parameterTypes;
|
||||
|
||||
private final boolean isVarArgs;
|
||||
|
||||
private Executable(final Constructor<?> constructor) {
|
||||
parameterTypes = constructor.getParameterTypes();
|
||||
isVarArgs = constructor.isVarArgs();
|
||||
}
|
||||
|
||||
private Executable(final Method method) {
|
||||
parameterTypes = method.getParameterTypes();
|
||||
isVarArgs = method.isVarArgs();
|
||||
}
|
||||
|
||||
public Class<?>[] getParameterTypes() {
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
public boolean isVarArgs() {
|
||||
return isVarArgs;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int ACCESS_TEST = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
|
||||
|
||||
/** 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 };
|
||||
|
||||
/**
|
||||
* Default access superclass workaround.
|
||||
*
|
||||
* When a {@code public} class has a default access superclass with {@code 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) prevent access even when the modifier is {@code public}.
|
||||
* Calling {@code setAccessible(true)} solves the problem but will only work from
|
||||
* sufficiently privileged code. Better workarounds would be gratefully
|
||||
* accepted.
|
||||
* @param obj the AccessibleObject to set as accessible
|
||||
* @return a boolean indicating whether the accessibility of the object was set to true.
|
||||
*/
|
||||
static <T extends AccessibleObject> T setAccessibleWorkaround(final T obj) {
|
||||
if (obj == null || obj.isAccessible()) {
|
||||
return obj;
|
||||
}
|
||||
final Member m = (Member) obj;
|
||||
if (!obj.isAccessible() && isPublic(m) && isPackageAccess(m.getDeclaringClass().getModifiers())) {
|
||||
try {
|
||||
obj.setAccessible(true);
|
||||
return obj;
|
||||
} catch (final SecurityException ignored) {
|
||||
// ignore in favor of subsequent IllegalAccessException
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a given set of modifiers implies package access.
|
||||
* @param modifiers to test
|
||||
* @return {@code true} unless {@code package}/{@code protected}/{@code private} modifier detected
|
||||
*/
|
||||
static boolean isPackageAccess(final int modifiers) {
|
||||
return (modifiers & ACCESS_TEST) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a {@link Member} is public.
|
||||
* @param member Member to test
|
||||
* @return {@code true} if {@code m} is public
|
||||
*/
|
||||
static boolean isPublic(final Member member) {
|
||||
return member != null && Modifier.isPublic(member.getModifiers());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a {@link Member} is static.
|
||||
* @param member Member to test
|
||||
* @return {@code true} if {@code m} is static
|
||||
*/
|
||||
static boolean isStatic(final Member member) {
|
||||
return member != null && Modifier.isStatic(member.getModifiers());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a {@link Member} is accessible.
|
||||
* @param member Member to test
|
||||
* @return {@code true} if {@code m} is accessible
|
||||
*/
|
||||
static boolean isAccessible(final Member member) {
|
||||
return isPublic(member) && !member.isSynthetic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the relative fitness of two Constructors in terms of how well they
|
||||
* match a set of runtime parameter types, such that a list ordered
|
||||
|
@ -156,52 +126,6 @@ final class MemberUtils {
|
|||
return Float.compare(leftCost, rightCost);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sum of the object transformation cost for each class in the
|
||||
* source argument list.
|
||||
* @param srcArgs The source arguments
|
||||
* @param executable The executable to calculate transformation costs for
|
||||
* @return The total transformation cost
|
||||
*/
|
||||
private static float getTotalTransformationCost(final Class<?>[] srcArgs, final Executable executable) {
|
||||
final Class<?>[] destArgs = executable.getParameterTypes();
|
||||
final boolean isVarArgs = executable.isVarArgs();
|
||||
|
||||
// "source" and "destination" are the actual and declared args respectively.
|
||||
float totalCost = 0.0f;
|
||||
final long normalArgsLen = isVarArgs ? destArgs.length - 1 : destArgs.length;
|
||||
if (srcArgs.length < normalArgsLen) {
|
||||
return Float.MAX_VALUE;
|
||||
}
|
||||
for (int i = 0; i < normalArgsLen; i++) {
|
||||
totalCost += getObjectTransformationCost(srcArgs[i], destArgs[i]);
|
||||
}
|
||||
if (isVarArgs) {
|
||||
// When isVarArgs is true, srcArgs and dstArgs may differ in length.
|
||||
// There are two special cases to consider:
|
||||
final boolean noVarArgsPassed = srcArgs.length < destArgs.length;
|
||||
final boolean explicitArrayForVarargs = srcArgs.length == destArgs.length && srcArgs[srcArgs.length - 1] != null
|
||||
&& srcArgs[srcArgs.length - 1].isArray();
|
||||
|
||||
final float varArgsCost = 0.001f;
|
||||
final Class<?> destClass = destArgs[destArgs.length - 1].getComponentType();
|
||||
if (noVarArgsPassed) {
|
||||
// When no varargs passed, the best match is the most generic matching type, not the most specific.
|
||||
totalCost += getObjectTransformationCost(destClass, Object.class) + varArgsCost;
|
||||
} else if (explicitArrayForVarargs) {
|
||||
final Class<?> sourceClass = srcArgs[srcArgs.length - 1].getComponentType();
|
||||
totalCost += getObjectTransformationCost(sourceClass, destClass) + varArgsCost;
|
||||
} else {
|
||||
// This is typical varargs case.
|
||||
for (int i = destArgs.length - 1; i < srcArgs.length; i++) {
|
||||
final Class<?> srcClass = srcArgs[i];
|
||||
totalCost += getObjectTransformationCost(srcClass, destClass) + varArgsCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
return totalCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of steps needed to turn the source class into
|
||||
* the destination class. This represents the number of steps in the object
|
||||
|
@ -267,8 +191,59 @@ final class MemberUtils {
|
|||
return cost;
|
||||
}
|
||||
|
||||
static boolean isMatchingMethod(final Method method, final Class<?>[] parameterTypes) {
|
||||
return isMatchingExecutable(Executable.of(method), parameterTypes);
|
||||
/**
|
||||
* Returns the sum of the object transformation cost for each class in the
|
||||
* source argument list.
|
||||
* @param srcArgs The source arguments
|
||||
* @param executable The executable to calculate transformation costs for
|
||||
* @return The total transformation cost
|
||||
*/
|
||||
private static float getTotalTransformationCost(final Class<?>[] srcArgs, final Executable executable) {
|
||||
final Class<?>[] destArgs = executable.getParameterTypes();
|
||||
final boolean isVarArgs = executable.isVarArgs();
|
||||
|
||||
// "source" and "destination" are the actual and declared args respectively.
|
||||
float totalCost = 0.0f;
|
||||
final long normalArgsLen = isVarArgs ? destArgs.length - 1 : destArgs.length;
|
||||
if (srcArgs.length < normalArgsLen) {
|
||||
return Float.MAX_VALUE;
|
||||
}
|
||||
for (int i = 0; i < normalArgsLen; i++) {
|
||||
totalCost += getObjectTransformationCost(srcArgs[i], destArgs[i]);
|
||||
}
|
||||
if (isVarArgs) {
|
||||
// When isVarArgs is true, srcArgs and dstArgs may differ in length.
|
||||
// There are two special cases to consider:
|
||||
final boolean noVarArgsPassed = srcArgs.length < destArgs.length;
|
||||
final boolean explicitArrayForVarargs = srcArgs.length == destArgs.length && srcArgs[srcArgs.length - 1] != null
|
||||
&& srcArgs[srcArgs.length - 1].isArray();
|
||||
|
||||
final float varArgsCost = 0.001f;
|
||||
final Class<?> destClass = destArgs[destArgs.length - 1].getComponentType();
|
||||
if (noVarArgsPassed) {
|
||||
// When no varargs passed, the best match is the most generic matching type, not the most specific.
|
||||
totalCost += getObjectTransformationCost(destClass, Object.class) + varArgsCost;
|
||||
} else if (explicitArrayForVarargs) {
|
||||
final Class<?> sourceClass = srcArgs[srcArgs.length - 1].getComponentType();
|
||||
totalCost += getObjectTransformationCost(sourceClass, destClass) + varArgsCost;
|
||||
} else {
|
||||
// This is typical varargs case.
|
||||
for (int i = destArgs.length - 1; i < srcArgs.length; i++) {
|
||||
final Class<?> srcClass = srcArgs[i];
|
||||
totalCost += getObjectTransformationCost(srcClass, destClass) + varArgsCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
return totalCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a {@link Member} is accessible.
|
||||
* @param member Member to test
|
||||
* @return {@code true} if {@code m} is accessible
|
||||
*/
|
||||
static boolean isAccessible(final Member member) {
|
||||
return isPublic(member) && !member.isSynthetic();
|
||||
}
|
||||
|
||||
static boolean isMatchingConstructor(final Constructor<?> method, final Class<?>[] parameterTypes) {
|
||||
|
@ -300,39 +275,64 @@ final class MemberUtils {
|
|||
return false;
|
||||
}
|
||||
|
||||
static boolean isMatchingMethod(final Method method, final Class<?>[] parameterTypes) {
|
||||
return isMatchingExecutable(Executable.of(method), parameterTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* A class providing a subset of the API of java.lang.reflect.Executable in Java 1.8,
|
||||
* providing a common representation for function signatures for Constructors and Methods.
|
||||
* Tests whether a given set of modifiers implies package access.
|
||||
* @param modifiers to test
|
||||
* @return {@code true} unless {@code package}/{@code protected}/{@code private} modifier detected
|
||||
*/
|
||||
private static final class Executable {
|
||||
private final Class<?>[] parameterTypes;
|
||||
private final boolean isVarArgs;
|
||||
static boolean isPackageAccess(final int modifiers) {
|
||||
return (modifiers & ACCESS_TEST) == 0;
|
||||
}
|
||||
|
||||
private static Executable of(final Method method) {
|
||||
return new Executable(method);
|
||||
}
|
||||
/**
|
||||
* Tests whether a {@link Member} is public.
|
||||
* @param member Member to test
|
||||
* @return {@code true} if {@code m} is public
|
||||
*/
|
||||
static boolean isPublic(final Member member) {
|
||||
return member != null && Modifier.isPublic(member.getModifiers());
|
||||
}
|
||||
|
||||
private static Executable of(final Constructor<?> constructor) {
|
||||
return new Executable(constructor);
|
||||
}
|
||||
/**
|
||||
* Tests whether a {@link Member} is static.
|
||||
* @param member Member to test
|
||||
* @return {@code true} if {@code m} is static
|
||||
*/
|
||||
static boolean isStatic(final Member member) {
|
||||
return member != null && Modifier.isStatic(member.getModifiers());
|
||||
}
|
||||
|
||||
private Executable(final Method method) {
|
||||
parameterTypes = method.getParameterTypes();
|
||||
isVarArgs = method.isVarArgs();
|
||||
}
|
||||
|
||||
private Executable(final Constructor<?> constructor) {
|
||||
parameterTypes = constructor.getParameterTypes();
|
||||
isVarArgs = constructor.isVarArgs();
|
||||
}
|
||||
|
||||
public Class<?>[] getParameterTypes() {
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
public boolean isVarArgs() {
|
||||
return isVarArgs;
|
||||
}
|
||||
/**
|
||||
* Default access superclass workaround.
|
||||
*
|
||||
* When a {@code public} class has a default access superclass with {@code 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) prevent access even when the modifier is {@code public}.
|
||||
* Calling {@code setAccessible(true)} solves the problem but will only work from
|
||||
* sufficiently privileged code. Better workarounds would be gratefully
|
||||
* accepted.
|
||||
* @param obj the AccessibleObject to set as accessible
|
||||
* @return a boolean indicating whether the accessibility of the object was set to true.
|
||||
*/
|
||||
static <T extends AccessibleObject> T setAccessibleWorkaround(final T obj) {
|
||||
if (obj == null || obj.isAccessible()) {
|
||||
return obj;
|
||||
}
|
||||
final Member m = (Member) obj;
|
||||
if (!obj.isAccessible() && isPublic(m) && isPackageAccess(m.getDeclaringClass().getModifiers())) {
|
||||
try {
|
||||
obj.setAccessible(true);
|
||||
return obj;
|
||||
} catch (final SecurityException ignored) {
|
||||
// ignore in favor of subsequent IllegalAccessException
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -107,6 +107,11 @@ public abstract class TypeLiteral<T> implements Typed<T> {
|
|||
return TypeUtils.equals(value, other.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 37 << 4 | value.hashCode();
|
||||
|
@ -116,9 +121,4 @@ public abstract class TypeLiteral<T> implements Typed<T> {
|
|||
public String toString() {
|
||||
return toString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,24 @@ public class CompositeFormat extends Format {
|
|||
return formatter.format(obj, toAppendTo, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to the parser Format implementation.
|
||||
*
|
||||
* @return formatter Format implementation
|
||||
*/
|
||||
public Format getFormatter() {
|
||||
return this.formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to the parser Format implementation.
|
||||
*
|
||||
* @return parser Format implementation
|
||||
*/
|
||||
public Format getParser() {
|
||||
return this.parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the parser Format instance.
|
||||
*
|
||||
|
@ -86,24 +104,6 @@ public class CompositeFormat extends Format {
|
|||
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.
|
||||
*
|
||||
|
|
|
@ -111,17 +111,6 @@ public class ExtendedMessageFormat extends MessageFormat {
|
|||
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(final String pattern, final Map<String, ? extends FormatFactory> registry) {
|
||||
this(pattern, Locale.getDefault(), registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ExtendedMessageFormat.
|
||||
*
|
||||
|
@ -138,11 +127,48 @@ public class ExtendedMessageFormat extends MessageFormat {
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
public String toPattern() {
|
||||
return toPattern;
|
||||
public ExtendedMessageFormat(final String pattern, final Map<String, ? extends FormatFactory> registry) {
|
||||
this(pattern, Locale.getDefault(), registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume a quoted string, adding it to {@code appendTo} if
|
||||
* specified.
|
||||
*
|
||||
* @param pattern pattern to parse
|
||||
* @param pos current parse position
|
||||
* @param appendTo optional StringBuilder to append
|
||||
* @return {@code appendTo}
|
||||
*/
|
||||
private StringBuilder appendQuotedString(final String pattern, final ParsePosition pos,
|
||||
final StringBuilder appendTo) {
|
||||
assert pattern.toCharArray()[pos.getIndex()] == QUOTE :
|
||||
"Quoted string must start with quote character";
|
||||
|
||||
// handle quote character at the beginning of the string
|
||||
if (appendTo != null) {
|
||||
appendTo.append(QUOTE);
|
||||
}
|
||||
next(pos);
|
||||
|
||||
final int start = pos.getIndex();
|
||||
final char[] c = pattern.toCharArray();
|
||||
for (int i = pos.getIndex(); i < pattern.length(); i++) {
|
||||
if (c[pos.getIndex()] == QUOTE) {
|
||||
next(pos);
|
||||
return appendTo == null ? null : appendTo.append(c, start,
|
||||
pos.getIndex() - start);
|
||||
}
|
||||
next(pos);
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"Unterminated quoted string at position " + start);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -218,49 +244,15 @@ public class ExtendedMessageFormat extends MessageFormat {
|
|||
}
|
||||
|
||||
/**
|
||||
* Throws UnsupportedOperationException - see class Javadoc for details.
|
||||
*
|
||||
* @param formatElementIndex format element index
|
||||
* @param newFormat the new format
|
||||
* @throws UnsupportedOperationException always thrown since this isn't supported by ExtendMessageFormat
|
||||
* Learn whether the specified Collection contains non-null elements.
|
||||
* @param coll to check
|
||||
* @return {@code true} if some Object was found, {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public void setFormat(final int formatElementIndex, final Format newFormat) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws UnsupportedOperationException - see class Javadoc for details.
|
||||
*
|
||||
* @param argumentIndex argument index
|
||||
* @param newFormat the new format
|
||||
* @throws UnsupportedOperationException always thrown since this isn't supported by ExtendMessageFormat
|
||||
*/
|
||||
@Override
|
||||
public void setFormatByArgumentIndex(final int argumentIndex, final Format newFormat) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws UnsupportedOperationException - see class Javadoc for details.
|
||||
*
|
||||
* @param newFormats new formats
|
||||
* @throws UnsupportedOperationException always thrown since this isn't supported by ExtendMessageFormat
|
||||
*/
|
||||
@Override
|
||||
public void setFormats(final Format[] newFormats) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws UnsupportedOperationException - see class Javadoc for details.
|
||||
*
|
||||
* @param newFormats new formats
|
||||
* @throws UnsupportedOperationException always thrown since this isn't supported by ExtendMessageFormat
|
||||
*/
|
||||
@Override
|
||||
public void setFormatsByArgumentIndex(final Format[] newFormats) {
|
||||
throw new UnsupportedOperationException();
|
||||
private boolean containsElements(final Collection<?> coll) {
|
||||
if (coll == null || coll.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return coll.stream().anyMatch(Objects::nonNull);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -290,17 +282,6 @@ public class ExtendedMessageFormat extends MessageFormat {
|
|||
return !ObjectUtils.notEqual(registry, rhs.registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = HASH_SEED * result + Objects.hashCode(registry);
|
||||
result = HASH_SEED * result + Objects.hashCode(toPattern);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a custom format from a format description.
|
||||
*
|
||||
|
@ -325,79 +306,24 @@ public class ExtendedMessageFormat extends MessageFormat {
|
|||
}
|
||||
|
||||
/**
|
||||
* Read the argument index from the current format element
|
||||
* Consume quoted string only
|
||||
*
|
||||
* @param pattern pattern to parse
|
||||
* @param pos current parse position
|
||||
* @return argument index
|
||||
*/
|
||||
private int readArgumentIndex(final String pattern, final ParsePosition pos) {
|
||||
final int start = pos.getIndex();
|
||||
seekNonWs(pattern, pos);
|
||||
final StringBuilder result = new StringBuilder();
|
||||
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 (final NumberFormatException ignored) {
|
||||
// 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);
|
||||
private void getQuotedString(final String pattern, final ParsePosition pos) {
|
||||
appendQuotedString(pattern, pos, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the format component of a format element.
|
||||
*
|
||||
* @param pattern string to parse
|
||||
* @param pos current parse position
|
||||
* @return Format description String
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
private String parseFormatDescription(final String pattern, final ParsePosition pos) {
|
||||
final int start = pos.getIndex();
|
||||
seekNonWs(pattern, pos);
|
||||
final 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);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"Unterminated format element at position " + start);
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = HASH_SEED * result + Objects.hashCode(registry);
|
||||
result = HASH_SEED * result + Objects.hashCode(toPattern);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -444,6 +370,93 @@ public class ExtendedMessageFormat extends MessageFormat {
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to advance parse position by 1
|
||||
*
|
||||
* @param pos ParsePosition
|
||||
* @return {@code pos}
|
||||
*/
|
||||
private ParsePosition next(final ParsePosition pos) {
|
||||
pos.setIndex(pos.getIndex() + 1);
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(final String pattern, final ParsePosition pos) {
|
||||
final int start = pos.getIndex();
|
||||
seekNonWs(pattern, pos);
|
||||
final 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);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"Unterminated format element at position " + start);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(final String pattern, final ParsePosition pos) {
|
||||
final int start = pos.getIndex();
|
||||
seekNonWs(pattern, pos);
|
||||
final StringBuilder result = new StringBuilder();
|
||||
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 (final NumberFormatException ignored) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume whitespace from the current parse position.
|
||||
*
|
||||
|
@ -460,69 +473,56 @@ public class ExtendedMessageFormat extends MessageFormat {
|
|||
}
|
||||
|
||||
/**
|
||||
* Convenience method to advance parse position by 1
|
||||
* Throws UnsupportedOperationException - see class Javadoc for details.
|
||||
*
|
||||
* @param pos ParsePosition
|
||||
* @return {@code pos}
|
||||
* @param formatElementIndex format element index
|
||||
* @param newFormat the new format
|
||||
* @throws UnsupportedOperationException always thrown since this isn't supported by ExtendMessageFormat
|
||||
*/
|
||||
private ParsePosition next(final ParsePosition pos) {
|
||||
pos.setIndex(pos.getIndex() + 1);
|
||||
return pos;
|
||||
@Override
|
||||
public void setFormat(final int formatElementIndex, final Format newFormat) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume a quoted string, adding it to {@code appendTo} if
|
||||
* specified.
|
||||
* Throws UnsupportedOperationException - see class Javadoc for details.
|
||||
*
|
||||
* @param pattern pattern to parse
|
||||
* @param pos current parse position
|
||||
* @param appendTo optional StringBuilder to append
|
||||
* @return {@code appendTo}
|
||||
* @param argumentIndex argument index
|
||||
* @param newFormat the new format
|
||||
* @throws UnsupportedOperationException always thrown since this isn't supported by ExtendMessageFormat
|
||||
*/
|
||||
private StringBuilder appendQuotedString(final String pattern, final ParsePosition pos,
|
||||
final StringBuilder appendTo) {
|
||||
assert pattern.toCharArray()[pos.getIndex()] == QUOTE :
|
||||
"Quoted string must start with quote character";
|
||||
|
||||
// handle quote character at the beginning of the string
|
||||
if (appendTo != null) {
|
||||
appendTo.append(QUOTE);
|
||||
}
|
||||
next(pos);
|
||||
|
||||
final int start = pos.getIndex();
|
||||
final char[] c = pattern.toCharArray();
|
||||
for (int i = pos.getIndex(); i < pattern.length(); i++) {
|
||||
if (c[pos.getIndex()] == QUOTE) {
|
||||
next(pos);
|
||||
return appendTo == null ? null : appendTo.append(c, start,
|
||||
pos.getIndex() - start);
|
||||
}
|
||||
next(pos);
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"Unterminated quoted string at position " + start);
|
||||
@Override
|
||||
public void setFormatByArgumentIndex(final int argumentIndex, final Format newFormat) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume quoted string only
|
||||
* Throws UnsupportedOperationException - see class Javadoc for details.
|
||||
*
|
||||
* @param pattern pattern to parse
|
||||
* @param pos current parse position
|
||||
* @param newFormats new formats
|
||||
* @throws UnsupportedOperationException always thrown since this isn't supported by ExtendMessageFormat
|
||||
*/
|
||||
private void getQuotedString(final String pattern, final ParsePosition pos) {
|
||||
appendQuotedString(pattern, pos, null);
|
||||
@Override
|
||||
public void setFormats(final Format[] newFormats) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Learn whether the specified Collection contains non-null elements.
|
||||
* @param coll to check
|
||||
* @return {@code true} if some Object was found, {@code false} otherwise.
|
||||
* Throws UnsupportedOperationException - see class Javadoc for details.
|
||||
*
|
||||
* @param newFormats new formats
|
||||
* @throws UnsupportedOperationException always thrown since this isn't supported by ExtendMessageFormat
|
||||
*/
|
||||
private boolean containsElements(final Collection<?> coll) {
|
||||
if (coll == null || coll.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return coll.stream().anyMatch(Objects::nonNull);
|
||||
@Override
|
||||
public void setFormatsByArgumentIndex(final Format[] newFormats) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toPattern() {
|
||||
return toPattern;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,28 +44,6 @@ public class FormattableUtils {
|
|||
*/
|
||||
private static final String SIMPLEST_FORMAT = "%s";
|
||||
|
||||
/**
|
||||
* {@link FormattableUtils} instances should NOT be constructed in
|
||||
* standard programming. Instead, the methods of the class should be invoked
|
||||
* statically.
|
||||
*
|
||||
* <p>This constructor is public to permit tools that require a JavaBean
|
||||
* instance to operate.</p>
|
||||
*/
|
||||
public FormattableUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default formatted representation of the specified
|
||||
* {@link Formattable}.
|
||||
*
|
||||
* @param formattable the instance to convert to a string, not null
|
||||
* @return the resulting string, not null
|
||||
*/
|
||||
public static String toString(final Formattable formattable) {
|
||||
return String.format(SIMPLEST_FORMAT, formattable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the common {@link Formattable} operations of truncate-pad-append,
|
||||
* with no ellipsis on precision overflow, and padding width underflow with
|
||||
|
@ -100,24 +78,6 @@ public class FormattableUtils {
|
|||
return append(seq, formatter, flags, width, precision, padChar, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the common {@link Formattable} operations of truncate-pad-append,
|
||||
* padding width underflow with spaces.
|
||||
*
|
||||
* @param seq the string to handle, not null
|
||||
* @param formatter the destination formatter, not null
|
||||
* @param flags the flags for formatting, see {@link Formattable}
|
||||
* @param width the width of the output, see {@link Formattable}
|
||||
* @param precision the precision of the output, see {@link Formattable}
|
||||
* @param ellipsis the ellipsis to use when precision dictates truncation, null or
|
||||
* empty causes a hard truncation
|
||||
* @return the {@code formatter} instance, not null
|
||||
*/
|
||||
public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
|
||||
final int precision, final CharSequence ellipsis) {
|
||||
return append(seq, formatter, flags, width, precision, ' ', ellipsis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the common {@link Formattable} operations of truncate-pad-append.
|
||||
*
|
||||
|
@ -148,4 +108,44 @@ public class FormattableUtils {
|
|||
return formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the common {@link Formattable} operations of truncate-pad-append,
|
||||
* padding width underflow with spaces.
|
||||
*
|
||||
* @param seq the string to handle, not null
|
||||
* @param formatter the destination formatter, not null
|
||||
* @param flags the flags for formatting, see {@link Formattable}
|
||||
* @param width the width of the output, see {@link Formattable}
|
||||
* @param precision the precision of the output, see {@link Formattable}
|
||||
* @param ellipsis the ellipsis to use when precision dictates truncation, null or
|
||||
* empty causes a hard truncation
|
||||
* @return the {@code formatter} instance, not null
|
||||
*/
|
||||
public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
|
||||
final int precision, final CharSequence ellipsis) {
|
||||
return append(seq, formatter, flags, width, precision, ' ', ellipsis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default formatted representation of the specified
|
||||
* {@link Formattable}.
|
||||
*
|
||||
* @param formattable the instance to convert to a string, not null
|
||||
* @return the resulting string, not null
|
||||
*/
|
||||
public static String toString(final Formattable formattable) {
|
||||
return String.format(SIMPLEST_FORMAT, formattable);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FormattableUtils} instances should NOT be constructed in
|
||||
* standard programming. Instead, the methods of the class should be invoked
|
||||
* statically.
|
||||
*
|
||||
* <p>This constructor is public to permit tools that require a JavaBean
|
||||
* instance to operate.</p>
|
||||
*/
|
||||
public FormattableUtils() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -46,91 +46,6 @@ import org.apache.commons.lang3.SystemProperties;
|
|||
@Deprecated
|
||||
public abstract class StrLookup<V> {
|
||||
|
||||
/**
|
||||
* Lookup that always returns null.
|
||||
*/
|
||||
private static final StrLookup<String> NONE_LOOKUP = new MapStrLookup<>(null);
|
||||
|
||||
/**
|
||||
* Lookup based on system properties.
|
||||
*/
|
||||
private static final StrLookup<String> SYSTEM_PROPERTIES_LOOKUP = new SystemPropertiesStrLookup();
|
||||
|
||||
/**
|
||||
* 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 new lookup which uses a copy of the current
|
||||
* {@link System#getProperties() System properties}.
|
||||
* <p>
|
||||
* If a security manager blocked access to system properties, then null will
|
||||
* be returned from every lookup.
|
||||
* </p>
|
||||
* <p>
|
||||
* If a null key is used, this lookup will throw a NullPointerException.
|
||||
* </p>
|
||||
*
|
||||
* @return a lookup using system properties, not null
|
||||
*/
|
||||
public static StrLookup<String> systemPropertiesLookup() {
|
||||
return SYSTEM_PROPERTIES_LOOKUP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a lookup which looks up values using a map.
|
||||
* <p>
|
||||
* If the map is null, then null will be returned from every lookup.
|
||||
* The map result object is converted to a string using toString().
|
||||
* </p>
|
||||
*
|
||||
* @param <V> the type of the values supported by the lookup
|
||||
* @param map the map of keys to values, may be null
|
||||
* @return a lookup using the map, not null
|
||||
*/
|
||||
public static <V> StrLookup<V> mapLookup(final Map<String, V> map) {
|
||||
return new MapStrLookup<>(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
protected StrLookup() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a String key to a String value.
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
* <p>
|
||||
* The {@link #lookup(String)} method always returns a String, regardless of
|
||||
* the underlying data, by converting it as necessary. For example:
|
||||
* </p>
|
||||
* <pre>
|
||||
* Map<String, Object> map = new HashMap<String, Object>();
|
||||
* map.put("number", Integer.valueOf(2));
|
||||
* assertEquals("2", StrLookup.mapLookup(map).lookup("number"));
|
||||
* </pre>
|
||||
* @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.
|
||||
*
|
||||
|
@ -181,4 +96,89 @@ public abstract class StrLookup<V> {
|
|||
return SystemProperties.getProperty(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup that always returns null.
|
||||
*/
|
||||
private static final StrLookup<String> NONE_LOOKUP = new MapStrLookup<>(null);
|
||||
|
||||
/**
|
||||
* Lookup based on system properties.
|
||||
*/
|
||||
private static final StrLookup<String> SYSTEM_PROPERTIES_LOOKUP = new SystemPropertiesStrLookup();
|
||||
|
||||
/**
|
||||
* Returns a lookup which looks up values using a map.
|
||||
* <p>
|
||||
* If the map is null, then null will be returned from every lookup.
|
||||
* The map result object is converted to a string using toString().
|
||||
* </p>
|
||||
*
|
||||
* @param <V> the type of the values supported by the lookup
|
||||
* @param map the map of keys to values, may be null
|
||||
* @return a lookup using the map, not null
|
||||
*/
|
||||
public static <V> StrLookup<V> mapLookup(final Map<String, V> map) {
|
||||
return new MapStrLookup<>(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 new lookup which uses a copy of the current
|
||||
* {@link System#getProperties() System properties}.
|
||||
* <p>
|
||||
* If a security manager blocked access to system properties, then null will
|
||||
* be returned from every lookup.
|
||||
* </p>
|
||||
* <p>
|
||||
* If a null key is used, this lookup will throw a NullPointerException.
|
||||
* </p>
|
||||
*
|
||||
* @return a lookup using system properties, not null
|
||||
*/
|
||||
public static StrLookup<String> systemPropertiesLookup() {
|
||||
return SYSTEM_PROPERTIES_LOOKUP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
protected StrLookup() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a String key to a String value.
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
* <p>
|
||||
* The {@link #lookup(String)} method always returns a String, regardless of
|
||||
* the underlying data, by converting it as necessary. For example:
|
||||
* </p>
|
||||
* <pre>
|
||||
* Map<String, Object> map = new HashMap<String, Object>();
|
||||
* map.put("number", Integer.valueOf(2));
|
||||
* assertEquals("2", StrLookup.mapLookup(map).lookup("number"));
|
||||
* </pre>
|
||||
* @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);
|
||||
}
|
||||
|
|
|
@ -39,244 +39,35 @@ import org.apache.commons.lang3.StringUtils;
|
|||
public abstract class StrMatcher {
|
||||
|
||||
/**
|
||||
* Matches the comma character.
|
||||
* Class used to define a character for matching purposes.
|
||||
*/
|
||||
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();
|
||||
static final class CharMatcher extends StrMatcher {
|
||||
/** The character to match. */
|
||||
private final char ch;
|
||||
|
||||
/**
|
||||
* 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(final 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(final char... chars) {
|
||||
if (ArrayUtils.isEmpty(chars)) {
|
||||
return NONE_MATCHER;
|
||||
/**
|
||||
* Constructor that creates a matcher that matches a single character.
|
||||
*
|
||||
* @param ch the character to match
|
||||
*/
|
||||
CharMatcher(final char ch) {
|
||||
this.ch = ch;
|
||||
}
|
||||
if (chars.length == 1) {
|
||||
return new CharMatcher(chars[0]);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@Override
|
||||
public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
|
||||
return ch == buffer[pos] ? 1 : 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(final String chars) {
|
||||
if (StringUtils.isEmpty(chars)) {
|
||||
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(final String str) {
|
||||
if (StringUtils.isEmpty(str)) {
|
||||
return NONE_MATCHER;
|
||||
}
|
||||
return new StringMatcher(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
protected StrMatcher() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of matching characters, zero for no match.
|
||||
* <p>
|
||||
* This method is called to check for a match.
|
||||
* The parameter {@code pos} represents the current position to be
|
||||
* checked in the string {@code buffer} (a character array which must
|
||||
* not be changed).
|
||||
* The API guarantees that {@code pos} is a valid index for {@code buffer}.
|
||||
* </p>
|
||||
* <p>
|
||||
* The character array may be larger than the active area to be matched.
|
||||
* Only values in the buffer between the specified indices may be accessed.
|
||||
* </p>
|
||||
* <p>
|
||||
* The matching code may check one character or many.
|
||||
* It may check characters preceding {@code pos} as well as those
|
||||
* after, so long as no checks exceed the bounds specified.
|
||||
* </p>
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* @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.
|
||||
* <p>
|
||||
* This method is called to check for a match.
|
||||
* The parameter {@code pos} represents the current position to be
|
||||
* checked in the string {@code buffer} (a character array which must
|
||||
* not be changed).
|
||||
* The API guarantees that {@code pos} is a valid index for {@code buffer}.
|
||||
* </p>
|
||||
* <p>
|
||||
* The matching code may check one character or many.
|
||||
* It may check characters preceding {@code pos} as well as those after.
|
||||
* </p>
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* @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(final char[] buffer, final int pos) {
|
||||
return isMatch(buffer, pos, 0, buffer.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class used to define a set of characters for matching purposes.
|
||||
*/
|
||||
|
@ -307,25 +98,19 @@ public abstract class StrMatcher {
|
|||
return Arrays.binarySearch(chars, buffer[pos]) >= 0 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class used to define a character for matching purposes.
|
||||
* Class used to match no characters.
|
||||
*/
|
||||
static final class CharMatcher extends StrMatcher {
|
||||
/** The character to match. */
|
||||
private final char ch;
|
||||
static final class NoMatcher extends StrMatcher {
|
||||
|
||||
/**
|
||||
* Constructor that creates a matcher that matches a single character.
|
||||
*
|
||||
* @param ch the character to match
|
||||
* Constructs a new instance of {@link NoMatcher}.
|
||||
*/
|
||||
CharMatcher(final char ch) {
|
||||
this.ch = ch;
|
||||
NoMatcher() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the given character matches.
|
||||
* Always returns {@code false}.
|
||||
*
|
||||
* @param buffer the text content to match against, do not change
|
||||
* @param pos the starting position for the match, valid for buffer
|
||||
|
@ -335,10 +120,9 @@ public abstract class StrMatcher {
|
|||
*/
|
||||
@Override
|
||||
public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
|
||||
return ch == buffer[pos] ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class used to define a set of characters for matching purposes.
|
||||
*/
|
||||
|
@ -384,33 +168,6 @@ public abstract class StrMatcher {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Class used to match no characters.
|
||||
*/
|
||||
static final class NoMatcher extends StrMatcher {
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link NoMatcher}.
|
||||
*/
|
||||
NoMatcher() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns {@code 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
|
||||
*/
|
||||
@Override
|
||||
public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class used to match whitespace as per trim().
|
||||
*/
|
||||
|
@ -436,5 +193,248 @@ public abstract class StrMatcher {
|
|||
return buffer[pos] <= 32 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* 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(final 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(final char... chars) {
|
||||
if (ArrayUtils.isEmpty(chars)) {
|
||||
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(final String chars) {
|
||||
if (StringUtils.isEmpty(chars)) {
|
||||
return NONE_MATCHER;
|
||||
}
|
||||
if (chars.length() == 1) {
|
||||
return new CharMatcher(chars.charAt(0));
|
||||
}
|
||||
return new CharSetMatcher(chars.toCharArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 double quote character.
|
||||
*
|
||||
* @return a matcher for a double quote
|
||||
*/
|
||||
public static StrMatcher doubleQuoteMatcher() {
|
||||
return DOUBLE_QUOTE_MATCHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches no characters.
|
||||
*
|
||||
* @return a matcher that matches nothing
|
||||
*/
|
||||
public static StrMatcher noneMatcher() {
|
||||
return NONE_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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(final String str) {
|
||||
if (StringUtils.isEmpty(str)) {
|
||||
return NONE_MATCHER;
|
||||
}
|
||||
return new StringMatcher(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a matcher which matches the tab character.
|
||||
*
|
||||
* @return a matcher for a tab
|
||||
*/
|
||||
public static StrMatcher tabMatcher() {
|
||||
return TAB_MATCHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the String trim() whitespace characters.
|
||||
*
|
||||
* @return the trim matcher
|
||||
*/
|
||||
public static StrMatcher trimMatcher() {
|
||||
return TRIM_MATCHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
protected StrMatcher() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of matching characters, zero for no match.
|
||||
* <p>
|
||||
* This method is called to check for a match.
|
||||
* The parameter {@code pos} represents the current position to be
|
||||
* checked in the string {@code buffer} (a character array which must
|
||||
* not be changed).
|
||||
* The API guarantees that {@code pos} is a valid index for {@code buffer}.
|
||||
* </p>
|
||||
* <p>
|
||||
* The matching code may check one character or many.
|
||||
* It may check characters preceding {@code pos} as well as those after.
|
||||
* </p>
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* @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(final char[] buffer, final int pos) {
|
||||
return isMatch(buffer, pos, 0, buffer.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of matching characters, zero for no match.
|
||||
* <p>
|
||||
* This method is called to check for a match.
|
||||
* The parameter {@code pos} represents the current position to be
|
||||
* checked in the string {@code buffer} (a character array which must
|
||||
* not be changed).
|
||||
* The API guarantees that {@code pos} is a valid index for {@code buffer}.
|
||||
* </p>
|
||||
* <p>
|
||||
* The character array may be larger than the active area to be matched.
|
||||
* Only values in the buffer between the specified indices may be accessed.
|
||||
* </p>
|
||||
* <p>
|
||||
* The matching code may check one character or many.
|
||||
* It may check characters preceding {@code pos} as well as those
|
||||
* after, so long as no checks exceed the bounds specified.
|
||||
* </p>
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* @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);
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -37,15 +37,375 @@ import org.apache.commons.lang3.StringUtils;
|
|||
@Deprecated
|
||||
public class WordUtils {
|
||||
|
||||
// Capitalizing
|
||||
/**
|
||||
* {@link WordUtils} instances should NOT be constructed in
|
||||
* standard programming. Instead, the class should be used as
|
||||
* {@code WordUtils.wrap("foo bar", 20);}.
|
||||
* Capitalizes all the whitespace separated words in a String.
|
||||
* Only the first character of each word is changed. To convert the
|
||||
* rest of each word to lowercase at the same time,
|
||||
* use {@link #capitalizeFully(String)}.
|
||||
*
|
||||
* <p>This constructor is public to permit tools that require a JavaBean
|
||||
* instance to operate.</p>
|
||||
* <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
|
||||
* A {@code null} input String returns {@code null}.
|
||||
* Capitalization uses the Unicode title case, normally equivalent to
|
||||
* upper case.</p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.capitalize(null) = null
|
||||
* WordUtils.capitalize("") = ""
|
||||
* WordUtils.capitalize("i am FINE") = "I Am FINE"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to capitalize, may be null
|
||||
* @return capitalized String, {@code null} if null String input
|
||||
* @see #uncapitalize(String)
|
||||
* @see #capitalizeFully(String)
|
||||
*/
|
||||
public WordUtils() {
|
||||
public static String capitalize(final String str) {
|
||||
return capitalize(str, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Capitalizes all the delimiter separated words in a String.
|
||||
* Only the first character of each word is changed. To convert the
|
||||
* rest of each word to lowercase at the same time,
|
||||
* use {@link #capitalizeFully(String, char[])}.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>A {@code null} input String returns {@code null}.
|
||||
* Capitalization uses the Unicode title case, normally equivalent to
|
||||
* upper case.</p>
|
||||
*
|
||||
* <pre>
|
||||
* 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"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to capitalize, may be null
|
||||
* @param delimiters set of characters to determine capitalization, null means whitespace
|
||||
* @return capitalized String, {@code null} if null String input
|
||||
* @see #uncapitalize(String)
|
||||
* @see #capitalizeFully(String)
|
||||
* @since 2.1
|
||||
*/
|
||||
public static String capitalize(final String str, final char... delimiters) {
|
||||
final int delimLen = delimiters == null ? -1 : delimiters.length;
|
||||
if (StringUtils.isEmpty(str) || delimLen == 0) {
|
||||
return str;
|
||||
}
|
||||
final char[] buffer = str.toCharArray();
|
||||
boolean capitalizeNext = true;
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
final char ch = buffer[i];
|
||||
if (isDelimiter(ch, delimiters)) {
|
||||
capitalizeNext = true;
|
||||
} else if (capitalizeNext) {
|
||||
buffer[i] = Character.toTitleCase(ch);
|
||||
capitalizeNext = false;
|
||||
}
|
||||
}
|
||||
return new String(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
|
||||
* A {@code null} input String returns {@code null}.
|
||||
* Capitalization uses the Unicode title case, normally equivalent to
|
||||
* upper case.</p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.capitalizeFully(null) = null
|
||||
* WordUtils.capitalizeFully("") = ""
|
||||
* WordUtils.capitalizeFully("i am FINE") = "I Am Fine"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to capitalize, may be null
|
||||
* @return capitalized String, {@code null} if null String input
|
||||
*/
|
||||
public static String capitalizeFully(final 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.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>A {@code null} input String returns {@code null}.
|
||||
* Capitalization uses the Unicode title case, normally equivalent to
|
||||
* upper case.</p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.capitalizeFully(null, *) = null
|
||||
* WordUtils.capitalizeFully("", *) = ""
|
||||
* WordUtils.capitalizeFully(*, null) = *
|
||||
* WordUtils.capitalizeFully(*, new char[0]) = *
|
||||
* WordUtils.capitalizeFully("i aM.fine", {'.'}) = "I am.Fine"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to capitalize, may be null
|
||||
* @param delimiters set of characters to determine capitalization, null means whitespace
|
||||
* @return capitalized String, {@code null} if null String input
|
||||
* @since 2.1
|
||||
*/
|
||||
public static String capitalizeFully(final String str, final char... delimiters) {
|
||||
final int delimLen = delimiters == null ? -1 : delimiters.length;
|
||||
if (StringUtils.isEmpty(str) || delimLen == 0) {
|
||||
return str;
|
||||
}
|
||||
return capitalize(str.toLowerCase(), delimiters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the String contains all words in the given array.
|
||||
*
|
||||
* <p>
|
||||
* A {@code null} String will return {@code false}. A {@code null}, zero
|
||||
* length search array or if one element of array is null will return {@code false}.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.containsAllWords(null, *) = false
|
||||
* WordUtils.containsAllWords("", *) = false
|
||||
* WordUtils.containsAllWords(*, null) = false
|
||||
* WordUtils.containsAllWords(*, []) = false
|
||||
* WordUtils.containsAllWords("abcd", "ab", "cd") = false
|
||||
* WordUtils.containsAllWords("abc def", "def", "abc") = true
|
||||
* </pre>
|
||||
*
|
||||
* @param word The CharSequence to check, may be null
|
||||
* @param words The array of String words to search for, may be null
|
||||
* @return {@code true} if all search words are found, {@code false} otherwise
|
||||
* @since 3.5
|
||||
*/
|
||||
public static boolean containsAllWords(final CharSequence word, final CharSequence... words) {
|
||||
if (StringUtils.isEmpty(word) || ArrayUtils.isEmpty(words)) {
|
||||
return false;
|
||||
}
|
||||
for (final CharSequence w : words) {
|
||||
if (StringUtils.isBlank(w)) {
|
||||
return false;
|
||||
}
|
||||
final Pattern p = Pattern.compile(".*\\b" + w + "\\b.*");
|
||||
if (!p.matcher(word).matches()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the initial characters from each word in the String.
|
||||
*
|
||||
* <p>All first characters after whitespace are returned as a new string.
|
||||
* Their case is not changed.</p>
|
||||
*
|
||||
* <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
|
||||
* A {@code null} input String returns {@code null}.</p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.initials(null) = null
|
||||
* WordUtils.initials("") = ""
|
||||
* WordUtils.initials("Ben John Lee") = "BJL"
|
||||
* WordUtils.initials("Ben J.Lee") = "BJ"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to get initials from, may be null
|
||||
* @return String of initial letters, {@code null} if null String input
|
||||
* @see #initials(String,char[])
|
||||
* @since 2.2
|
||||
*/
|
||||
public static String initials(final String str) {
|
||||
return initials(str, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the initial characters from each word in the String.
|
||||
*
|
||||
* <p>All first characters after the defined delimiters are returned as a new string.
|
||||
* Their case is not changed.</p>
|
||||
*
|
||||
* <p>If the delimiters array is null, then Whitespace is used.
|
||||
* Whitespace is defined by {@link Character#isWhitespace(char)}.
|
||||
* A {@code null} input String returns {@code null}.
|
||||
* An empty delimiter array returns an empty String.</p>
|
||||
*
|
||||
* <pre>
|
||||
* 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]) = ""
|
||||
* </pre>
|
||||
*
|
||||
* @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 characters, {@code null} if null String input
|
||||
* @see #initials(String)
|
||||
* @since 2.2
|
||||
*/
|
||||
public static String initials(final String str, final char... delimiters) {
|
||||
if (StringUtils.isEmpty(str)) {
|
||||
return str;
|
||||
}
|
||||
if (delimiters != null && delimiters.length == 0) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
final int strLen = str.length();
|
||||
final char[] buf = new char[strLen / 2 + 1];
|
||||
int count = 0;
|
||||
boolean lastWasGap = true;
|
||||
for (int i = 0; i < strLen; i++) {
|
||||
final char ch = str.charAt(i);
|
||||
if (isDelimiter(ch, delimiters)) {
|
||||
lastWasGap = true;
|
||||
} else if (lastWasGap) {
|
||||
buf[count++] = ch;
|
||||
lastWasGap = false;
|
||||
} else {
|
||||
continue; // ignore ch
|
||||
}
|
||||
}
|
||||
return new String(buf, 0, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the character is a delimiter.
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @param delimiters the delimiters
|
||||
* @return true if it is a delimiter
|
||||
*/
|
||||
private static boolean isDelimiter(final char ch, final char[] delimiters) {
|
||||
return delimiters == null ? Character.isWhitespace(ch) : ArrayUtils.contains(delimiters, ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps the case of a String using a word based algorithm.
|
||||
*
|
||||
* <ul>
|
||||
* <li>Upper case character converts to Lower case</li>
|
||||
* <li>Title case character converts to Lower case</li>
|
||||
* <li>Lower case character after Whitespace or at start converts to Title case</li>
|
||||
* <li>Other Lower case character converts to Upper case</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
|
||||
* A {@code null} input String returns {@code null}.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtils.swapCase(null) = null
|
||||
* StringUtils.swapCase("") = ""
|
||||
* StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to swap case, may be null
|
||||
* @return the changed String, {@code null} if null String input
|
||||
*/
|
||||
public static String swapCase(final String str) {
|
||||
if (StringUtils.isEmpty(str)) {
|
||||
return str;
|
||||
}
|
||||
final char[] buffer = str.toCharArray();
|
||||
|
||||
boolean whitespace = true;
|
||||
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
final char ch = buffer[i];
|
||||
if (Character.isUpperCase(ch) || Character.isTitleCase(ch)) {
|
||||
buffer[i] = Character.toLowerCase(ch);
|
||||
whitespace = false;
|
||||
} else if (Character.isLowerCase(ch)) {
|
||||
if (whitespace) {
|
||||
buffer[i] = Character.toTitleCase(ch);
|
||||
whitespace = false;
|
||||
} else {
|
||||
buffer[i] = Character.toUpperCase(ch);
|
||||
}
|
||||
} else {
|
||||
whitespace = Character.isWhitespace(ch);
|
||||
}
|
||||
}
|
||||
return new String(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uncapitalizes all the whitespace separated words in a String.
|
||||
* Only the first character of each word is changed.
|
||||
*
|
||||
* <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
|
||||
* A {@code null} input String returns {@code null}.</p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.uncapitalize(null) = null
|
||||
* WordUtils.uncapitalize("") = ""
|
||||
* WordUtils.uncapitalize("I Am FINE") = "i am fINE"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to uncapitalize, may be null
|
||||
* @return uncapitalized String, {@code null} if null String input
|
||||
* @see #capitalize(String)
|
||||
*/
|
||||
public static String uncapitalize(final String str) {
|
||||
return uncapitalize(str, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uncapitalizes all the whitespace separated words in a String.
|
||||
* Only the first character of each word is changed.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
|
||||
* A {@code null} input String returns {@code null}.</p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.uncapitalize(null, *) = null
|
||||
* WordUtils.uncapitalize("", *) = ""
|
||||
* WordUtils.uncapitalize(*, null) = *
|
||||
* WordUtils.uncapitalize(*, new char[0]) = *
|
||||
* WordUtils.uncapitalize("I AM.FINE", {'.'}) = "i AM.fINE"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to uncapitalize, may be null
|
||||
* @param delimiters set of characters to determine uncapitalization, null means whitespace
|
||||
* @return uncapitalized String, {@code null} if null String input
|
||||
* @see #capitalize(String)
|
||||
* @since 2.1
|
||||
*/
|
||||
public static String uncapitalize(final String str, final char... delimiters) {
|
||||
final int delimLen = delimiters == null ? -1 : delimiters.length;
|
||||
if (StringUtils.isEmpty(str) || delimLen == 0) {
|
||||
return str;
|
||||
}
|
||||
final char[] buffer = str.toCharArray();
|
||||
boolean uncapitalizeNext = true;
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
final char ch = buffer[i];
|
||||
if (isDelimiter(ch, delimiters)) {
|
||||
uncapitalizeNext = true;
|
||||
} else if (uncapitalizeNext) {
|
||||
buffer[i] = Character.toLowerCase(ch);
|
||||
uncapitalizeNext = false;
|
||||
}
|
||||
}
|
||||
return new String(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -343,375 +703,15 @@ public class WordUtils {
|
|||
return wrappedLine.toString();
|
||||
}
|
||||
|
||||
// Capitalizing
|
||||
/**
|
||||
* Capitalizes all the whitespace separated words in a String.
|
||||
* Only the first character of each word is changed. To convert the
|
||||
* rest of each word to lowercase at the same time,
|
||||
* use {@link #capitalizeFully(String)}.
|
||||
* {@link WordUtils} instances should NOT be constructed in
|
||||
* standard programming. Instead, the class should be used as
|
||||
* {@code WordUtils.wrap("foo bar", 20);}.
|
||||
*
|
||||
* <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
|
||||
* A {@code null} input String returns {@code null}.
|
||||
* Capitalization uses the Unicode title case, normally equivalent to
|
||||
* upper case.</p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.capitalize(null) = null
|
||||
* WordUtils.capitalize("") = ""
|
||||
* WordUtils.capitalize("i am FINE") = "I Am FINE"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to capitalize, may be null
|
||||
* @return capitalized String, {@code null} if null String input
|
||||
* @see #uncapitalize(String)
|
||||
* @see #capitalizeFully(String)
|
||||
* <p>This constructor is public to permit tools that require a JavaBean
|
||||
* instance to operate.</p>
|
||||
*/
|
||||
public static String capitalize(final String str) {
|
||||
return capitalize(str, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Capitalizes all the delimiter separated words in a String.
|
||||
* Only the first character of each word is changed. To convert the
|
||||
* rest of each word to lowercase at the same time,
|
||||
* use {@link #capitalizeFully(String, char[])}.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>A {@code null} input String returns {@code null}.
|
||||
* Capitalization uses the Unicode title case, normally equivalent to
|
||||
* upper case.</p>
|
||||
*
|
||||
* <pre>
|
||||
* 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"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to capitalize, may be null
|
||||
* @param delimiters set of characters to determine capitalization, null means whitespace
|
||||
* @return capitalized String, {@code null} if null String input
|
||||
* @see #uncapitalize(String)
|
||||
* @see #capitalizeFully(String)
|
||||
* @since 2.1
|
||||
*/
|
||||
public static String capitalize(final String str, final char... delimiters) {
|
||||
final int delimLen = delimiters == null ? -1 : delimiters.length;
|
||||
if (StringUtils.isEmpty(str) || delimLen == 0) {
|
||||
return str;
|
||||
}
|
||||
final char[] buffer = str.toCharArray();
|
||||
boolean capitalizeNext = true;
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
final char ch = buffer[i];
|
||||
if (isDelimiter(ch, delimiters)) {
|
||||
capitalizeNext = true;
|
||||
} else if (capitalizeNext) {
|
||||
buffer[i] = Character.toTitleCase(ch);
|
||||
capitalizeNext = false;
|
||||
}
|
||||
}
|
||||
return new String(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
|
||||
* A {@code null} input String returns {@code null}.
|
||||
* Capitalization uses the Unicode title case, normally equivalent to
|
||||
* upper case.</p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.capitalizeFully(null) = null
|
||||
* WordUtils.capitalizeFully("") = ""
|
||||
* WordUtils.capitalizeFully("i am FINE") = "I Am Fine"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to capitalize, may be null
|
||||
* @return capitalized String, {@code null} if null String input
|
||||
*/
|
||||
public static String capitalizeFully(final 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.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>A {@code null} input String returns {@code null}.
|
||||
* Capitalization uses the Unicode title case, normally equivalent to
|
||||
* upper case.</p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.capitalizeFully(null, *) = null
|
||||
* WordUtils.capitalizeFully("", *) = ""
|
||||
* WordUtils.capitalizeFully(*, null) = *
|
||||
* WordUtils.capitalizeFully(*, new char[0]) = *
|
||||
* WordUtils.capitalizeFully("i aM.fine", {'.'}) = "I am.Fine"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to capitalize, may be null
|
||||
* @param delimiters set of characters to determine capitalization, null means whitespace
|
||||
* @return capitalized String, {@code null} if null String input
|
||||
* @since 2.1
|
||||
*/
|
||||
public static String capitalizeFully(final String str, final char... delimiters) {
|
||||
final int delimLen = delimiters == null ? -1 : delimiters.length;
|
||||
if (StringUtils.isEmpty(str) || delimLen == 0) {
|
||||
return str;
|
||||
}
|
||||
return capitalize(str.toLowerCase(), delimiters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uncapitalizes all the whitespace separated words in a String.
|
||||
* Only the first character of each word is changed.
|
||||
*
|
||||
* <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
|
||||
* A {@code null} input String returns {@code null}.</p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.uncapitalize(null) = null
|
||||
* WordUtils.uncapitalize("") = ""
|
||||
* WordUtils.uncapitalize("I Am FINE") = "i am fINE"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to uncapitalize, may be null
|
||||
* @return uncapitalized String, {@code null} if null String input
|
||||
* @see #capitalize(String)
|
||||
*/
|
||||
public static String uncapitalize(final String str) {
|
||||
return uncapitalize(str, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uncapitalizes all the whitespace separated words in a String.
|
||||
* Only the first character of each word is changed.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
|
||||
* A {@code null} input String returns {@code null}.</p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.uncapitalize(null, *) = null
|
||||
* WordUtils.uncapitalize("", *) = ""
|
||||
* WordUtils.uncapitalize(*, null) = *
|
||||
* WordUtils.uncapitalize(*, new char[0]) = *
|
||||
* WordUtils.uncapitalize("I AM.FINE", {'.'}) = "i AM.fINE"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to uncapitalize, may be null
|
||||
* @param delimiters set of characters to determine uncapitalization, null means whitespace
|
||||
* @return uncapitalized String, {@code null} if null String input
|
||||
* @see #capitalize(String)
|
||||
* @since 2.1
|
||||
*/
|
||||
public static String uncapitalize(final String str, final char... delimiters) {
|
||||
final int delimLen = delimiters == null ? -1 : delimiters.length;
|
||||
if (StringUtils.isEmpty(str) || delimLen == 0) {
|
||||
return str;
|
||||
}
|
||||
final char[] buffer = str.toCharArray();
|
||||
boolean uncapitalizeNext = true;
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
final char ch = buffer[i];
|
||||
if (isDelimiter(ch, delimiters)) {
|
||||
uncapitalizeNext = true;
|
||||
} else if (uncapitalizeNext) {
|
||||
buffer[i] = Character.toLowerCase(ch);
|
||||
uncapitalizeNext = false;
|
||||
}
|
||||
}
|
||||
return new String(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps the case of a String using a word based algorithm.
|
||||
*
|
||||
* <ul>
|
||||
* <li>Upper case character converts to Lower case</li>
|
||||
* <li>Title case character converts to Lower case</li>
|
||||
* <li>Lower case character after Whitespace or at start converts to Title case</li>
|
||||
* <li>Other Lower case character converts to Upper case</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
|
||||
* A {@code null} input String returns {@code null}.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtils.swapCase(null) = null
|
||||
* StringUtils.swapCase("") = ""
|
||||
* StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to swap case, may be null
|
||||
* @return the changed String, {@code null} if null String input
|
||||
*/
|
||||
public static String swapCase(final String str) {
|
||||
if (StringUtils.isEmpty(str)) {
|
||||
return str;
|
||||
}
|
||||
final char[] buffer = str.toCharArray();
|
||||
|
||||
boolean whitespace = true;
|
||||
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
final char ch = buffer[i];
|
||||
if (Character.isUpperCase(ch) || Character.isTitleCase(ch)) {
|
||||
buffer[i] = Character.toLowerCase(ch);
|
||||
whitespace = false;
|
||||
} else if (Character.isLowerCase(ch)) {
|
||||
if (whitespace) {
|
||||
buffer[i] = Character.toTitleCase(ch);
|
||||
whitespace = false;
|
||||
} else {
|
||||
buffer[i] = Character.toUpperCase(ch);
|
||||
}
|
||||
} else {
|
||||
whitespace = Character.isWhitespace(ch);
|
||||
}
|
||||
}
|
||||
return new String(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the initial characters from each word in the String.
|
||||
*
|
||||
* <p>All first characters after whitespace are returned as a new string.
|
||||
* Their case is not changed.</p>
|
||||
*
|
||||
* <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
|
||||
* A {@code null} input String returns {@code null}.</p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.initials(null) = null
|
||||
* WordUtils.initials("") = ""
|
||||
* WordUtils.initials("Ben John Lee") = "BJL"
|
||||
* WordUtils.initials("Ben J.Lee") = "BJ"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to get initials from, may be null
|
||||
* @return String of initial letters, {@code null} if null String input
|
||||
* @see #initials(String,char[])
|
||||
* @since 2.2
|
||||
*/
|
||||
public static String initials(final String str) {
|
||||
return initials(str, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the initial characters from each word in the String.
|
||||
*
|
||||
* <p>All first characters after the defined delimiters are returned as a new string.
|
||||
* Their case is not changed.</p>
|
||||
*
|
||||
* <p>If the delimiters array is null, then Whitespace is used.
|
||||
* Whitespace is defined by {@link Character#isWhitespace(char)}.
|
||||
* A {@code null} input String returns {@code null}.
|
||||
* An empty delimiter array returns an empty String.</p>
|
||||
*
|
||||
* <pre>
|
||||
* 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]) = ""
|
||||
* </pre>
|
||||
*
|
||||
* @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 characters, {@code null} if null String input
|
||||
* @see #initials(String)
|
||||
* @since 2.2
|
||||
*/
|
||||
public static String initials(final String str, final char... delimiters) {
|
||||
if (StringUtils.isEmpty(str)) {
|
||||
return str;
|
||||
}
|
||||
if (delimiters != null && delimiters.length == 0) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
final int strLen = str.length();
|
||||
final char[] buf = new char[strLen / 2 + 1];
|
||||
int count = 0;
|
||||
boolean lastWasGap = true;
|
||||
for (int i = 0; i < strLen; i++) {
|
||||
final char ch = str.charAt(i);
|
||||
if (isDelimiter(ch, delimiters)) {
|
||||
lastWasGap = true;
|
||||
} else if (lastWasGap) {
|
||||
buf[count++] = ch;
|
||||
lastWasGap = false;
|
||||
} else {
|
||||
continue; // ignore ch
|
||||
}
|
||||
}
|
||||
return new String(buf, 0, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the String contains all words in the given array.
|
||||
*
|
||||
* <p>
|
||||
* A {@code null} String will return {@code false}. A {@code null}, zero
|
||||
* length search array or if one element of array is null will return {@code false}.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.containsAllWords(null, *) = false
|
||||
* WordUtils.containsAllWords("", *) = false
|
||||
* WordUtils.containsAllWords(*, null) = false
|
||||
* WordUtils.containsAllWords(*, []) = false
|
||||
* WordUtils.containsAllWords("abcd", "ab", "cd") = false
|
||||
* WordUtils.containsAllWords("abc def", "def", "abc") = true
|
||||
* </pre>
|
||||
*
|
||||
* @param word The CharSequence to check, may be null
|
||||
* @param words The array of String words to search for, may be null
|
||||
* @return {@code true} if all search words are found, {@code false} otherwise
|
||||
* @since 3.5
|
||||
*/
|
||||
public static boolean containsAllWords(final CharSequence word, final CharSequence... words) {
|
||||
if (StringUtils.isEmpty(word) || ArrayUtils.isEmpty(words)) {
|
||||
return false;
|
||||
}
|
||||
for (final CharSequence w : words) {
|
||||
if (StringUtils.isBlank(w)) {
|
||||
return false;
|
||||
}
|
||||
final Pattern p = Pattern.compile(".*\\b" + w + "\\b.*");
|
||||
if (!p.matcher(word).matches()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the character is a delimiter.
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @param delimiters the delimiters
|
||||
* @return true if it is a delimiter
|
||||
*/
|
||||
private static boolean isDelimiter(final char ch, final char[] delimiters) {
|
||||
return delimiters == null ? Character.isWhitespace(ch) : ArrayUtils.contains(delimiters, ch);
|
||||
public WordUtils() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,18 +39,15 @@ public abstract class CharSequenceTranslator {
|
|||
static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
|
||||
/**
|
||||
* Translate a set of code points, represented by an int index into a CharSequence,
|
||||
* into another set of code points. The number of code points consumed must be returned,
|
||||
* and the only IOExceptions thrown must be from interacting with the Writer so that
|
||||
* the top level API may reliably ignore StringWriter IOExceptions.
|
||||
* Returns an upper case hexadecimal {@link String} for the given
|
||||
* character.
|
||||
*
|
||||
* @param input CharSequence that is being translated
|
||||
* @param index int representing the current point of translation
|
||||
* @param out Writer to translate the text to
|
||||
* @return int count of code points consumed
|
||||
* @throws IOException if and only if the Writer produces an IOException
|
||||
* @param codePoint The code point to convert.
|
||||
* @return An upper case hexadecimal {@link String}
|
||||
*/
|
||||
public abstract int translate(CharSequence input, int index, Writer out) throws IOException;
|
||||
public static String hex(final int codePoint) {
|
||||
return Integer.toHexString(codePoint).toUpperCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for non-Writer usage.
|
||||
|
@ -71,6 +68,20 @@ public abstract class CharSequenceTranslator {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a set of code points, represented by an int index into a CharSequence,
|
||||
* into another set of code points. The number of code points consumed must be returned,
|
||||
* and the only IOExceptions thrown must be from interacting with the Writer so that
|
||||
* the top level API may reliably ignore StringWriter IOExceptions.
|
||||
*
|
||||
* @param input CharSequence that is being translated
|
||||
* @param index int representing the current point of translation
|
||||
* @param out Writer to translate the text to
|
||||
* @return int count of code points consumed
|
||||
* @throws IOException if and only if the Writer produces an IOException
|
||||
*/
|
||||
public abstract int translate(CharSequence input, int index, Writer out) throws IOException;
|
||||
|
||||
/**
|
||||
* Translate an input onto a Writer. This is intentionally final as its algorithm is
|
||||
* tightly coupled with the abstract method of this class.
|
||||
|
@ -125,15 +136,4 @@ public abstract class CharSequenceTranslator {
|
|||
return new AggregateTranslator(newArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an upper case hexadecimal {@link String} for the given
|
||||
* character.
|
||||
*
|
||||
* @param codePoint The code point to convert.
|
||||
* @return An upper case hexadecimal {@link String}
|
||||
*/
|
||||
public static String hex(final int codePoint) {
|
||||
return Integer.toHexString(codePoint).toUpperCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,15 +29,6 @@ package org.apache.commons.lang3.text.translate;
|
|||
@Deprecated
|
||||
public class EntityArrays {
|
||||
|
||||
/**
|
||||
* Mapping to escape <a href="https://secure.wikimedia.org/wikipedia/en/wiki/ISO/IEC_8859-1">ISO-8859-1</a>
|
||||
* characters to their named HTML 3.x equivalents.
|
||||
* @return the mapping table
|
||||
*/
|
||||
public static String[][] ISO8859_1_ESCAPE() {
|
||||
return ISO8859_1_ESCAPE.clone();
|
||||
}
|
||||
|
||||
private static final String[][] ISO8859_1_ESCAPE = {
|
||||
{"\u00A0", " "}, // non-breaking space
|
||||
{"\u00A1", "¡"}, // inverted exclamation mark
|
||||
|
@ -137,26 +128,8 @@ public class EntityArrays {
|
|||
{"\u00FF", "ÿ"}, // ÿ - lowercase y, umlaut
|
||||
};
|
||||
|
||||
/**
|
||||
* Reverse of {@link #ISO8859_1_ESCAPE()} for unescaping purposes.
|
||||
* @return the mapping table
|
||||
*/
|
||||
public static String[][] ISO8859_1_UNESCAPE() {
|
||||
return ISO8859_1_UNESCAPE.clone();
|
||||
}
|
||||
|
||||
private static final String[][] ISO8859_1_UNESCAPE = invert(ISO8859_1_ESCAPE);
|
||||
|
||||
/**
|
||||
* Mapping to escape additional <a href="https://www.w3.org/TR/REC-html40/sgml/entities.html">character entity
|
||||
* references</a>. Note that this must be used with {@link #ISO8859_1_ESCAPE()} to get the full list of
|
||||
* HTML 4.0 character entities.
|
||||
* @return the mapping table
|
||||
*/
|
||||
public static String[][] HTML40_EXTENDED_ESCAPE() {
|
||||
return HTML40_EXTENDED_ESCAPE.clone();
|
||||
}
|
||||
|
||||
private static final String[][] HTML40_EXTENDED_ESCAPE = {
|
||||
// <!-- Latin Extended-B -->
|
||||
{"\u0192", "ƒ"}, // latin small f with hook = function= florin, U+0192 ISOtech -->
|
||||
|
@ -354,15 +327,48 @@ public class EntityArrays {
|
|||
{"\u20AC", "€"}, // -- euro sign, U+20AC NEW -->
|
||||
};
|
||||
|
||||
private static final String[][] HTML40_EXTENDED_UNESCAPE = invert(HTML40_EXTENDED_ESCAPE);
|
||||
|
||||
private static final String[][] BASIC_ESCAPE = {
|
||||
{"\"", """}, // " - double-quote
|
||||
{"&", "&"}, // & - ampersand
|
||||
{"<", "<"}, // < - less-than
|
||||
{">", ">"}, // > - greater-than
|
||||
};
|
||||
|
||||
private static final String[][] BASIC_UNESCAPE = invert(BASIC_ESCAPE);
|
||||
|
||||
private static final String[][] APOS_ESCAPE = {
|
||||
{"'", "'"}, // XML apostrophe
|
||||
};
|
||||
|
||||
private static final String[][] APOS_UNESCAPE = invert(APOS_ESCAPE);
|
||||
|
||||
private static final String[][] JAVA_CTRL_CHARS_ESCAPE = {
|
||||
{"\b", "\\b"},
|
||||
{"\n", "\\n"},
|
||||
{"\t", "\\t"},
|
||||
{"\f", "\\f"},
|
||||
{"\r", "\\r"}
|
||||
};
|
||||
|
||||
private static final String[][] JAVA_CTRL_CHARS_UNESCAPE = invert(JAVA_CTRL_CHARS_ESCAPE);
|
||||
|
||||
/**
|
||||
* Reverse of {@link #HTML40_EXTENDED_ESCAPE()} for unescaping purposes.
|
||||
* Mapping to escape the apostrophe character to its XML character entity.
|
||||
* @return the mapping table
|
||||
*/
|
||||
public static String[][] HTML40_EXTENDED_UNESCAPE() {
|
||||
return HTML40_EXTENDED_UNESCAPE.clone();
|
||||
public static String[][] APOS_ESCAPE() {
|
||||
return APOS_ESCAPE.clone();
|
||||
}
|
||||
|
||||
private static final String[][] HTML40_EXTENDED_UNESCAPE = invert(HTML40_EXTENDED_ESCAPE);
|
||||
/**
|
||||
* Reverse of {@link #APOS_ESCAPE()} for unescaping purposes.
|
||||
* @return the mapping table
|
||||
*/
|
||||
public static String[][] APOS_UNESCAPE() {
|
||||
return APOS_UNESCAPE.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping to escape the basic XML and HTML character entities.
|
||||
|
@ -374,13 +380,6 @@ public class EntityArrays {
|
|||
return BASIC_ESCAPE.clone();
|
||||
}
|
||||
|
||||
private static final String[][] BASIC_ESCAPE = {
|
||||
{"\"", """}, // " - double-quote
|
||||
{"&", "&"}, // & - ampersand
|
||||
{"<", "<"}, // < - less-than
|
||||
{">", ">"}, // > - greater-than
|
||||
};
|
||||
|
||||
/**
|
||||
* Reverse of {@link #BASIC_ESCAPE()} for unescaping purposes.
|
||||
* @return the mapping table
|
||||
|
@ -389,58 +388,24 @@ public class EntityArrays {
|
|||
return BASIC_UNESCAPE.clone();
|
||||
}
|
||||
|
||||
private static final String[][] BASIC_UNESCAPE = invert(BASIC_ESCAPE);
|
||||
|
||||
/**
|
||||
* Mapping to escape the apostrophe character to its XML character entity.
|
||||
* Mapping to escape additional <a href="https://www.w3.org/TR/REC-html40/sgml/entities.html">character entity
|
||||
* references</a>. Note that this must be used with {@link #ISO8859_1_ESCAPE()} to get the full list of
|
||||
* HTML 4.0 character entities.
|
||||
* @return the mapping table
|
||||
*/
|
||||
public static String[][] APOS_ESCAPE() {
|
||||
return APOS_ESCAPE.clone();
|
||||
public static String[][] HTML40_EXTENDED_ESCAPE() {
|
||||
return HTML40_EXTENDED_ESCAPE.clone();
|
||||
}
|
||||
|
||||
private static final String[][] APOS_ESCAPE = {
|
||||
{"'", "'"}, // XML apostrophe
|
||||
};
|
||||
|
||||
/**
|
||||
* Reverse of {@link #APOS_ESCAPE()} for unescaping purposes.
|
||||
* Reverse of {@link #HTML40_EXTENDED_ESCAPE()} for unescaping purposes.
|
||||
* @return the mapping table
|
||||
*/
|
||||
public static String[][] APOS_UNESCAPE() {
|
||||
return APOS_UNESCAPE.clone();
|
||||
public static String[][] HTML40_EXTENDED_UNESCAPE() {
|
||||
return HTML40_EXTENDED_UNESCAPE.clone();
|
||||
}
|
||||
|
||||
private static final String[][] APOS_UNESCAPE = invert(APOS_ESCAPE);
|
||||
|
||||
/**
|
||||
* Mapping to escape the Java control characters.
|
||||
*
|
||||
* Namely: {@code \b \n \t \f \r}
|
||||
* @return the mapping table
|
||||
*/
|
||||
public static String[][] JAVA_CTRL_CHARS_ESCAPE() {
|
||||
return JAVA_CTRL_CHARS_ESCAPE.clone();
|
||||
}
|
||||
|
||||
private static final String[][] JAVA_CTRL_CHARS_ESCAPE = {
|
||||
{"\b", "\\b"},
|
||||
{"\n", "\\n"},
|
||||
{"\t", "\\t"},
|
||||
{"\f", "\\f"},
|
||||
{"\r", "\\r"}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reverse of {@link #JAVA_CTRL_CHARS_ESCAPE()} for unescaping purposes.
|
||||
* @return the mapping table
|
||||
*/
|
||||
public static String[][] JAVA_CTRL_CHARS_UNESCAPE() {
|
||||
return JAVA_CTRL_CHARS_UNESCAPE.clone();
|
||||
}
|
||||
|
||||
private static final String[][] JAVA_CTRL_CHARS_UNESCAPE = invert(JAVA_CTRL_CHARS_ESCAPE);
|
||||
|
||||
/**
|
||||
* Used to invert an escape array into an unescape array
|
||||
* @param array String[][] to be inverted
|
||||
|
@ -455,4 +420,39 @@ public class EntityArrays {
|
|||
return newarray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping to escape <a href="https://secure.wikimedia.org/wikipedia/en/wiki/ISO/IEC_8859-1">ISO-8859-1</a>
|
||||
* characters to their named HTML 3.x equivalents.
|
||||
* @return the mapping table
|
||||
*/
|
||||
public static String[][] ISO8859_1_ESCAPE() {
|
||||
return ISO8859_1_ESCAPE.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse of {@link #ISO8859_1_ESCAPE()} for unescaping purposes.
|
||||
* @return the mapping table
|
||||
*/
|
||||
public static String[][] ISO8859_1_UNESCAPE() {
|
||||
return ISO8859_1_UNESCAPE.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping to escape the Java control characters.
|
||||
*
|
||||
* Namely: {@code \b \n \t \f \r}
|
||||
* @return the mapping table
|
||||
*/
|
||||
public static String[][] JAVA_CTRL_CHARS_ESCAPE() {
|
||||
return JAVA_CTRL_CHARS_ESCAPE.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse of {@link #JAVA_CTRL_CHARS_ESCAPE()} for unescaping purposes.
|
||||
* @return the mapping table
|
||||
*/
|
||||
public static String[][] JAVA_CTRL_CHARS_UNESCAPE() {
|
||||
return JAVA_CTRL_CHARS_UNESCAPE.clone();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,43 +30,6 @@ import java.io.Writer;
|
|||
@Deprecated
|
||||
public class NumericEntityEscaper extends CodePointTranslator {
|
||||
|
||||
private final int below;
|
||||
private final int above;
|
||||
private final boolean between;
|
||||
|
||||
/**
|
||||
* Constructs a {@link NumericEntityEscaper} for the specified range. This is
|
||||
* the underlying method for the other constructors/builders. The {@code below}
|
||||
* and {@code above} boundaries are inclusive when {@code between} is
|
||||
* {@code true} and exclusive when it is {@code false}.
|
||||
*
|
||||
* @param below int value representing the lowest code point boundary
|
||||
* @param above int value representing the highest code point boundary
|
||||
* @param between whether to escape between the boundaries or outside them
|
||||
*/
|
||||
private NumericEntityEscaper(final int below, final int above, final boolean between) {
|
||||
this.below = below;
|
||||
this.above = above;
|
||||
this.between = between;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link NumericEntityEscaper} for all characters.
|
||||
*/
|
||||
public NumericEntityEscaper() {
|
||||
this(0, Integer.MAX_VALUE, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link NumericEntityEscaper} below the specified value (exclusive).
|
||||
*
|
||||
* @param codePoint below which to escape
|
||||
* @return the newly created {@link NumericEntityEscaper} instance
|
||||
*/
|
||||
public static NumericEntityEscaper below(final int codePoint) {
|
||||
return outsideOf(codePoint, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link NumericEntityEscaper} above the specified value (exclusive).
|
||||
*
|
||||
|
@ -76,7 +39,15 @@ public class NumericEntityEscaper extends CodePointTranslator {
|
|||
public static NumericEntityEscaper above(final int codePoint) {
|
||||
return outsideOf(0, codePoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link NumericEntityEscaper} below the specified value (exclusive).
|
||||
*
|
||||
* @param codePoint below which to escape
|
||||
* @return the newly created {@link NumericEntityEscaper} instance
|
||||
*/
|
||||
public static NumericEntityEscaper below(final int codePoint) {
|
||||
return outsideOf(codePoint, Integer.MAX_VALUE);
|
||||
}
|
||||
/**
|
||||
* Constructs a {@link NumericEntityEscaper} between the specified values (inclusive).
|
||||
*
|
||||
|
@ -99,6 +70,35 @@ public class NumericEntityEscaper extends CodePointTranslator {
|
|||
return new NumericEntityEscaper(codePointLow, codePointHigh, false);
|
||||
}
|
||||
|
||||
private final int below;
|
||||
|
||||
private final int above;
|
||||
|
||||
private final boolean between;
|
||||
|
||||
/**
|
||||
* Constructs a {@link NumericEntityEscaper} for all characters.
|
||||
*/
|
||||
public NumericEntityEscaper() {
|
||||
this(0, Integer.MAX_VALUE, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link NumericEntityEscaper} for the specified range. This is
|
||||
* the underlying method for the other constructors/builders. The {@code below}
|
||||
* and {@code above} boundaries are inclusive when {@code between} is
|
||||
* {@code true} and exclusive when it is {@code false}.
|
||||
*
|
||||
* @param below int value representing the lowest code point boundary
|
||||
* @param above int value representing the highest code point boundary
|
||||
* @param between whether to escape between the boundaries or outside them
|
||||
*/
|
||||
private NumericEntityEscaper(final int below, final int above, final boolean between) {
|
||||
this.below = below;
|
||||
this.above = above;
|
||||
this.between = between;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
|
|
@ -35,6 +35,24 @@ import java.io.Writer;
|
|||
@Deprecated
|
||||
public class OctalUnescaper extends CharSequenceTranslator {
|
||||
|
||||
/**
|
||||
* Checks if the given char is an octal digit. Octal digits are the character representations of the digits 0 to 7.
|
||||
* @param ch the char to check
|
||||
* @return true if the given char is the character representation of one of the digits from 0 to 7
|
||||
*/
|
||||
private boolean isOctalDigit(final char ch) {
|
||||
return ch >= '0' && ch <= '7';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given char is the character representation of one of the digit from 0 to 3.
|
||||
* @param ch the char to check
|
||||
* @return true if the given char is the character representation of one of the digits from 0 to 3
|
||||
*/
|
||||
private boolean isZeroToThree(final char ch) {
|
||||
return ch >= '0' && ch <= '3';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
@ -62,22 +80,4 @@ public class OctalUnescaper extends CharSequenceTranslator {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given char is an octal digit. Octal digits are the character representations of the digits 0 to 7.
|
||||
* @param ch the char to check
|
||||
* @return true if the given char is the character representation of one of the digits from 0 to 7
|
||||
*/
|
||||
private boolean isOctalDigit(final char ch) {
|
||||
return ch >= '0' && ch <= '7';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given char is the character representation of one of the digit from 0 to 3.
|
||||
* @param ch the char to check
|
||||
* @return true if the given char is the character representation of one of the digits from 0 to 3
|
||||
*/
|
||||
private boolean isZeroToThree(final char ch) {
|
||||
return ch >= '0' && ch <= '3';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,8 +30,50 @@ import java.io.Writer;
|
|||
@Deprecated
|
||||
public class UnicodeEscaper extends CodePointTranslator {
|
||||
|
||||
/**
|
||||
* Constructs a {@link UnicodeEscaper} above the specified value (exclusive).
|
||||
*
|
||||
* @param codePoint above which to escape
|
||||
* @return the newly created {@link UnicodeEscaper} instance
|
||||
*/
|
||||
public static UnicodeEscaper above(final int codePoint) {
|
||||
return outsideOf(0, codePoint);
|
||||
}
|
||||
/**
|
||||
* Constructs a {@link UnicodeEscaper} below the specified value (exclusive).
|
||||
*
|
||||
* @param codePoint below which to escape
|
||||
* @return the newly created {@link UnicodeEscaper} instance
|
||||
*/
|
||||
public static UnicodeEscaper below(final int codePoint) {
|
||||
return outsideOf(codePoint, Integer.MAX_VALUE);
|
||||
}
|
||||
/**
|
||||
* Constructs a {@link UnicodeEscaper} between the specified values (inclusive).
|
||||
*
|
||||
* @param codePointLow above which to escape
|
||||
* @param codePointHigh below which to escape
|
||||
* @return the newly created {@link UnicodeEscaper} instance
|
||||
*/
|
||||
public static UnicodeEscaper between(final int codePointLow, final int codePointHigh) {
|
||||
return new UnicodeEscaper(codePointLow, codePointHigh, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link UnicodeEscaper} outside of the specified values (exclusive).
|
||||
*
|
||||
* @param codePointLow below which to escape
|
||||
* @param codePointHigh above which to escape
|
||||
* @return the newly created {@link UnicodeEscaper} instance
|
||||
*/
|
||||
public static UnicodeEscaper outsideOf(final int codePointLow, final int codePointHigh) {
|
||||
return new UnicodeEscaper(codePointLow, codePointHigh, false);
|
||||
}
|
||||
|
||||
private final int below;
|
||||
|
||||
private final int above;
|
||||
|
||||
private final boolean between;
|
||||
|
||||
/**
|
||||
|
@ -58,45 +100,16 @@ public class UnicodeEscaper extends CodePointTranslator {
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link UnicodeEscaper} below the specified value (exclusive).
|
||||
* Converts the given code point to a hexadecimal string of the form {@code "\\uXXXX"}
|
||||
*
|
||||
* @param codePoint below which to escape
|
||||
* @return the newly created {@link UnicodeEscaper} instance
|
||||
*/
|
||||
public static UnicodeEscaper below(final int codePoint) {
|
||||
return outsideOf(codePoint, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link UnicodeEscaper} above the specified value (exclusive).
|
||||
* @param codePoint
|
||||
* a Unicode code point
|
||||
* @return the hexadecimal string for the given code point
|
||||
*
|
||||
* @param codePoint above which to escape
|
||||
* @return the newly created {@link UnicodeEscaper} instance
|
||||
* @since 3.2
|
||||
*/
|
||||
public static UnicodeEscaper above(final int codePoint) {
|
||||
return outsideOf(0, codePoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link UnicodeEscaper} outside of the specified values (exclusive).
|
||||
*
|
||||
* @param codePointLow below which to escape
|
||||
* @param codePointHigh above which to escape
|
||||
* @return the newly created {@link UnicodeEscaper} instance
|
||||
*/
|
||||
public static UnicodeEscaper outsideOf(final int codePointLow, final int codePointHigh) {
|
||||
return new UnicodeEscaper(codePointLow, codePointHigh, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link UnicodeEscaper} between the specified values (inclusive).
|
||||
*
|
||||
* @param codePointLow above which to escape
|
||||
* @param codePointHigh below which to escape
|
||||
* @return the newly created {@link UnicodeEscaper} instance
|
||||
*/
|
||||
public static UnicodeEscaper between(final int codePointLow, final int codePointHigh) {
|
||||
return new UnicodeEscaper(codePointLow, codePointHigh, true);
|
||||
protected String toUtf16Escape(final int codePoint) {
|
||||
return "\\u" + hex(codePoint);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,17 +137,4 @@ public class UnicodeEscaper extends CodePointTranslator {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given code point to a hexadecimal string of the form {@code "\\uXXXX"}
|
||||
*
|
||||
* @param codePoint
|
||||
* a Unicode code point
|
||||
* @return the hexadecimal string for the given code point
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
protected String toUtf16Escape(final int codePoint) {
|
||||
return "\\u" + hex(codePoint);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,14 +38,160 @@ import org.apache.commons.lang3.LocaleUtils;
|
|||
// TODO: Before making public move from getDateTimeInstance(Integer, ...) to int; or some other approach.
|
||||
abstract class AbstractFormatCache<F extends Format> {
|
||||
|
||||
/**
|
||||
* Helper class to hold multipart Map keys as arrays.
|
||||
*/
|
||||
private static final class ArrayKey {
|
||||
|
||||
private static int computeHashCode(final Object[] keys) {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Arrays.hashCode(keys);
|
||||
return result;
|
||||
}
|
||||
|
||||
private final Object[] keys;
|
||||
private final int hashCode;
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@link MultipartKey} to hold the specified objects.
|
||||
*
|
||||
* @param keys the set of objects that make up the key. Each key may be null.
|
||||
*/
|
||||
ArrayKey(final Object... keys) {
|
||||
this.keys = keys;
|
||||
this.hashCode = computeHashCode(keys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final ArrayKey other = (ArrayKey) obj;
|
||||
return Arrays.deepEquals(keys, other.keys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* No date or no time. Used in same parameters as DateFormat.SHORT or DateFormat.LONG
|
||||
*/
|
||||
static final int NONE = -1;
|
||||
|
||||
private static final ConcurrentMap<ArrayKey, String> cDateTimeInstanceCache = new ConcurrentHashMap<>(7);
|
||||
|
||||
/**
|
||||
* Gets a date/time format for the specified styles and locale.
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT, null indicates no date in format
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT, null indicates no time in format
|
||||
* @param locale The non-null locale of the desired format
|
||||
* @return a localized standard date/time format
|
||||
* @throws IllegalArgumentException if the Locale has no date/time pattern defined
|
||||
*/
|
||||
// package protected, for access from test code; do not make public or protected
|
||||
static String getPatternForStyle(final Integer dateStyle, final Integer timeStyle, final Locale locale) {
|
||||
final Locale safeLocale = LocaleUtils.toLocale(locale);
|
||||
final ArrayKey key = new ArrayKey(dateStyle, timeStyle, safeLocale);
|
||||
return cDateTimeInstanceCache.computeIfAbsent(key, k -> {
|
||||
try {
|
||||
final DateFormat formatter;
|
||||
if (dateStyle == null) {
|
||||
formatter = DateFormat.getTimeInstance(timeStyle.intValue(), safeLocale);
|
||||
} else if (timeStyle == null) {
|
||||
formatter = DateFormat.getDateInstance(dateStyle.intValue(), safeLocale);
|
||||
} else {
|
||||
formatter = DateFormat.getDateTimeInstance(dateStyle.intValue(), timeStyle.intValue(), safeLocale);
|
||||
}
|
||||
return ((SimpleDateFormat) formatter).toPattern();
|
||||
} catch (final ClassCastException ex) {
|
||||
throw new IllegalArgumentException("No date time pattern for locale: " + safeLocale);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private final ConcurrentMap<ArrayKey, F> cInstanceCache = new ConcurrentHashMap<>(7);
|
||||
|
||||
private static final ConcurrentMap<ArrayKey, String> cDateTimeInstanceCache = new ConcurrentHashMap<>(7);
|
||||
/**
|
||||
* Create a format instance using the specified pattern, time zone
|
||||
* and locale.
|
||||
*
|
||||
* @param pattern {@link java.text.SimpleDateFormat} compatible pattern, this will not be null.
|
||||
* @param timeZone time zone, this will not be null.
|
||||
* @param locale locale, this will not be null.
|
||||
* @return a pattern based date/time formatter
|
||||
* @throws IllegalArgumentException if pattern is invalid
|
||||
* or {@code null}
|
||||
*/
|
||||
protected abstract F createInstance(String pattern, TimeZone timeZone, Locale locale);
|
||||
|
||||
/**
|
||||
* Gets a date formatter instance using the specified style,
|
||||
* time zone and locale.
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone optional time zone, overrides time zone of
|
||||
* formatted date, null means use default Locale
|
||||
* @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
|
||||
*/
|
||||
// package protected, for access from FastDateFormat; do not make public or protected
|
||||
F getDateInstance(final int dateStyle, final TimeZone timeZone, final Locale locale) {
|
||||
return getDateTimeInstance(Integer.valueOf(dateStyle), null, timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, null means use default Locale
|
||||
* @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
|
||||
*/
|
||||
// package protected, for access from FastDateFormat; do not make public or protected
|
||||
F getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) {
|
||||
return getDateTimeInstance(Integer.valueOf(dateStyle), Integer.valueOf(timeStyle), timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a date/time formatter instance using the specified style,
|
||||
* time zone and locale.
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT, null indicates no date in format
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT, null indicates no time in format
|
||||
* @param timeZone optional time zone, overrides time zone of
|
||||
* formatted date, null means use default Locale
|
||||
* @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
|
||||
*/
|
||||
// This must remain private, see LANG-884
|
||||
private F getDateTimeInstance(final Integer dateStyle, final Integer timeStyle, final TimeZone timeZone, Locale locale) {
|
||||
locale = LocaleUtils.toLocale(locale);
|
||||
final String pattern = getPatternForStyle(dateStyle, timeStyle, locale);
|
||||
return getInstance(pattern, timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a formatter instance using the default pattern in the
|
||||
|
@ -77,74 +223,6 @@ abstract class AbstractFormatCache<F extends Format> {
|
|||
return cInstanceCache.computeIfAbsent(key, k -> createInstance(pattern, actualTimeZone, actualLocale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a format instance using the specified pattern, time zone
|
||||
* and locale.
|
||||
*
|
||||
* @param pattern {@link java.text.SimpleDateFormat} compatible pattern, this will not be null.
|
||||
* @param timeZone time zone, this will not be null.
|
||||
* @param locale locale, this will not be null.
|
||||
* @return a pattern based date/time formatter
|
||||
* @throws IllegalArgumentException if pattern is invalid
|
||||
* or {@code null}
|
||||
*/
|
||||
protected abstract F createInstance(String pattern, TimeZone timeZone, Locale locale);
|
||||
|
||||
/**
|
||||
* Gets a date/time formatter instance using the specified style,
|
||||
* time zone and locale.
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT, null indicates no date in format
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT, null indicates no time in format
|
||||
* @param timeZone optional time zone, overrides time zone of
|
||||
* formatted date, null means use default Locale
|
||||
* @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
|
||||
*/
|
||||
// This must remain private, see LANG-884
|
||||
private F getDateTimeInstance(final Integer dateStyle, final Integer timeStyle, final TimeZone timeZone, Locale locale) {
|
||||
locale = LocaleUtils.toLocale(locale);
|
||||
final String pattern = getPatternForStyle(dateStyle, timeStyle, locale);
|
||||
return getInstance(pattern, timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, null means use default Locale
|
||||
* @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
|
||||
*/
|
||||
// package protected, for access from FastDateFormat; do not make public or protected
|
||||
F getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) {
|
||||
return getDateTimeInstance(Integer.valueOf(dateStyle), Integer.valueOf(timeStyle), timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a date formatter instance using the specified style,
|
||||
* time zone and locale.
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone optional time zone, overrides time zone of
|
||||
* formatted date, null means use default Locale
|
||||
* @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
|
||||
*/
|
||||
// package protected, for access from FastDateFormat; do not make public or protected
|
||||
F getDateInstance(final int dateStyle, final TimeZone timeZone, final Locale locale) {
|
||||
return getDateTimeInstance(Integer.valueOf(dateStyle), null, timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a time formatter instance using the specified style,
|
||||
* time zone and locale.
|
||||
|
@ -162,82 +240,4 @@ abstract class AbstractFormatCache<F extends Format> {
|
|||
return getDateTimeInstance(null, Integer.valueOf(timeStyle), timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a date/time format for the specified styles and locale.
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT, null indicates no date in format
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT, null indicates no time in format
|
||||
* @param locale The non-null locale of the desired format
|
||||
* @return a localized standard date/time format
|
||||
* @throws IllegalArgumentException if the Locale has no date/time pattern defined
|
||||
*/
|
||||
// package protected, for access from test code; do not make public or protected
|
||||
static String getPatternForStyle(final Integer dateStyle, final Integer timeStyle, final Locale locale) {
|
||||
final Locale safeLocale = LocaleUtils.toLocale(locale);
|
||||
final ArrayKey key = new ArrayKey(dateStyle, timeStyle, safeLocale);
|
||||
return cDateTimeInstanceCache.computeIfAbsent(key, k -> {
|
||||
try {
|
||||
final DateFormat formatter;
|
||||
if (dateStyle == null) {
|
||||
formatter = DateFormat.getTimeInstance(timeStyle.intValue(), safeLocale);
|
||||
} else if (timeStyle == null) {
|
||||
formatter = DateFormat.getDateInstance(dateStyle.intValue(), safeLocale);
|
||||
} else {
|
||||
formatter = DateFormat.getDateTimeInstance(dateStyle.intValue(), timeStyle.intValue(), safeLocale);
|
||||
}
|
||||
return ((SimpleDateFormat) formatter).toPattern();
|
||||
} catch (final ClassCastException ex) {
|
||||
throw new IllegalArgumentException("No date time pattern for locale: " + safeLocale);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to hold multipart Map keys as arrays.
|
||||
*/
|
||||
private static final class ArrayKey {
|
||||
|
||||
private static int computeHashCode(final Object[] keys) {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Arrays.hashCode(keys);
|
||||
return result;
|
||||
}
|
||||
|
||||
private final Object[] keys;
|
||||
private final int hashCode;
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@link MultipartKey} to hold the specified objects.
|
||||
*
|
||||
* @param keys the set of objects that make up the key. Each key may be null.
|
||||
*/
|
||||
ArrayKey(final Object... keys) {
|
||||
this.keys = keys;
|
||||
this.hashCode = computeHashCode(keys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final ArrayKey other = (ArrayKey) obj;
|
||||
return Arrays.deepEquals(keys, other.keys);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -197,15 +197,6 @@ public class DateFormatUtils {
|
|||
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.
|
||||
*
|
||||
* <p>This constructor is public to permit tools that require a JavaBean instance
|
||||
* to operate.</p>
|
||||
*/
|
||||
public DateFormatUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a calendar into a specific pattern. The TimeZone from the calendar
|
||||
* will be used for formatting.
|
||||
|
@ -412,4 +403,13 @@ public class DateFormatUtils {
|
|||
return calendar == null ? null : calendar.getTimeZone();
|
||||
}
|
||||
|
||||
/**
|
||||
* DateFormatUtils instances should NOT be constructed in standard programming.
|
||||
*
|
||||
* <p>This constructor is public to permit tools that require a JavaBean instance
|
||||
* to operate.</p>
|
||||
*/
|
||||
public DateFormatUtils() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,33 @@ import java.util.TimeZone;
|
|||
*/
|
||||
public interface DateParser {
|
||||
|
||||
/**
|
||||
* Gets the locale used by this parser.
|
||||
*
|
||||
* @return the locale
|
||||
*/
|
||||
Locale getLocale();
|
||||
|
||||
// Accessors
|
||||
/**
|
||||
* Gets the pattern used by this parser.
|
||||
*
|
||||
* @return the pattern, {@link java.text.SimpleDateFormat} compatible
|
||||
*/
|
||||
String getPattern();
|
||||
|
||||
/**
|
||||
* Gets the time zone used by this parser.
|
||||
*
|
||||
* <p>
|
||||
* The default {@link TimeZone} used to create a {@link Date} when the {@link TimeZone} is not specified by
|
||||
* the format pattern.
|
||||
* </p>
|
||||
*
|
||||
* @return the time zone
|
||||
*/
|
||||
TimeZone getTimeZone();
|
||||
|
||||
/**
|
||||
* Equivalent to DateFormat.parse(String).
|
||||
*
|
||||
|
@ -75,33 +102,6 @@ public interface DateParser {
|
|||
*/
|
||||
boolean parse(String source, ParsePosition pos, Calendar calendar);
|
||||
|
||||
// Accessors
|
||||
/**
|
||||
* Gets the pattern used by this parser.
|
||||
*
|
||||
* @return the pattern, {@link java.text.SimpleDateFormat} compatible
|
||||
*/
|
||||
String getPattern();
|
||||
|
||||
/**
|
||||
* Gets the time zone used by this parser.
|
||||
*
|
||||
* <p>
|
||||
* The default {@link TimeZone} used to create a {@link Date} when the {@link TimeZone} is not specified by
|
||||
* the format pattern.
|
||||
* </p>
|
||||
*
|
||||
* @return the time zone
|
||||
*/
|
||||
TimeZone getTimeZone();
|
||||
|
||||
/**
|
||||
* Gets the locale used by this parser.
|
||||
*
|
||||
* @return the locale
|
||||
*/
|
||||
Locale getLocale();
|
||||
|
||||
/**
|
||||
* Parses text from a string to produce a Date.
|
||||
*
|
||||
|
|
|
@ -35,23 +35,6 @@ import java.util.TimeZone;
|
|||
*/
|
||||
public interface DatePrinter {
|
||||
|
||||
/**
|
||||
* Formats a millisecond {@code long} value.
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @return the formatted string
|
||||
* @since 2.1
|
||||
*/
|
||||
String format(long millis);
|
||||
|
||||
/**
|
||||
* Formats a {@link Date} object using a {@link GregorianCalendar}.
|
||||
*
|
||||
* @param date the date to format
|
||||
* @return the formatted string
|
||||
*/
|
||||
String format(Date date);
|
||||
|
||||
/**
|
||||
* Formats a {@link Calendar} object.
|
||||
* The TimeZone set on the Calendar is only used to adjust the time offset.
|
||||
|
@ -64,28 +47,18 @@ public interface DatePrinter {
|
|||
String format(Calendar calendar);
|
||||
|
||||
/**
|
||||
* Formats a millisecond {@code long} value into the
|
||||
* supplied {@link StringBuffer}.
|
||||
* Formats a {@link Calendar} object into the supplied {@link Appendable}.
|
||||
* The TimeZone set on the Calendar is only used to adjust the time offset.
|
||||
* The TimeZone specified during the construction of the Parser will determine the TimeZone
|
||||
* used in the formatted string.
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @param calendar the calendar to format
|
||||
* @param buf the buffer to format into
|
||||
* @param <B> the Appendable class type, usually StringBuilder or StringBuffer.
|
||||
* @return the specified string buffer
|
||||
* @deprecated Use {{@link #format(long, Appendable)}.
|
||||
* @since 3.5
|
||||
*/
|
||||
@Deprecated
|
||||
StringBuffer format(long millis, StringBuffer buf);
|
||||
|
||||
/**
|
||||
* Formats a {@link Date} object into the
|
||||
* supplied {@link StringBuffer} using a {@link GregorianCalendar}.
|
||||
*
|
||||
* @param date the date to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @deprecated Use {{@link #format(Date, Appendable)}.
|
||||
*/
|
||||
@Deprecated
|
||||
StringBuffer format(Date date, StringBuffer buf);
|
||||
<B extends Appendable> B format(Calendar calendar, B buf);
|
||||
|
||||
/**
|
||||
* Formats a {@link Calendar} object into the supplied {@link StringBuffer}.
|
||||
|
@ -102,16 +75,12 @@ public interface DatePrinter {
|
|||
StringBuffer format(Calendar calendar, StringBuffer buf);
|
||||
|
||||
/**
|
||||
* Formats a millisecond {@code long} value into the
|
||||
* supplied {@link Appendable}.
|
||||
* Formats a {@link Date} object using a {@link GregorianCalendar}.
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @param buf the buffer to format into
|
||||
* @param <B> the Appendable class type, usually StringBuilder or StringBuffer.
|
||||
* @return the specified string buffer
|
||||
* @since 3.5
|
||||
* @param date the date to format
|
||||
* @return the formatted string
|
||||
*/
|
||||
<B extends Appendable> B format(long millis, B buf);
|
||||
String format(Date date);
|
||||
|
||||
/**
|
||||
* Formats a {@link Date} object into the
|
||||
|
@ -126,19 +95,69 @@ public interface DatePrinter {
|
|||
<B extends Appendable> B format(Date date, B buf);
|
||||
|
||||
/**
|
||||
* Formats a {@link Calendar} object into the supplied {@link Appendable}.
|
||||
* The TimeZone set on the Calendar is only used to adjust the time offset.
|
||||
* The TimeZone specified during the construction of the Parser will determine the TimeZone
|
||||
* used in the formatted string.
|
||||
* Formats a {@link Date} object into the
|
||||
* supplied {@link StringBuffer} using a {@link GregorianCalendar}.
|
||||
*
|
||||
* @param calendar the calendar to format
|
||||
* @param date the date to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @deprecated Use {{@link #format(Date, Appendable)}.
|
||||
*/
|
||||
@Deprecated
|
||||
StringBuffer format(Date date, StringBuffer buf);
|
||||
|
||||
/**
|
||||
* Formats a millisecond {@code long} value.
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @return the formatted string
|
||||
* @since 2.1
|
||||
*/
|
||||
String format(long millis);
|
||||
|
||||
/**
|
||||
* Formats a millisecond {@code long} value into the
|
||||
* supplied {@link Appendable}.
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @param buf the buffer to format into
|
||||
* @param <B> the Appendable class type, usually StringBuilder or StringBuffer.
|
||||
* @return the specified string buffer
|
||||
* @since 3.5
|
||||
*/
|
||||
<B extends Appendable> B format(Calendar calendar, B buf);
|
||||
<B extends Appendable> B format(long millis, B buf);
|
||||
|
||||
/**
|
||||
* Formats a millisecond {@code long} value into the
|
||||
* supplied {@link StringBuffer}.
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @deprecated Use {{@link #format(long, Appendable)}.
|
||||
*/
|
||||
@Deprecated
|
||||
StringBuffer format(long millis, StringBuffer buf);
|
||||
|
||||
|
||||
/**
|
||||
* Formats a {@link Date}, {@link Calendar} or
|
||||
* {@link 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
|
||||
* @see java.text.DateFormat#format(Object, StringBuffer, FieldPosition)
|
||||
*/
|
||||
StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos);
|
||||
|
||||
/**
|
||||
* Gets the locale used by this printer.
|
||||
*
|
||||
* @return the locale
|
||||
*/
|
||||
Locale getLocale();
|
||||
|
||||
// Accessors
|
||||
/**
|
||||
|
@ -156,23 +175,4 @@ public interface DatePrinter {
|
|||
* @return the time zone
|
||||
*/
|
||||
TimeZone getTimeZone();
|
||||
|
||||
/**
|
||||
* Gets the locale used by this printer.
|
||||
*
|
||||
* @return the locale
|
||||
*/
|
||||
Locale getLocale();
|
||||
|
||||
/**
|
||||
* Formats a {@link Date}, {@link Calendar} or
|
||||
* {@link 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
|
||||
* @see java.text.DateFormat#format(Object, StringBuffer, FieldPosition)
|
||||
*/
|
||||
StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -80,12 +80,116 @@ import org.apache.commons.lang3.Validate;
|
|||
public class DurationFormatUtils {
|
||||
|
||||
/**
|
||||
* DurationFormatUtils instances should NOT be constructed in standard programming.
|
||||
*
|
||||
* <p>This constructor is public to permit tools that require a JavaBean instance
|
||||
* to operate.</p>
|
||||
* Element that is parsed from the format pattern.
|
||||
*/
|
||||
public DurationFormatUtils() {
|
||||
static class Token {
|
||||
|
||||
/** Empty array. */
|
||||
private static final Token[] EMPTY_ARRAY = {};
|
||||
|
||||
/**
|
||||
* Helper method to determine if a set of tokens contain a value
|
||||
*
|
||||
* @param tokens set to look in
|
||||
* @param value to look for
|
||||
* @return boolean {@code true} if contained
|
||||
*/
|
||||
static boolean containsTokenWithValue(final Token[] tokens, final Object value) {
|
||||
return Stream.of(tokens).anyMatch(token -> token.getValue() == value);
|
||||
}
|
||||
|
||||
private final Object value;
|
||||
private int count;
|
||||
private int optionalIndex = -1;
|
||||
|
||||
/**
|
||||
* Wraps a token around a value. A value would be something like a 'Y'.
|
||||
*
|
||||
* @param value value to wrap, non-null.
|
||||
* @param optional whether the token is optional
|
||||
* @param optionalIndex the index of the optional token within the pattern
|
||||
*/
|
||||
Token(final Object value, final boolean optional, final int optionalIndex) {
|
||||
this.value = Objects.requireNonNull(value, "value");
|
||||
this.count = 1;
|
||||
if (optional) {
|
||||
this.optionalIndex = optionalIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Supports equality of this Token to another Token.
|
||||
*
|
||||
* @param obj2 Object to consider equality of
|
||||
* @return boolean {@code true} if equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj2) {
|
||||
if (obj2 instanceof Token) {
|
||||
final Token tok2 = (Token) obj2;
|
||||
if (this.value.getClass() != tok2.value.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (this.count != tok2.count) {
|
||||
return false;
|
||||
}
|
||||
if (this.value instanceof StringBuilder) {
|
||||
return this.value.toString().equals(tok2.value.toString());
|
||||
}
|
||||
if (this.value instanceof Number) {
|
||||
return this.value.equals(tok2.value);
|
||||
}
|
||||
return this.value == tok2.value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, non-null.
|
||||
*/
|
||||
Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code for the token equal to the
|
||||
* hash code for the token's value. Thus 'TT' and 'TTTT'
|
||||
* will have the same hash code.
|
||||
*
|
||||
* @return The hash code for the token
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.value.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds another one of the value
|
||||
*/
|
||||
void increment() {
|
||||
count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents this token as a String.
|
||||
*
|
||||
* @return String representation of the token
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return StringUtils.repeat(this.value.toString(), this.count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,33 +201,123 @@ public class DurationFormatUtils {
|
|||
*/
|
||||
public static final String ISO_EXTENDED_FORMAT_PATTERN = "'P'yyyy'Y'M'M'd'DT'H'H'm'M's.SSS'S'";
|
||||
|
||||
/**
|
||||
* Formats the time gap as a string.
|
||||
*
|
||||
* <p>The format used is ISO 8601-like: {@code HH:mm:ss.SSS}.</p>
|
||||
*
|
||||
* @param durationMillis the duration to format
|
||||
* @return the formatted duration, not null
|
||||
* @throws IllegalArgumentException if durationMillis is negative
|
||||
*/
|
||||
public static String formatDurationHMS(final long durationMillis) {
|
||||
return formatDuration(durationMillis, "HH:mm:ss.SSS");
|
||||
}
|
||||
static final String y = "y";
|
||||
|
||||
static final String M = "M";
|
||||
|
||||
static final String d = "d";
|
||||
|
||||
static final String H = "H";
|
||||
|
||||
static final String m = "m";
|
||||
|
||||
static final String s = "s";
|
||||
|
||||
static final String S = "S";
|
||||
|
||||
/**
|
||||
* Formats the time gap as a string.
|
||||
* The internal method to do the formatting.
|
||||
*
|
||||
* <p>The format used is the ISO 8601 period format.</p>
|
||||
*
|
||||
* <p>This method formats durations using the days and lower fields of the
|
||||
* ISO format pattern, such as P7D6TH5M4.321S.</p>
|
||||
*
|
||||
* @param durationMillis the duration to format
|
||||
* @return the formatted duration, not null
|
||||
* @throws IllegalArgumentException if durationMillis is negative
|
||||
* @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
|
||||
*/
|
||||
public static String formatDurationISO(final long durationMillis) {
|
||||
return formatDuration(durationMillis, ISO_EXTENDED_FORMAT_PATTERN, false);
|
||||
static String format(final Token[] tokens, final long years, final long months, final long days, final long hours, final long minutes,
|
||||
final long seconds,
|
||||
final long milliseconds, final boolean padWithZeros) {
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
boolean lastOutputSeconds = false;
|
||||
boolean lastOutputZero = false;
|
||||
int optionalStart = -1;
|
||||
boolean firstOptionalNonLiteral = false;
|
||||
int optionalIndex = -1;
|
||||
boolean inOptional = false;
|
||||
for (final Token token : tokens) {
|
||||
final Object value = token.getValue();
|
||||
final boolean isLiteral = value instanceof StringBuilder;
|
||||
final int count = token.getCount();
|
||||
if (optionalIndex != token.optionalIndex) {
|
||||
optionalIndex = token.optionalIndex;
|
||||
if (optionalIndex > -1) {
|
||||
//entering new optional block
|
||||
optionalStart = buffer.length();
|
||||
lastOutputZero = false;
|
||||
inOptional = true;
|
||||
firstOptionalNonLiteral = false;
|
||||
} else {
|
||||
//leaving optional block
|
||||
inOptional = false;
|
||||
}
|
||||
}
|
||||
if (isLiteral) {
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
buffer.append(value.toString());
|
||||
}
|
||||
} else if (value.equals(y)) {
|
||||
lastOutputSeconds = false;
|
||||
lastOutputZero = years == 0;
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
buffer.append(paddedValue(years, padWithZeros, count));
|
||||
}
|
||||
} else if (value.equals(M)) {
|
||||
lastOutputSeconds = false;
|
||||
lastOutputZero = months == 0;
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
buffer.append(paddedValue(months, padWithZeros, count));
|
||||
}
|
||||
} else if (value.equals(d)) {
|
||||
lastOutputSeconds = false;
|
||||
lastOutputZero = days == 0;
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
buffer.append(paddedValue(days, padWithZeros, count));
|
||||
}
|
||||
} else if (value.equals(H)) {
|
||||
lastOutputSeconds = false;
|
||||
lastOutputZero = hours == 0;
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
buffer.append(paddedValue(hours, padWithZeros, count));
|
||||
}
|
||||
} else if (value.equals(m)) {
|
||||
lastOutputSeconds = false;
|
||||
lastOutputZero = minutes == 0;
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
buffer.append(paddedValue(minutes, padWithZeros, count));
|
||||
}
|
||||
} else if (value.equals(s)) {
|
||||
lastOutputSeconds = true;
|
||||
lastOutputZero = seconds == 0;
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
buffer.append(paddedValue(seconds, padWithZeros, count));
|
||||
}
|
||||
} else if (value.equals(S)) {
|
||||
lastOutputZero = milliseconds == 0;
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
if (lastOutputSeconds) {
|
||||
// ensure at least 3 digits are displayed even if padding is not selected
|
||||
final int width = padWithZeros ? Math.max(3, count) : 3;
|
||||
buffer.append(paddedValue(milliseconds, true, width));
|
||||
} else {
|
||||
buffer.append(paddedValue(milliseconds, padWithZeros, count));
|
||||
}
|
||||
}
|
||||
lastOutputSeconds = false;
|
||||
}
|
||||
//as soon as we hit first nonliteral in optional, check for literal prefix
|
||||
if (inOptional && !isLiteral && !firstOptionalNonLiteral){
|
||||
firstOptionalNonLiteral = true;
|
||||
if (lastOutputZero) {
|
||||
buffer.delete(optionalStart, buffer.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -185,6 +379,33 @@ public class DurationFormatUtils {
|
|||
return format(tokens, 0, 0, days, hours, minutes, seconds, milliseconds, padWithZeros);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the time gap as a string.
|
||||
*
|
||||
* <p>The format used is ISO 8601-like: {@code HH:mm:ss.SSS}.</p>
|
||||
*
|
||||
* @param durationMillis the duration to format
|
||||
* @return the formatted duration, not null
|
||||
* @throws IllegalArgumentException if durationMillis is negative
|
||||
*/
|
||||
public static String formatDurationHMS(final long durationMillis) {
|
||||
return formatDuration(durationMillis, "HH:mm:ss.SSS");
|
||||
}
|
||||
/**
|
||||
* Formats the time gap as a string.
|
||||
*
|
||||
* <p>The format used is the ISO 8601 period format.</p>
|
||||
*
|
||||
* <p>This method formats durations using the days and lower fields of the
|
||||
* ISO format pattern, such as P7D6TH5M4.321S.</p>
|
||||
*
|
||||
* @param durationMillis the duration to format
|
||||
* @return the formatted duration, not null
|
||||
* @throws IllegalArgumentException if durationMillis is negative
|
||||
*/
|
||||
public static String formatDurationISO(final long durationMillis) {
|
||||
return formatDuration(durationMillis, ISO_EXTENDED_FORMAT_PATTERN, false);
|
||||
}
|
||||
/**
|
||||
* Formats an elapsed time into a pluralization correct string.
|
||||
*
|
||||
|
@ -246,21 +467,6 @@ public class DurationFormatUtils {
|
|||
duration = StringUtils.replaceOnce(duration, " 1 days", " 1 day");
|
||||
return duration.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the time gap as a string.
|
||||
*
|
||||
* <p>The format used is the ISO 8601 period format.</p>
|
||||
*
|
||||
* @param startMillis the start of the duration to format
|
||||
* @param endMillis the end of the duration to format
|
||||
* @return the formatted duration, not null
|
||||
* @throws IllegalArgumentException if startMillis is greater than endMillis
|
||||
*/
|
||||
public static String formatPeriodISO(final long startMillis, final 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.
|
||||
|
@ -274,7 +480,6 @@ public class DurationFormatUtils {
|
|||
public static String formatPeriod(final long startMillis, final long endMillis, final String format) {
|
||||
return formatPeriod(startMillis, endMillis, format, true, TimeZone.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Formats the time gap as a string, using the specified format.
|
||||
* Padding the left-hand side of numbers with zeroes is optional and
|
||||
|
@ -430,134 +635,19 @@ public class DurationFormatUtils {
|
|||
|
||||
return format(tokens, years, months, days, hours, minutes, seconds, milliseconds, padWithZeros);
|
||||
}
|
||||
|
||||
/**
|
||||
* The internal method to do the formatting.
|
||||
* Formats the time gap as a string.
|
||||
*
|
||||
* @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(final Token[] tokens, final long years, final long months, final long days, final long hours, final long minutes,
|
||||
final long seconds,
|
||||
final long milliseconds, final boolean padWithZeros) {
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
boolean lastOutputSeconds = false;
|
||||
boolean lastOutputZero = false;
|
||||
int optionalStart = -1;
|
||||
boolean firstOptionalNonLiteral = false;
|
||||
int optionalIndex = -1;
|
||||
boolean inOptional = false;
|
||||
for (final Token token : tokens) {
|
||||
final Object value = token.getValue();
|
||||
final boolean isLiteral = value instanceof StringBuilder;
|
||||
final int count = token.getCount();
|
||||
if (optionalIndex != token.optionalIndex) {
|
||||
optionalIndex = token.optionalIndex;
|
||||
if (optionalIndex > -1) {
|
||||
//entering new optional block
|
||||
optionalStart = buffer.length();
|
||||
lastOutputZero = false;
|
||||
inOptional = true;
|
||||
firstOptionalNonLiteral = false;
|
||||
} else {
|
||||
//leaving optional block
|
||||
inOptional = false;
|
||||
}
|
||||
}
|
||||
if (isLiteral) {
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
buffer.append(value.toString());
|
||||
}
|
||||
} else if (value.equals(y)) {
|
||||
lastOutputSeconds = false;
|
||||
lastOutputZero = years == 0;
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
buffer.append(paddedValue(years, padWithZeros, count));
|
||||
}
|
||||
} else if (value.equals(M)) {
|
||||
lastOutputSeconds = false;
|
||||
lastOutputZero = months == 0;
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
buffer.append(paddedValue(months, padWithZeros, count));
|
||||
}
|
||||
} else if (value.equals(d)) {
|
||||
lastOutputSeconds = false;
|
||||
lastOutputZero = days == 0;
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
buffer.append(paddedValue(days, padWithZeros, count));
|
||||
}
|
||||
} else if (value.equals(H)) {
|
||||
lastOutputSeconds = false;
|
||||
lastOutputZero = hours == 0;
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
buffer.append(paddedValue(hours, padWithZeros, count));
|
||||
}
|
||||
} else if (value.equals(m)) {
|
||||
lastOutputSeconds = false;
|
||||
lastOutputZero = minutes == 0;
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
buffer.append(paddedValue(minutes, padWithZeros, count));
|
||||
}
|
||||
} else if (value.equals(s)) {
|
||||
lastOutputSeconds = true;
|
||||
lastOutputZero = seconds == 0;
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
buffer.append(paddedValue(seconds, padWithZeros, count));
|
||||
}
|
||||
} else if (value.equals(S)) {
|
||||
lastOutputZero = milliseconds == 0;
|
||||
if (!inOptional || !lastOutputZero) {
|
||||
if (lastOutputSeconds) {
|
||||
// ensure at least 3 digits are displayed even if padding is not selected
|
||||
final int width = padWithZeros ? Math.max(3, count) : 3;
|
||||
buffer.append(paddedValue(milliseconds, true, width));
|
||||
} else {
|
||||
buffer.append(paddedValue(milliseconds, padWithZeros, count));
|
||||
}
|
||||
}
|
||||
lastOutputSeconds = false;
|
||||
}
|
||||
//as soon as we hit first nonliteral in optional, check for literal prefix
|
||||
if (inOptional && !isLiteral && !firstOptionalNonLiteral){
|
||||
firstOptionalNonLiteral = true;
|
||||
if (lastOutputZero) {
|
||||
buffer.delete(optionalStart, buffer.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@code long} to a {@link String} with optional
|
||||
* zero padding.
|
||||
* <p>The format used is the ISO 8601 period format.</p>
|
||||
*
|
||||
* @param value the value to convert
|
||||
* @param padWithZeros whether to pad with zeroes
|
||||
* @param count the size to pad to (ignored if {@code padWithZeros} is false)
|
||||
* @return the string result
|
||||
* @param startMillis the start of the duration to format
|
||||
* @param endMillis the end of the duration to format
|
||||
* @return the formatted duration, not null
|
||||
* @throws IllegalArgumentException if startMillis is greater than endMillis
|
||||
*/
|
||||
private static String paddedValue(final long value, final boolean padWithZeros, final int count) {
|
||||
final String longString = Long.toString(value);
|
||||
return padWithZeros ? StringUtils.leftPad(longString, count, '0') : longString;
|
||||
public static String formatPeriodISO(final long startMillis, final long endMillis) {
|
||||
return formatPeriod(startMillis, endMillis, ISO_EXTENDED_FORMAT_PATTERN, false, TimeZone.getDefault());
|
||||
}
|
||||
|
||||
static final String y = "y";
|
||||
static final String M = "M";
|
||||
static final String d = "d";
|
||||
static final String H = "H";
|
||||
static final String m = "m";
|
||||
static final String s = "s";
|
||||
static final String S = "S";
|
||||
|
||||
/**
|
||||
* Parses a classic date format string into Tokens
|
||||
*
|
||||
|
@ -656,116 +746,26 @@ public class DurationFormatUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Element that is parsed from the format pattern.
|
||||
* Converts a {@code long} to a {@link String} with optional
|
||||
* zero padding.
|
||||
*
|
||||
* @param value the value to convert
|
||||
* @param padWithZeros whether to pad with zeroes
|
||||
* @param count the size to pad to (ignored if {@code padWithZeros} is false)
|
||||
* @return the string result
|
||||
*/
|
||||
static class Token {
|
||||
private static String paddedValue(final long value, final boolean padWithZeros, final int count) {
|
||||
final String longString = Long.toString(value);
|
||||
return padWithZeros ? StringUtils.leftPad(longString, count, '0') : longString;
|
||||
}
|
||||
|
||||
/** Empty array. */
|
||||
private static final Token[] EMPTY_ARRAY = {};
|
||||
|
||||
/**
|
||||
* Helper method to determine if a set of tokens contain a value
|
||||
*
|
||||
* @param tokens set to look in
|
||||
* @param value to look for
|
||||
* @return boolean {@code true} if contained
|
||||
*/
|
||||
static boolean containsTokenWithValue(final Token[] tokens, final Object value) {
|
||||
return Stream.of(tokens).anyMatch(token -> token.getValue() == value);
|
||||
}
|
||||
|
||||
private final Object value;
|
||||
private int count;
|
||||
private int optionalIndex = -1;
|
||||
|
||||
/**
|
||||
* Wraps a token around a value. A value would be something like a 'Y'.
|
||||
*
|
||||
* @param value value to wrap, non-null.
|
||||
* @param optional whether the token is optional
|
||||
* @param optionalIndex the index of the optional token within the pattern
|
||||
*/
|
||||
Token(final Object value, final boolean optional, final int optionalIndex) {
|
||||
this.value = Objects.requireNonNull(value, "value");
|
||||
this.count = 1;
|
||||
if (optional) {
|
||||
this.optionalIndex = optionalIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, non-null.
|
||||
*/
|
||||
Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supports equality of this Token to another Token.
|
||||
*
|
||||
* @param obj2 Object to consider equality of
|
||||
* @return boolean {@code true} if equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj2) {
|
||||
if (obj2 instanceof Token) {
|
||||
final Token tok2 = (Token) obj2;
|
||||
if (this.value.getClass() != tok2.value.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (this.count != tok2.count) {
|
||||
return false;
|
||||
}
|
||||
if (this.value instanceof StringBuilder) {
|
||||
return this.value.toString().equals(tok2.value.toString());
|
||||
}
|
||||
if (this.value instanceof Number) {
|
||||
return this.value.equals(tok2.value);
|
||||
}
|
||||
return this.value == tok2.value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code for the token equal to the
|
||||
* hash code for the token's value. Thus 'TT' and 'TTTT'
|
||||
* will have the same hash code.
|
||||
*
|
||||
* @return The hash code for the token
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.value.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents this token as a String.
|
||||
*
|
||||
* @return String representation of the token
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return StringUtils.repeat(this.value.toString(), this.count);
|
||||
}
|
||||
/**
|
||||
* DurationFormatUtils instances should NOT be constructed in standard programming.
|
||||
*
|
||||
* <p>This constructor is public to permit tools that require a JavaBean instance
|
||||
* to operate.</p>
|
||||
*/
|
||||
public DurationFormatUtils() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -106,6 +106,12 @@ public class DurationUtils {
|
|||
return !duration.isNegative() && !duration.isZero();
|
||||
}
|
||||
|
||||
private static <E extends Throwable> Instant now(final FailableConsumer<Instant, E> nowConsumer) throws E {
|
||||
final Instant start = Instant.now();
|
||||
nowConsumer.accept(start);
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the lambda and returns the duration of its execution.
|
||||
*
|
||||
|
@ -132,12 +138,6 @@ public class DurationUtils {
|
|||
return of(start -> runnable.run());
|
||||
}
|
||||
|
||||
private static <E extends Throwable> Instant now(final FailableConsumer<Instant, E> nowConsumer) throws E {
|
||||
final Instant start = Instant.now();
|
||||
nowConsumer.accept(start);
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the Duration between a start instant and now.
|
||||
*
|
||||
|
|
|
@ -108,81 +108,6 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
|||
}
|
||||
};
|
||||
|
||||
/** Our fast printer. */
|
||||
private final FastDatePrinter printer;
|
||||
|
||||
/** Our fast parser. */
|
||||
private final FastDateParser parser;
|
||||
|
||||
/**
|
||||
* Gets a formatter instance using the default pattern in the
|
||||
* default locale.
|
||||
*
|
||||
* @return a date/time formatter
|
||||
*/
|
||||
public static FastDateFormat getInstance() {
|
||||
return cache.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(final String pattern) {
|
||||
return cache.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(final String pattern, final TimeZone timeZone) {
|
||||
return cache.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(final String pattern, final Locale locale) {
|
||||
return cache.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 {@code null}
|
||||
*/
|
||||
public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
|
||||
return cache.getInstance(pattern, timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a date formatter instance using the specified style in the
|
||||
* default time zone and locale.
|
||||
|
@ -244,6 +169,141 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
|||
return cache.getDateInstance(style, timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(final int dateStyle, final int timeStyle) {
|
||||
return cache.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(final int dateStyle, final int timeStyle, final Locale locale) {
|
||||
return cache.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(final int dateStyle, final int timeStyle, final 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 FastDateFormat getDateTimeInstance(
|
||||
final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) {
|
||||
return cache.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a formatter instance using the default pattern in the
|
||||
* default locale.
|
||||
*
|
||||
* @return a date/time formatter
|
||||
*/
|
||||
public static FastDateFormat getInstance() {
|
||||
return cache.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(final String pattern) {
|
||||
return cache.getInstance(pattern, null, 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(final String pattern, final Locale locale) {
|
||||
return cache.getInstance(pattern, null, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(final String pattern, final TimeZone timeZone) {
|
||||
return cache.getInstance(pattern, timeZone, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {@code null}
|
||||
*/
|
||||
public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
|
||||
return cache.getInstance(pattern, timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a time formatter instance using the specified style in the
|
||||
* default time zone and locale.
|
||||
|
@ -305,70 +365,10 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
|||
return cache.getTimeInstance(style, timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(final int dateStyle, final int timeStyle) {
|
||||
return cache.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(final int dateStyle, final int timeStyle, final Locale locale) {
|
||||
return cache.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(final int dateStyle, final int timeStyle, final 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 FastDateFormat getDateTimeInstance(
|
||||
final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) {
|
||||
return cache.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale);
|
||||
}
|
||||
/** Our fast printer. */
|
||||
private final FastDatePrinter printer;
|
||||
/** Our fast parser. */
|
||||
private final FastDateParser parser;
|
||||
|
||||
// Constructor
|
||||
/**
|
||||
|
@ -398,43 +398,35 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
|||
parser = new FastDateParser(pattern, timeZone, locale, centuryStart);
|
||||
}
|
||||
|
||||
// Format methods
|
||||
/**
|
||||
* Formats a {@link Date}, {@link Calendar} or
|
||||
* {@link Long} (milliseconds) object.
|
||||
* This method is an implementation of {@link Format#format(Object, StringBuffer, FieldPosition)}
|
||||
* Performs the formatting by applying the rules to the
|
||||
* specified calendar.
|
||||
*
|
||||
* @param obj the object to format
|
||||
* @param toAppendTo the buffer to append to
|
||||
* @param pos the position - ignored
|
||||
* @return the buffer passed in
|
||||
* @param calendar the calendar to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @deprecated Use {@link #format(Calendar, Appendable)}
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
|
||||
return toAppendTo.append(printer.format(obj));
|
||||
@Deprecated
|
||||
protected StringBuffer applyRules(final Calendar calendar, final StringBuffer buf) {
|
||||
return printer.applyRules(calendar, buf);
|
||||
}
|
||||
|
||||
// Basics
|
||||
/**
|
||||
* Formats a millisecond {@code long} value.
|
||||
* Compares two objects for equality.
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @return the formatted string
|
||||
* @since 2.1
|
||||
* @param obj the object to compare to
|
||||
* @return {@code true} if equal
|
||||
*/
|
||||
@Override
|
||||
public String format(final long millis) {
|
||||
return printer.format(millis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a {@link Date} object using a {@link GregorianCalendar}.
|
||||
*
|
||||
* @param date the date to format
|
||||
* @return the formatted string
|
||||
*/
|
||||
@Override
|
||||
public String format(final Date date) {
|
||||
return printer.format(date);
|
||||
public boolean equals(final Object obj) {
|
||||
if (!(obj instanceof FastDateFormat)) {
|
||||
return false;
|
||||
}
|
||||
final FastDateFormat other = (FastDateFormat) obj;
|
||||
// no need to check parser, as it has same invariants as printer
|
||||
return printer.equals(other.printer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -449,34 +441,17 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Formats a millisecond {@code long} value into the
|
||||
* Formats a {@link Calendar} object into the
|
||||
* supplied {@link StringBuffer}.
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @param calendar the calendar to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @since 2.1
|
||||
* @deprecated Use {{@link #format(long, Appendable)}.
|
||||
*/
|
||||
@Deprecated
|
||||
* @since 3.5
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(final long millis, final StringBuffer buf) {
|
||||
return printer.format(millis, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a {@link Date} object into the
|
||||
* supplied {@link StringBuffer} using a {@link GregorianCalendar}.
|
||||
*
|
||||
* @param date the date to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @deprecated Use {{@link #format(Date, Appendable)}.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public StringBuffer format(final Date date, final StringBuffer buf) {
|
||||
return printer.format(date, buf);
|
||||
public <B extends Appendable> B format(final Calendar calendar, final B buf) {
|
||||
return printer.format(calendar, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -495,17 +470,14 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Formats a millisecond {@code long} value into the
|
||||
* supplied {@link StringBuffer}.
|
||||
* Formats a {@link Date} object using a {@link GregorianCalendar}.
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @since 3.5
|
||||
* @param date the date to format
|
||||
* @return the formatted string
|
||||
*/
|
||||
@Override
|
||||
public <B extends Appendable> B format(final long millis, final B buf) {
|
||||
return printer.format(millis, buf);
|
||||
public String format(final Date date) {
|
||||
return printer.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -523,22 +495,137 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Formats a {@link Calendar} object into the
|
||||
* Formats a {@link Date} object into the
|
||||
* supplied {@link StringBuffer} using a {@link GregorianCalendar}.
|
||||
*
|
||||
* @param date the date to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @deprecated Use {{@link #format(Date, Appendable)}.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public StringBuffer format(final Date date, final StringBuffer buf) {
|
||||
return printer.format(date, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a millisecond {@code long} value.
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @return the formatted string
|
||||
* @since 2.1
|
||||
*/
|
||||
@Override
|
||||
public String format(final long millis) {
|
||||
return printer.format(millis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a millisecond {@code long} value into the
|
||||
* supplied {@link StringBuffer}.
|
||||
*
|
||||
* @param calendar the calendar to format
|
||||
* @param millis the millisecond value to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @since 3.5
|
||||
*/
|
||||
*/
|
||||
@Override
|
||||
public <B extends Appendable> B format(final Calendar calendar, final B buf) {
|
||||
return printer.format(calendar, buf);
|
||||
public <B extends Appendable> B format(final long millis, final B buf) {
|
||||
return printer.format(millis, buf);
|
||||
}
|
||||
|
||||
// Parsing
|
||||
|
||||
|
||||
/**
|
||||
* Formats a millisecond {@code long} value into the
|
||||
* supplied {@link StringBuffer}.
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @since 2.1
|
||||
* @deprecated Use {{@link #format(long, Appendable)}.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public StringBuffer format(final long millis, final StringBuffer buf) {
|
||||
return printer.format(millis, buf);
|
||||
}
|
||||
|
||||
// Format methods
|
||||
/**
|
||||
* Formats a {@link Date}, {@link Calendar} or
|
||||
* {@link Long} (milliseconds) object.
|
||||
* This method is an implementation of {@link Format#format(Object, StringBuffer, FieldPosition)}
|
||||
*
|
||||
* @param obj the object to format
|
||||
* @param toAppendTo the buffer to append to
|
||||
* @param pos the position - ignored
|
||||
* @return the buffer passed in
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
|
||||
return toAppendTo.append(printer.format(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the locale used by this formatter.
|
||||
*
|
||||
* @return the locale
|
||||
*/
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return printer.getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an estimate for the maximum string length that the
|
||||
* formatter will produce.
|
||||
*
|
||||
* <p>The actual formatted length will almost always be less than or
|
||||
* equal to this amount.</p>
|
||||
*
|
||||
* @return the maximum formatted length
|
||||
*/
|
||||
public int getMaxLengthEstimate() {
|
||||
return printer.getMaxLengthEstimate();
|
||||
}
|
||||
|
||||
// Accessors
|
||||
/**
|
||||
* Gets the pattern used by this formatter.
|
||||
*
|
||||
* @return the pattern, {@link java.text.SimpleDateFormat} compatible
|
||||
*/
|
||||
@Override
|
||||
public String getPattern() {
|
||||
return printer.getPattern();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time zone used by this formatter.
|
||||
*
|
||||
* <p>This zone is always used for {@link Date} formatting.</p>
|
||||
*
|
||||
* @return the time zone
|
||||
*/
|
||||
@Override
|
||||
public TimeZone getTimeZone() {
|
||||
return printer.getTimeZone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code compatible with equals.
|
||||
*
|
||||
* @return a hash code compatible with equals
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return printer.hashCode();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see DateParser#parse(String)
|
||||
*/
|
||||
|
@ -572,79 +659,6 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
|||
return parser.parseObject(source, pos);
|
||||
}
|
||||
|
||||
// Accessors
|
||||
/**
|
||||
* Gets the pattern used by this formatter.
|
||||
*
|
||||
* @return the pattern, {@link java.text.SimpleDateFormat} compatible
|
||||
*/
|
||||
@Override
|
||||
public String getPattern() {
|
||||
return printer.getPattern();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time zone used by this formatter.
|
||||
*
|
||||
* <p>This zone is always used for {@link Date} formatting.</p>
|
||||
*
|
||||
* @return the time zone
|
||||
*/
|
||||
@Override
|
||||
public TimeZone getTimeZone() {
|
||||
return printer.getTimeZone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the locale used by this formatter.
|
||||
*
|
||||
* @return the locale
|
||||
*/
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return printer.getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an estimate for the maximum string length that the
|
||||
* formatter will produce.
|
||||
*
|
||||
* <p>The actual formatted length will almost always be less than or
|
||||
* equal to this amount.</p>
|
||||
*
|
||||
* @return the maximum formatted length
|
||||
*/
|
||||
public int getMaxLengthEstimate() {
|
||||
return printer.getMaxLengthEstimate();
|
||||
}
|
||||
|
||||
// Basics
|
||||
/**
|
||||
* Compares two objects for equality.
|
||||
*
|
||||
* @param obj the object to compare to
|
||||
* @return {@code true} if equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (!(obj instanceof FastDateFormat)) {
|
||||
return false;
|
||||
}
|
||||
final FastDateFormat other = (FastDateFormat) obj;
|
||||
// no need to check parser, as it has same invariants as printer
|
||||
return printer.equals(other.printer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code compatible with equals.
|
||||
*
|
||||
* @return a hash code compatible with equals
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return printer.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a debugging string version of this formatter.
|
||||
*
|
||||
|
@ -654,18 +668,4 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
|||
public String toString() {
|
||||
return "FastDateFormat[" + printer.getPattern() + "," + printer.getLocale() + "," + printer.getTimeZone().getID() + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @deprecated Use {@link #format(Calendar, Appendable)}
|
||||
*/
|
||||
@Deprecated
|
||||
protected StringBuffer applyRules(final Calendar calendar, final StringBuffer buf) {
|
||||
return printer.applyRules(calendar, buf);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -28,10 +28,6 @@ import org.apache.commons.lang3.ObjectUtils;
|
|||
*/
|
||||
public class TimeZones {
|
||||
|
||||
/** Do not instantiate. */
|
||||
private TimeZones() {
|
||||
}
|
||||
|
||||
/**
|
||||
* A public version of {@link java.util.TimeZone}'s package private {@code GMT_ID} field.
|
||||
*/
|
||||
|
@ -55,4 +51,8 @@ public class TimeZones {
|
|||
return ObjectUtils.getIfNull(timeZone, TimeZone::getDefault);
|
||||
}
|
||||
|
||||
/** Do not instantiate. */
|
||||
private TimeZones() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue