gov.sandia.cognition.util.ObjectUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cognitive-foundry Show documentation
Show all versions of cognitive-foundry Show documentation
A single jar with all the Cognitive Foundry components.
/*
* File: ObjectUtil.java
* Authors: Justin Basilico
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright June 28, 2007, Sandia Corporation. Under the terms of Contract
* DE-AC04-94AL85000, there is a non-exclusive license for use of this work by
* or on behalf of the U.S. Government. Export of this program may require a
* license from the United States Government. See CopyrightHistory.txt for
* complete details.
*
*/
package gov.sandia.cognition.util;
import gov.sandia.cognition.collection.CollectionUtil;
import gov.sandia.cognition.io.FileUtil;
import gov.sandia.cognition.io.ObjectSerializationHandler;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* The ObjectUtil class implements static utility methods for dealing with
* Objects.
*
* @author Justin Basilico
* @since 2.0
*/
public class ObjectUtil
extends Object
{
/**
* Determines if two objects are equals in a way that is safe for dealing
* with null. Null is only equal to itself.
*
* @param first The first object.
* @param second The second object.
* @return True if the two objects are equal and false otherwise.
*/
public static boolean equalsSafe(
Object first,
Object second)
{
if ( first == null )
{
// Only equal if both are null.
return second == null;
}
else if ( second == null )
{
// First is not null so they are not equal.
return false;
}
else
{
// Call the equals method.
return first.equals(second);
}
}
/**
* Determines the hash code of the given value by calling the hashCode
* method on the given object if it is not null. If it is null, 0 is
* returned.
*
* @param value
* The value to get the hash code for. May be null.
* @return
* The hash code of the given value if it is not null; otherwise, 0.
*/
public static int hashCodeSafe(
final Object value)
{
if (value == null)
{
return 0;
}
else
{
return value.hashCode();
}
}
/**
* Calls the Clone method on the given object of some type that extends
* CloneableSerializable.
*
* Note: It assumes that the given object's clone method will return the
* same object of type T.
*
* @param The type of the object to clone.
* @param object The object to clone.
* @return The clone.
*/
@SuppressWarnings("unchecked")
public static T cloneSafe(
T object)
{
if ( object == null )
{
return null;
}
else
{
return (T) object.clone();
}
}
/**
* Attempts to clone a given object. If the passed object is null, then
* null is returned. Otherwise, it checks to see if the object implements
* the {@code CloneableSerializable} interface. If it does, it calls the
* {@code cloneSafe} method with it. If not, it attempts to see if there is
* a clone method on the given object, and if so it attempts to call the
* method. If this fails, then it just returns the given object.
*
* Note: It assumes that the given object's clone method will return the
* same object of type T.
*
* @param The type of the object to clone.
* @param object The object to clone.
* @return
* A clone of the given object, if it possible to clone it. If it is
* not, then the original object is returned.
*/
@SuppressWarnings("unchecked")
public static T cloneSmart(
final T object)
{
if (object == null)
{
// Its null, so there is no clone.
return null;
}
else if (object instanceof CloneableSerializable)
{
// Try to clone via the CloneableSerializable interface.
return (T) cloneSafe((CloneableSerializable) object);
}
// Look for a clone method by reflection.
final Class> clazz = object.getClass();
Method cloneMethod = null;
try
{
cloneMethod = clazz.getDeclaredMethod("clone");
}
catch (NoSuchMethodException ex)
{
}
catch (SecurityException ex)
{
}
if (cloneMethod != null)
{
// Try to invoke the clone method.
try
{
final Object clone = cloneMethod.invoke(object);
return (T) clone;
}
catch (IllegalAccessException ex)
{
}
catch (IllegalArgumentException ex)
{
}
catch (InvocationTargetException ex)
{
}
}
// Couldn't clone it, so just return the original.
return object;
}
/**
* Creates a new {@code ArrayList} and attempts to copy all of the elements
* from the given collection into it by calling the cloneSmart method on
* each of them.
*
* @param The type of the elements in the list.
* @param collection The collection of elements to clone.
* @return A new {@code ArrayList} with a clone of each element in it.
*/
public static ArrayList cloneSmartElementsAsArrayList(
final Collection collection)
{
if( collection == null )
{
return null;
}
final ArrayList result = new ArrayList(collection.size());
for (T value : collection)
{
result.add(cloneSmart(value));
}
return result;
}
/**
* Creates a new {@code LinkedList} and attempts to copy all of the elements
* from the given collection into it by calling the cloneSmart method on
* each of them.
*
* @param The type of the elements in the list.
* @param collection The collection of elements to clone.
* @return A new {@code LinkedList} with a clone of each element in it.
*/
public static LinkedList cloneSmartElementsAsLinkedList(
final Iterable collection)
{
if( collection == null )
{
return null;
}
final LinkedList result = new LinkedList();
for (T value : collection)
{
result.add(cloneSmart(value));
}
return result;
}
/**
* Clones an array and its elements.
*
* @param The type of object in the array.
* @param array The array to copy, along with its elements.
* @return A new smart copy of the array and its elements.
*/
public static T[] cloneSmartArrayAndElements(
final T[] array)
{
if (array == null)
{
return null;
}
@SuppressWarnings("unchecked")
final T[] result = (T[]) Array.newInstance(
array.getClass().getComponentType(), array.length);
for (int i = 0; i < result.length; i++)
{
result[i] = cloneSmart(array[i]);
}
return result;
}
/**
* Performs a deep copy of a given object. Works by using serialization to
* write out an object and read it back in. It should only be used if you
* are really sure you want a deep copy of an object.
*
* @param The type of the object to copy.
* @param object The object to copy.
* @return A deep copy of the given object or null, if the copy fails.
*/
@SuppressWarnings("unchecked")
public static T deepCopy(
final T object)
{
if (object == null)
{
// Don't attempt to deep copy null.
return null;
}
try
{
byte[] bytes = ObjectSerializationHandler.convertToBytes(object);
return (T) ObjectSerializationHandler.convertFromBytes(bytes);
}
catch (Exception ex)
{
Logger.getLogger(ObjectUtil.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
/**
* Prints out the Methods and Fields associated with the argument. If the
* argument is a type of "Class", then the referenced Class is accessed.
* If the argument is a String, then the String is examined to extract
* the name of the Class: e.g., "gov.sandia.cognition.util.DefaultPair".
* Otherwise, the argument is taken to be an instantiated Object, and
* we inspect the methods and fields of the object itself.
* @param o
* Object/Class/String to inspect from
* @return
* String representing a list of the Methods and Fields of the given
* argument. If a ClassNotFoundException gets thrown, this method
* intercepts the Exception and simply returns the Exception String as
* the return value (thus, no Exceptions are thrown).
*/
public static String inspector(
final Object o)
{
Object instantiatedObject = null;
Class> c = null;
if ( o instanceof String )
{
try
{
String s = (String) o;
c = Class.forName( s );
}
catch (Exception e)
{
return "Exception: " + e.toString();
}
}
else if ( o instanceof Class )
{
c = (Class) o;
}
else
{
c = o.getClass();
instantiatedObject = o;
}
StringBuilder retval = new StringBuilder();
retval.append( "Class "+ c.getSimpleName() + " extends " + c.getSuperclass() + "\n" );
if( c.getInterfaces().length > 0 )
{
retval.append( "Implements " + c.getInterfaces().length + " interfaces:" );
for( Class> i : c.getInterfaces() )
{
retval.append( " " + i.getSimpleName() );
}
retval.append( "\n" );
}
retval.append("------------- Methods ----------------\n");
retval.append( ObjectUtil.inspectAPI( c ) );
retval.append("------------- Fields ----------------\n");
if( instantiatedObject == null )
{
retval.append( ObjectUtil.inspectFields( c ) );
}
else
{
retval.append( ObjectUtil.inspectFieldValues( instantiatedObject ) );
}
return retval.toString();
}
/**
* Creates a String representing the Constructors and Methods from the
* given Class, inspects public constructors and all
* public/private/protected methods (except those from the Object class).
* @param c
* Class to determine the API of
* @return
* String representing the Constructors and Methods
*/
public static String inspectAPI(
final Class> c )
{
LinkedList methods = ObjectUtil.getMethods( c );
StringBuilder retval = new StringBuilder();
Constructor>[] constructors = c.getConstructors();
for( Constructor> m : constructors )
{
retval.append( Modifier.toString( m.getModifiers() ) + " " );
retval.append( m.getName() );
retval.append( "(" );
for( int j = 0; j < m.getParameterTypes().length; j++ )
{
retval.append( " " + m.getParameterTypes()[j].getSimpleName() );
if( j < m.getParameterTypes().length-1 )
{
retval.append( "," );
}
else
{
retval.append( " " );
}
}
retval.append( ")" );
retval.append( "\n" );
}
for( Method m : methods )
{
retval.append( Modifier.toString( m.getModifiers() ) + " " );
retval.append( m.getReturnType().getSimpleName() + " " );
retval.append( m.getName() );
retval.append( "(" );
for( int j = 0; j < m.getParameterTypes().length; j++ )
{
retval.append( " " + m.getParameterTypes()[j].getSimpleName() );
if( j < m.getParameterTypes().length-1 )
{
retval.append( "," );
}
else
{
retval.append( " " );
}
}
retval.append( ")" );
retval.append( "\n" );
}
return retval.toString();
}
/**
* Gets the Collection of all public/private/protected Methods in the
* given Class (except those only given in the Object class). If the
* argument represents an interface, then the interface methods are listed.
* Otherwise, only nonvolatile (i.e., not abstract) methods are returned.
* @param c
* Class from which to pull the Methods
* @return
* Collection of all public/private/protected Methods in the given Class
*/
public static LinkedList getMethods(
final Class> c)
{
// Don't recurse if te class is null or if it is Object.
if ( c == null || Object.class.equals( c ) )
{
return new LinkedList();
}
final LinkedList methods =
ObjectUtil.getMethods(c.getSuperclass());
final boolean isInterface = c.isInterface();
for ( Method m : c.getDeclaredMethods() )
{
// If we're an interface, then include interface methods
// Otherwise, don't include "volatile" methods, as those
// appear from interfaces only
if ( isInterface || !Modifier.isVolatile( m.getModifiers() ) )
{
methods.add( m );
}
}
return methods;
}
/**
* Creates a String that contains the names and values of the members, or
* the default Object toString if that fails.
* @param o
* Object to convert to a String
* @return
* String with member names and values of the members, or the
* default Object toString if that fails.
*/
public static String toString(
Object o )
{
String retval;
try
{
if( o.getClass().isArray() )
{
final int num = Array.getLength(o);
StringBuilder buffer = new StringBuilder( num * 20 );
buffer.append( o.getClass().getSimpleName() + " with " + num + " entries:\n" );
for( int i = 0; i < num; i++ )
{
buffer.append( "Index " + i + ":\n" + ObjectUtil.toString( Array.get(o,i) ) );
}
retval = buffer.toString();
}
else if( o instanceof Iterable> )
{
Iterable> iterable = (Iterable>) o;
final int num = CollectionUtil.size(iterable);
StringBuilder buffer = new StringBuilder( num * 20 );
buffer.append( o.getClass().getSimpleName() + " with " + num + " entries:\n" );
int index = 0;
for( Object i : iterable )
{
buffer.append( "Index " + index + ":\n" + ObjectUtil.toString(i) );
index++;
}
retval = buffer.toString();
}
else
{
retval = o.getClass().getSimpleName() + " field values:\n"
+ ObjectUtil.inspectFieldValues( o );
}
}
catch (Exception e)
{
retval = o.toString();
}
return retval;
}
/**
* Returns a String representing the values of all public/private/protected
* fields in the given instantiated Object, e.g., "double myField = 3.14"
* @param o
* Instantiated Object to inspect
* @return
* String representing the values of all public/private/protected fields
*/
public static String inspectFieldValues(
final Object o )
{
ArrayList> fieldValuePairs =
ObjectUtil.getAllFieldValues( o );
StringBuilder retval = new StringBuilder( fieldValuePairs.size() * 50 );
for( DefaultPair fieldValuePair : fieldValuePairs )
{
// Skip static fields.
Field f = fieldValuePair.getFirst();
if( !Modifier.isStatic( f.getModifiers() ) )
{
retval.append( f.getType().getSimpleName() + " " );
retval.append( f.getName() );
Object v = fieldValuePair.getSecond();
if( v != null )
{
retval.append( " = " + v.toString() );
}
else
{
retval.append( " = {null or value protected}" );
}
retval.append( "\n" );
}
}
return retval.toString();
}
/**
* Returns a String representing the values of all public/private/protected
* fields in the given Class, e.g., "protected double myField"
* @param c
* Class from which to inspect the fields
* @return
* The String containing the name, type, and modifier of all fields.
*/
public static String inspectFields(
final Class> c )
{
StringBuilder retval = new StringBuilder();
for( Field f : ObjectUtil.getAllFields( c ) )
{
retval.append( Modifier.toString( f.getModifiers() ) + " " );
retval.append( f.getType().getSimpleName() + " " );
retval.append( f.getName() );
retval.append( "\n" );
}
return retval.toString();
}
/**
* Returns a list of all of the fields on the given class and any
* super-class. It includes fields of all access modifiers.
*
* @param c
* The class to get all the fields from.
* @return The
* list of fields on the given class or any of its super classes.
*/
public static LinkedList getAllFields(
final Class> c)
{
// A null class has no fields.
// Also, don't get fields from Object.
if ( c == null || Object.class.equals( c ) )
{
return new LinkedList();
}
// Get the fields from the super class.
final LinkedList fields =
ObjectUtil.getAllFields(c.getSuperclass());
// Declared fields include both public and private members
fields.addAll( Arrays.asList( c.getDeclaredFields() ) );
return fields;
}
/**
* Returns an ArrayList of field/value pairs
* @param o
* Object to get the field/value pairs
* @return
* ArrayList of field/value pairs. The value component of the DefaultPair will
* be null if the field is protected by the security manager
*/
public static ArrayList> getAllFieldValues(
final Object o )
{
LinkedList fields = ObjectUtil.getAllFields( o.getClass() );
ArrayList