
org.flexdock.util.Utilities Maven / Gradle / Ivy
/*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.flexdock.util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
/**
* @author Christopher Butler
*/
public class Utilities {
/**
* A constant representing the Java version. This constant is {@code true}
* if the version is 1.4.
*/
public static final boolean JAVA_1_4 = isJavaVersion("1.4");
/**
* A constant representing the Java version. This constant is {@code true}
* if the version is 1.5.
*/
public static final boolean JAVA_1_5 = isJavaVersion("1.5");
/**
* A String representing the flexdock version. This constant is a string.
*/
public static final String VERSION = "1.2.4";
private Utilities() {
// does nothing
}
/**
* Returns an {@code int} value for the specified {@code String}. This
* method calls {@code Integer.parseInt(String s)} and returns the resulting
* {@code int} value. If any {@code Exception} is thrown, this method
* returns a value of {@code 0}.
*
* @param data
* a {@code String} containing the {@code int} representation to
* be parsed
* @return the integer value represented by the argument in decimal
* @see #getInt(String, int)
* @see Integer#parseInt(java.lang.String)
*/
public static int getInt(String data) {
return getInt(data, 0);
}
/**
* Returns an {@code int} value for the specified {@code String}. This
* method calls {@code Integer.parseInt(String s)} and returns the resulting
* {@code int} value. If any {@code Exception} is thrown, this method
* returns the value supplied by the {@code defaultValue} parameter.
*
* @param data
* a {@code String} containing the {@code int} representation to
* be parsed
* @param defaultValue
* the value to return if an {@code Exception} is encountered.
* @return the integer value represented by the argument in decimal
* @see Integer#parseInt(java.lang.String)
*/
public static int getInt(String data, int defaultValue) {
if (data == null) {
return defaultValue;
}
try {
return Integer.parseInt(data);
} catch (Exception e) {
return defaultValue;
}
}
/**
* Returns a {@code float} value for the specified {@code String}. This
* method calls {@code Float.parseFloat(String s)} and returns the resulting
* {@code float} value. If any {@code Exception} is thrown by
* {@code parseFloat}, this method returns the value supplied by the
* {@code defaultValue} parameter.
*
* @param data
* a {@code String} containing the {@code float} representation
* to be parsed
* @param defaultValue
* the value to return if an {@code Exception} is encountered on
* the underlying parse mechanism.
* @return the floating-point value represented by the argument in decimal
* @see Float#parseFloat(java.lang.String)
*/
public static float getFloat(String data, float defaultValue) {
if (data == null) {
return defaultValue;
}
try {
return Float.parseFloat(data);
} catch (Exception e) {
return defaultValue;
}
}
/**
* Returns {@code true} if the specified {@code String} is {@code null} or
* contains only whitespace. Otherwise, returns {@code false}. The
* whitespace check is performed by calling {@code trim()} and checking to
* see if the trimmed string {@code length()} is zero.
*
* @param data
* the {@code String} to check for non-whitespace content
* @return {@code true} if the specified {@code String} is {@code null} or
* contains only whitespace, {@code false} otherwise.
*/
public static boolean isEmpty(String data) {
return data == null ? true : data.trim().length() == 0;
}
/**
* Returns an instance of the specified class name. If {@code className} is
* {@code null}, then this method returns a {@code null} reference.
*
* This method will try two different means of obtaining an instance of
* {@code className}. First, it will attempt to resolve the {@code Class}
* of {@code className} via {@code Class.forName(String className)}. It
* will then use reflection to search for a method on the class named
* {@code "getInstance()"}. If the method is found, then it is invoked and
* the object instance is returned.
*
* If there are any problems encountered while attempting to invoke
* {@code getInstance()} on the specified class, the {@code Throwable} is
* caught and this method dispatches to
* {@code createInstance(String className, boolean failSilent)} with an
* argument of {@code false} for {@code failSilent}.
* {@code createInstance(String className, boolean failSilent)} will attempt
* to invoke {@code newInstance()} on the {@code Class} for the specified
* class name. If any {@code Throwable} is encountered during this process,
* the value of {@code false} for {@code failSilent} will cause the stack
* trace to be printed to the {@code System.err} and a {@code null}
* reference will be returned.
*
* @param className
* the fully qualified name of the desired class.
* @return an instance of the specified class
* @see #getInstance(String, boolean)
* @see #createInstance(String, boolean)
* @see Class#forName(java.lang.String)
* @see Class#getMethod(java.lang.String, java.lang.Class[])
* @see Method#invoke(java.lang.Object, java.lang.Object[])
* @see Class#newInstance()
*/
public static Object getInstance(String className) {
return getInstance(className, false);
}
/**
* Returns an instance of the specified class name. If {@code className} is
* {@code null}, then this method returns a {@code null} reference.
*
* This method will try two different means of obtaining an instance of
* {@code className}. First, it will attempt to resolve the {@code Class}
* of {@code className} via {@code Class.forName(String className)}. It
* will then use reflection to search for a method on the class named
* {@code "getInstance()"}. If the method is found, then it is invoked and
* the object instance is returned.
*
* If there are any problems encountered while attempting to invoke
* {@code getInstance()} on the specified class, the {@code Throwable} is
* caught and this method dispatches to
* {@code createInstance(String className, boolean failSilent)}, passing
* the specified value for {@code failSilent}.
* {@code createInstance(String className, boolean failSilent)} will attempt
* to invoke {@code newInstance()} on the {@code Class} for the specified
* class name. If any {@code Throwable} is encountered during this process,
* the value of {@code failSilent} is checked to determine whether the stack
* stack trace should be printed to the {@code System.err}. A {@code null}
* reference will be returned if any problems are encountered.
*
* @param className
* the fully qualified name of the desired class.
* @param failSilent
* {@code true} if the stack trace should not be printed
* to the {@code System.err} when a {@code Throwable} is caught,
* {@code false} otherwise.
* @return an instance of the specified class
* @see #createInstance(String, boolean)
* @see Class#forName(java.lang.String)
* @see Class#getMethod(java.lang.String, java.lang.Class[])
* @see Method#invoke(java.lang.Object, java.lang.Object[])
* @see Class#newInstance()
*/
public static Object getInstance(String className, boolean failSilent) {
if (className == null) {
return null;
}
try {
Class c = Class.forName(className);
Method m = c.getMethod("getInstance", new Class[0]);
return m.invoke(null, new Object[0]);
} catch (Throwable e) {
return createInstance(className, failSilent);
}
}
/**
* Creates and returns an instance of the specified class name using
* {@code Class.newInstance()}. If {@code className} is {@code null}, then
* this method returns a {@code null} reference. This dispatches to
* {@code createInstance(String className, Class superType, boolean failSilent)}
* with an argument of {@code null} for {@code superType} and {@code false}
* for {@code failSilent}.
*
* This method will attempt to resolve the {@code Class} of
* {@code className} via {@code Class.forName(String className)}. No class
* assignability checkes are performed because this method uses a
* {@code null} {@code superType}.
*
* Once the desired class has been resolved, a new instance of it is created
* and returned by invoking its {@code newInstance()} method. If there are
* any problems encountered during this process, the value of {@code false}
* for {@code failSilent} will ensure the stack stack trace is be printed to
* the {@code System.err}. A {@code null} reference will be returned if any
* problems are encountered.
*
* @param className
* the fully qualified name of the desired class.
* @return an instance of the specified class
* @see #createInstance(String, Class, boolean)
* @see Class#forName(java.lang.String)
* @see Class#newInstance()
*/
public static Object createInstance(String className) {
return createInstance(className, null);
}
/**
* Creates and returns an instance of the specified class name using
* {@code Class.newInstance()}. If {@code className} is {@code null}, then
* this method returns a {@code null} reference. The {@code failSilent}
* parameter will determine whether error stack traces should be reported to
* the {@code System.err} before this method returns {@code null}. This
* method dispatches to
* {@code createInstance(String className, Class superType, boolean failSilent)}
* with an argument of {@code null} for {@code superType}.
*
* This method will attempt to resolve the {@code Class} of
* {@code className} via {@code Class.forName(String className)}. No class
* assignability checkes are performed because this method uses a
* {@code null} {@code superType}.
*
* Once the desired class has been resolved, a new instance of it is created
* and returned by invoking its {@code newInstance()} method. If there are
* any problems encountered during this process, the value of
* {@code failSilent} is checked to determine whether the stack stack trace
* should be printed to the {@code System.err}. A {@code null} reference
* will be returned if any problems are encountered.
*
* @param className
* the fully qualified name of the desired class.
* @param failSilent
* {@code true} if the stack trace should not be printed
* to the {@code System.err} when a {@code Throwable} is caught,
* {@code false} otherwise.
* @return an instance of the specified class
* @see #createInstance(String, Class, boolean)
* @see Class#forName(java.lang.String)
* @see Class#newInstance()
*/
public static Object createInstance(String className, boolean failSilent) {
return createInstance(className, null, failSilent);
}
/**
* Creates and returns an instance of the specified class name using
* {@code Class.newInstance()}. If {@code className} is {@code null}, then
* this method returns a {@code null} reference. If {@code superType} is
* non-{@code null}, then this method will enforce polymorphic identity
* via {@code Class.isAssignableFrom(Class cls)}. This method dispatches to
* {@code createInstance(String className, Class superType, boolean failSilent)}
* with an argument of {@code false} for {@code failSilent}.
*
* This method will attempt to resolve the {@code Class} of
* {@code className} via {@code Class.forName(String className)}. If
* {@code superType} is non-{@code null}, then class identity is checked
* by calling {@code superType.isAssignableFrom(c)} to ensure the resolved
* class is an valid equivalent, descendent, or implementation of the
* specified {@code className}. If this check fails, then a
* {@code ClassCastException} is thrown and caught internally and this
* method returns {@code null}. If {@code superType} is {@code null}, then
* no assignability checks are performed on the resolved class.
*
* Once the desired class has been resolved, a new instance of it is created
* and returned by invoking its {@code newInstance()} method. If there are
* any problems encountered during this process, the value of {@code false}
* for {@code failSilent} will ensure the stack stack trace is be printed to
* the {@code System.err}. A {@code null} reference will be returned if any
* problems are encountered.
*
* @param className
* the fully qualified name of the desired class.
* @param superType
* optional paramter used as a means of enforcing the inheritance
* hierarchy
* @return an instance of the specified class
* @see #createInstance(String, Class, boolean)
* @see Class#forName(java.lang.String)
* @see Class#isAssignableFrom(java.lang.Class)
* @see Class#newInstance()
*/
public static Object createInstance(String className, Class superType) {
return createInstance(className, superType, false);
}
/**
* Creates and returns an instance of the specified class name using
* {@code Class.newInstance()}. If {@code className} is {@code null}, then
* this method returns a {@code null} reference. If {@code superType} is
* non-{@code null}, then this method will enforce polymorphic identity
* via {@code Class.isAssignableFrom(Class cls)}. The {@code failSilent}
* parameter will determine whether error stack traces should be reported to
* the {@code System.err} before this method returns {@code null}.
*
* This method will attempt to resolve the {@code Class} of
* {@code className} via {@code Class.forName(String className)}. If
* {@code superType} is non-{@code null}, then class identity is checked
* by calling {@code superType.isAssignableFrom(c)} to ensure the resolved
* class is an valid equivalent, descendent, or implementation of the
* specified {@code className}. If this check fails, then a
* {@code ClassCastException} is thrown and caught internally and this
* method returns {@code null}. If {@code superType} is {@code null}, then
* no assignability checks are performed on the resolved class.
*
* Once the desired class has been resolved, a new instance of it is created
* and returned by invoking its {@code newInstance()} method. If there are
* any problems encountered during this process, the value of
* {@code failSilent} is checked to determine whether the stack stack trace
* should be printed to the {@code System.err}. A {@code null} reference
* will be returned if any problems are encountered.
*
* @param className
* the fully qualified name of the desired class.
* @param superType
* optional paramter used as a means of enforcing the inheritance
* hierarchy
* @param failSilent
* {@code true} if the stack trace should not be printed
* to the {@code System.err} when a {@code Throwable} is caught,
* {@code false} otherwise.
* @return an instance of the specified class
* @see Class#forName(java.lang.String)
* @see Class#isAssignableFrom(java.lang.Class)
* @see Class#newInstance()
*/
public static Object createInstance(String className, Class superType,
boolean failSilent) {
if (className == null) {
return null;
}
try {
Class c = Class.forName(className);
if (superType != null && !superType.isAssignableFrom(c)) {
throw new ClassCastException("'" + c.getName()
+ "' is not a type of " + superType + ".");
}
return c.newInstance();
} catch (Throwable e) {
if (!failSilent) {
System.err.println("Exception: " +e.getMessage());
}
return null;
}
}
/**
* Checks for equality between the two specified {@code Objects}. If both
* arguments are the same {@code Object} reference using an {@code ==}
* relationship, then this method returns {@code true}. Failing that check,
* if either of the arguments is {@code null}, then the other must not be
* and this method returns {@code false}. Finally, if both arguments are
* non-{@code null} with different {@code Object} references, then this
* method returns the value of {@code obj1.equals(obj2)}.
*
* This method is the exact opposite of
* {@code isChanged(Object oldObj, Object newObj)}.
*
* @param obj1
* the first {@code Object} to be checked for equality
* @param obj2
* the second {@code Object} to be checked for equality
* @return {@code true} if the {@code Objects} are equal, {@code false}
* otherwise.
* @see #isChanged(Object, Object)
* @see Object#equals(java.lang.Object)
*/
public static boolean isEqual(Object obj1, Object obj2) {
return !isChanged(obj1, obj2);
}
/**
* Checks for inequality between the two specified {@code Objects}. If both
* arguments are the same {@code Object} reference using an {@code ==}
* relationship, then this method returns {@code false}. Failing that
* check, if either of the arguments is {@code null}, then the other must
* not be and this method returns {@code true}. Finally, if both arguments
* are non-{@code null} with different {@code Object} references, then this
* method returns the opposite value of {@code obj1.equals(obj2)}.
*
* This method is the exact opposite of
* {@code isEqual(Object obj1, Object obj2)}.
*
* @param oldObj
* the first {@code Object} to be checked for inequality
* @param newObj
* the second {@code Object} to be checked for inequality
* @return {@code false} if the {@code Objects} are equal, {@code true}
* otherwise.
* @see #isEqual(Object, Object)
* @see Object#equals(java.lang.Object)
*/
public static boolean isChanged(Object oldObj, Object newObj) {
if (oldObj == newObj) {
return false;
}
if (oldObj == null || newObj == null) {
return true;
}
return !oldObj.equals(newObj);
}
/**
* Returns {@code true} if there is currently a {@code System} property with
* the specified {@code key} whose value is "true". If the {@code System}
* property does not exist, or the value is inequal to "true", this method
* returns {@code false}. This method returns {@code false} if the
* specified {@code key} parameter is {@code null}.
*
* @param key
* the {@code System} property to test.
* @return {@code true} if there is currently a {@code System} property with
* the specified {@code key} whose value is "true".
* @see System#getProperty(java.lang.String)
* @see String#equals(java.lang.Object)
* @deprecated Use {@link Boolean#getBoolean(String)}.
*/
public static boolean sysTrue(String key) {
String value = key == null ? null : System.getProperty(key);
return value == null ? false : "true".equals(value);
}
/**
* Puts the supplied {@code value} into the specified {@code Map} using the
* specified {@code key}. This is a convenience method to automate
* null-checks. A {@code value} parameter of {@code null} is interpreted as
* a removal from the specified {@code Map} rather than an {@code put}
* operation.
*
* If either {@code map} or {@code key} are {@code null} then this method
* returns with no action taken. If {@code value} is {@code null},
* then this method calls {@code map.remove(key)}. Otherwise, this method
* calls {@code map.put(key, value)}.
*
* @param map
* the {@code Map} whose contents is to be modified
* @param key
* with which the specified value is to be associated.
* @param value
* value to be associated with the specified key.
* @see Map#put(java.lang.Object, java.lang.Object)
* @see Map#remove(java.lang.Object)
*/
public static void put(Map map, Object key, Object value) {
if (map == null || key == null) {
return;
}
if (value == null) {
map.remove(key);
} else {
map.put(key, value);
}
}
/**
* Returns the value of the specified {@code fieldName} within the specified
* {@code Object}. This is a convenience method for reflection hacks to
* retrieve the value of protected, private, or package-private field
* members while hiding the boilerplate reflection code within a single
* utility method call. This method will return {@code true} if the
* operation was successful and {@code false} if errors were encountered.
*
* This method calls {@code obj.getClass()} to retrieve the {@code Class} of
* the specified {@code Object}. It then retrieves the desired field by
* calling the classes' {@code getDeclaredField(String name)} method,
* passing the specified field name. If the field is deemed inaccessible via
* it's {@code isAccessible()} method, then it is made accessible by calling
* {@code setAccessible(true)}. The field value is set by invoking the
* field's {@code set(Object obj, Object value)} method and passing the
* original {@code Object} and {@code value} parameter as arguments. Before
* returning, the field's accessibility is reset to its original state.
*
* If either {@code obj} or {@code fieldName} are {@code null}, then this
* method returns {@code false}.
*
* It should be understood that this method will not function properly for
* inaccessible fields in the presence of a {@code SecurityManager}. Nor
* will it function properly for non-existent fields (if a field called
* {@code fieldName} does not exist on the class). All {@code Throwable}s
* encountered by this method will be caught and eaten and the method will
* return {@code false}. This works under the assumption that the operation
* might likely fail because the method itself is, in reality, a convenience
* hack. Therefore, specifics of any generated errors on the call stack are
* discarded and only the final outcome ({@code true}/{@code false}) of the
* operation is deemed relevant.
*
* If call stack data is required within the application for any thrown
* exceptions, then this method should not be used.
*
* @param obj
* the object for which the represented field's value is to be
* modified
* @param fieldName
* the name of the field to be set
* @param value
* the new value for the field of {@code obj} being modified
* @return as described
* @see Object#getClass()
* @see Class#getDeclaredField(java.lang.String)
* @see Field#isAccessible()
* @see Field#setAccessible(boolean)
* @see Field#set(Object, Object)
*/
public static boolean setValue(Object obj, String fieldName, Object value) {
if (obj == null || fieldName == null) {
return false;
}
try {
Class c = obj.getClass();
Field field = c.getDeclaredField(fieldName);
if (field.isAccessible()) {
field.set(obj, value);
return true;
}
field.setAccessible(true);
field.set(obj, value);
field.setAccessible(false);
return true;
} catch (Throwable t) {
// don't report the error. the purpse of this method is to try to
// access the field, but fail silently if we can't.
return false;
}
}
/**
* Returns the value of the specified {@code fieldName} within the specified
* {@code Object}. This is a convenience method for reflection hacks to
* retrieve the value of protected, private, or package-private field
* members while hiding the boilerplate reflection code within a single
* utility method call.
*
* This method calls {@code obj.getClass()} to retrieve the {@code Class} of
* the specified {@code Object}. It then retrieves the desired field by
* calling the classes' {@code getDeclaredField(String name)} method,
* passing the specified field name. If the field is deemed inaccessible via
* it's {@code isAccessible()} method, then it is made accessible by calling
* {@code setAccessible(true)}. The return value is retrieved by invoking
* the field's {@code get(Object obj)} method and passing the original
* {@code Object} parameter as an argument. Before returning, the field's
* accessibility is reset to its original state.
*
* If either {@code obj} or {@code fieldName} are {@code null}, then this
* method returns {@code null}.
*
* It should be understood that this method will not function properly for
* inaccessible fields in the presence of a {@code SecurityManager}. Nor
* will it function properly for non-existent fields (if a field called
* {@code fieldName} does not exist on the class). All {@code Throwables}
* encountered by this method will be rethrown as
* {@code IllegalAccessException}. For wrapped {@code Throwable}s, the
* original cause can be accessed via {@code IllegalAccessException's}
* {@code getCause()} method.
*
* @param obj
* the object from which the represented field's value is to be
* extracted
* @param fieldName
* the name of the field to be checked
* @return the value of the represented field in object {@code obj};
* primitive values are wrapped in an appropriate object before
* being returned
* @throws IllegalAccessException all {@code Throwable}s as described
* @see Object#getClass()
* @see Class#getDeclaredField(java.lang.String)
* @see Field#isAccessible()
* @see Field#setAccessible(boolean)
* @see Field#get(java.lang.Object)
* @see IllegalAccessException#getCause()
*/
public static Object getValue(Object obj, String fieldName)
throws IllegalAccessException {
if (obj == null || fieldName == null) {
return null;
}
try {
Class c = obj.getClass();
Field field = c.getDeclaredField(fieldName);
if (field.isAccessible()) {
return field.get(obj);
}
field.setAccessible(true);
Object ret = field.get(obj);
field.setAccessible(false);
return ret;
} catch (Throwable t) {
if (t instanceof IllegalAccessException) {
throw (IllegalAccessException) t;
}
IllegalAccessException e = new IllegalAccessException(t
.getMessage());
e.initCause(t);
throw e;
}
}
/**
* Puts the current {@code Thread} to sleep for the specified timeout. This
* method calls {@code Thread.sleep(long millis)}, catching any thrown
* {@code InterruptedException} and printing a stack trace to the
* {@code System.err}.
*
* @param millis
* the length of time to sleep in milliseconds.
* @see Thread#sleep(long)
*/
public static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
System.err.println("Exception: " +e.getMessage());
e.printStackTrace();
}
}
private static boolean isJavaVersion(String version) {
if (version == null) {
return false;
}
return System.getProperty("java.version").startsWith(version);
}
}