summaryrefslogtreecommitdiff
path: root/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ValueConverter.java
diff options
context:
space:
mode:
Diffstat (limited to 'projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ValueConverter.java')
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ValueConverter.java718
1 files changed, 718 insertions, 0 deletions
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ValueConverter.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ValueConverter.java
new file mode 100644
index 0000000..d6bc797
--- /dev/null
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ValueConverter.java
@@ -0,0 +1,718 @@
+/*
+Wotonomy: OpenStep design patterns for pure Java applications.
+Copyright (C) 2000 Michael Powers
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, see http://www.gnu.org
+*/
+
+package net.wotonomy.foundation.internal;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+
+/**
+* A utility class to convert objects to a desired class.
+*
+* @author michael@mpowers.net
+* @author $Author: cgruber $
+* @version $Revision: 893 $
+*/
+public class ValueConverter
+{
+ /**
+ * Returns the specified object as converted to an instance of the
+ * specified class, or null if the conversion could not be performed.
+ */
+ static public Object convertObjectToClass( Object anObject, Class aClass )
+ {
+ if ( aClass == String.class )
+ {
+ return getString( anObject );
+ }
+ if ( aClass == Short.class )
+ {
+ return getShort( anObject );
+ }
+ if ( aClass == short.class )
+ {
+ return getShort( anObject );
+ }
+ if ( aClass == Integer.class )
+ {
+ return getInteger( anObject );
+ }
+ if ( aClass == int.class )
+ {
+ return getInteger( anObject );
+ }
+ if ( aClass == Long.class )
+ {
+ return getLong( anObject );
+ }
+ if ( aClass == long.class )
+ {
+ return getLong( anObject );
+ }
+ if ( aClass == Float.class )
+ {
+ return getFloat( anObject );
+ }
+ if ( aClass == float.class )
+ {
+ return getFloat( anObject );
+ }
+ if ( aClass == Double.class )
+ {
+ return getDouble( anObject );
+ }
+ if ( aClass == double.class )
+ {
+ return getDouble( anObject );
+ }
+ if ( aClass == java.util.Date.class )
+ {
+ return getDate( anObject );
+ }
+ if ( aClass == Boolean.class )
+ {
+ return getBoolean( anObject );
+ }
+ if ( aClass == boolean.class )
+ {
+ return getBoolean( anObject );
+ }
+ if ( aClass == Character.class )
+ {
+ return getCharacter( anObject );
+ }
+ if ( aClass == char.class )
+ {
+ return getCharacter( anObject );
+ }
+ if ( aClass == Byte.class )
+ {
+ return getByte( anObject );
+ }
+ if ( aClass == byte.class )
+ {
+ return getByte( anObject );
+ }
+ if ( Collection.class.isAssignableFrom( aClass ) )
+ {
+ return getCollection( anObject, aClass );
+ }
+ if ( aClass.isArray() )
+ {
+ return getArray( anObject, aClass );
+ }
+
+ return convert( anObject, aClass );
+ }
+
+ /**
+ * Called by convertObjectToClass() when we need to
+ * convert to an unrecognized type.
+ * This implementation scans the constructors of the
+ * specified class for the best fit to the object.
+ * and returns a new instance with that constructor.
+ * Subclasses can override to directly support specific
+ * types.
+ */
+ static protected Object convert( Object anObject, Class aClass )
+ {
+ Constructor[] ctors = aClass.getConstructors();
+
+ Class[] types;
+ for ( int i = 0; i < ctors.length; i++ )
+ {
+ types = ctors[i].getParameterTypes();
+ if ( types.length == 1 )
+ {
+ if ( types[0].equals( anObject.getClass() ) )
+ {
+ try
+ {
+ return ctors[i].newInstance( new Object[] { anObject } );
+ }
+ catch ( Exception exc )
+ {
+ // fall through
+ }
+ }
+ }
+ }
+
+ for ( int i = 0; i < ctors.length; i++ )
+ {
+ types = ctors[i].getParameterTypes();
+ if ( types.length == 1 )
+ {
+ if ( anObject.getClass().isAssignableFrom( types[0] ) )
+ {
+ try
+ {
+ return ctors[i].newInstance( new Object[] { anObject } );
+ }
+ catch ( Exception exc )
+ {
+ // fall through
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Tries to convert all objects to either Numbers or objects
+ * that will produce a parsable toString result.
+ */
+ static protected Object preprocess( Object anObject )
+ {
+ if ( anObject instanceof Boolean )
+ {
+ if ( ((Boolean)anObject).booleanValue() )
+ {
+ return new Double( 1.0 );
+ }
+ return new Double( 0.0 );
+ }
+
+ if ( anObject instanceof Character )
+ {
+ return anObject.toString();
+ }
+
+ return anObject;
+ }
+
+ static public short getShortValue( Object anObject )
+ {
+ Short result = getShort( anObject );
+ return ( result == null ) ? (short) 0 : result.shortValue();
+ }
+ static public Short getShort( Object anObject )
+ {
+ if ( anObject == null ) return new Short( (short) 0 );
+ if ( "".equals( anObject ) ) return new Short( (short) 0 );
+ if ( anObject instanceof Short ) return (Short) anObject;
+
+ anObject = preprocess( anObject );
+
+ if ( anObject instanceof Number )
+ {
+ return new Short( ((Number)anObject).shortValue() );
+ }
+
+ try
+ {
+ return Short.valueOf( anObject.toString() );
+ }
+ catch ( Exception exc )
+ {
+ return null;
+ }
+ }
+
+ static public int getIntValue( Object anObject )
+ {
+ Integer result = getInteger( anObject );
+ return ( result == null ) ? 0 : result.intValue();
+ }
+ static public Integer getInteger( Object anObject )
+ {
+ if ( anObject == null ) return new Integer( 0 );
+ if ( "".equals( anObject ) ) return new Integer( 0 );
+ if ( anObject instanceof Integer ) return (Integer) anObject;
+
+ anObject = preprocess( anObject );
+
+ if ( anObject instanceof Number )
+ {
+ return new Integer( ((Number)anObject).intValue() );
+ }
+
+ try
+ {
+ return Integer.valueOf( anObject.toString() );
+ }
+ catch ( Exception exc )
+ {
+ return null;
+ }
+ }
+
+ static public long getLongValue ( Object anObject )
+ {
+ Long result = getLong( anObject );
+ return ( result == null ) ? (long) 0 : result.longValue();
+ }
+ static public Long getLong( Object anObject )
+ {
+ if ( anObject == null ) return new Long( 0 );
+ if ( "".equals( anObject ) ) return new Long( 0 );
+ if ( anObject instanceof Long ) return (Long) anObject;
+
+ anObject = preprocess( anObject );
+
+ if ( anObject instanceof Number )
+ {
+ return new Long( ((Number)anObject).longValue() );
+ }
+
+ try
+ {
+ return Long.valueOf( anObject.toString() );
+ }
+ catch ( Exception exc )
+ {
+ return null;
+ }
+ }
+
+ static public double getDoubleValue ( Object anObject )
+ {
+ Double result = getDouble( anObject );
+ return ( result == null ) ? 0.0f : result.doubleValue();
+ }
+ static public Double getDouble( Object anObject )
+ {
+ if ( anObject == null ) return new Double( 0.0 );
+ if ( "".equals( anObject ) ) return new Double( 0 );
+ if ( anObject instanceof Double ) return (Double) anObject;
+
+ anObject = preprocess( anObject );
+
+ if ( anObject instanceof Number )
+ {
+ return new Double( ((Number)anObject).doubleValue() );
+ }
+
+ try
+ {
+ return Double.valueOf( anObject.toString() );
+ }
+ catch ( Exception exc )
+ {
+ return null;
+ }
+ }
+
+ static public float getFloatValue( Object anObject )
+ {
+ Float result = getFloat( anObject );
+ return ( result == null ) ? 0.0f : result.floatValue();
+ }
+ static public Float getFloat( Object anObject )
+ {
+ if ( anObject == null ) return new Float( 0.0 );
+ if ( "".equals( anObject ) ) return new Float( 0.0 );
+ if ( anObject instanceof Float ) return (Float) anObject;
+
+ anObject = preprocess( anObject );
+
+ if ( anObject instanceof Number )
+ {
+ return new Float( ((Number)anObject).floatValue() );
+ }
+
+ try
+ {
+ return Float.valueOf( anObject.toString() );
+ }
+ catch ( Exception exc )
+ {
+ return null;
+ }
+ }
+
+ static public char getCharValue( Object anObject )
+ {
+ Character result = getCharacter( anObject );
+ return ( result == null ) ? (char) 0 : result.charValue();
+ }
+ static public Character getCharacter( Object anObject )
+ {
+ if ( anObject == null ) return new Character( (char) 0 );
+ if ( anObject instanceof Character ) return (Character) anObject;
+
+ anObject = preprocess( anObject );
+
+ if ( anObject instanceof Number )
+ {
+ return new Character( (char) ((Number)anObject).byteValue() );
+ }
+
+ try
+ {
+ return new Character( anObject.toString().charAt( 0 ) );
+ }
+ catch ( Exception exc )
+ {
+ return null;
+ }
+ }
+
+ static public byte getByteValue( Object anObject )
+ {
+ Byte result = getByte ( anObject );
+ return ( result == null ) ? (byte) 0 : result.byteValue();
+ }
+ static public Byte getByte( Object anObject )
+ {
+ if ( anObject == null ) return new Byte( Byte.MIN_VALUE );
+ if ( "".equals( anObject ) ) return new Byte( Byte.MIN_VALUE );
+ if ( anObject instanceof Byte ) return (Byte) anObject;
+
+ anObject = preprocess( anObject );
+
+ if ( anObject instanceof Number )
+ {
+ return new Byte( ((Number)anObject).byteValue() );
+ }
+
+ try
+ {
+ return Byte.decode( anObject.toString() );
+ }
+ catch ( Exception exc )
+ {
+ // fall through
+ }
+
+ try
+ {
+ return Byte.valueOf( anObject.toString() );
+ }
+ catch ( Exception exc )
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Calls getBoolean and converts result to primitive.
+ */
+ static public boolean getBooleanValue( Object anObject )
+ {
+ Boolean result = getBoolean( anObject );
+ return ( result == null ) ? false : result.booleanValue();
+ }
+
+ /**
+ * Numbers equal to zero are true; Strings equal to "yes" are true;
+ * Strings are then passed to the Boolean constructor.
+ * Other values return null.
+ */
+ static public Boolean getBoolean( Object anObject )
+ {
+ if ( anObject instanceof Boolean )
+ {
+ return (Boolean) anObject;
+ }
+ if ( anObject instanceof Number )
+ {
+ return new Boolean( ((Number)anObject).doubleValue() == 0.0 );
+ }
+
+ if ( anObject instanceof String )
+ {
+ if ( anObject.toString().toLowerCase().equals( "yes" ) )
+ {
+ return Boolean.TRUE;
+ }
+ return new Boolean( (String) anObject );
+ }
+
+ return null;
+ }
+
+ /**
+ * Get an appropriate String representation for the
+ * object. Nulls are converted to "null". Date are
+ * formatted according to the current date format.
+ * All else uses toString.
+ */
+ static public String getString( Object anObject )
+ {
+ if ( anObject == null ) return "null";
+ if ( anObject instanceof java.util.Date )
+ {
+ return dateFormat.format( (java.util.Date) anObject );
+ }
+ return anObject.toString();
+ }
+
+ /**
+ * Converts the object into the specified collection class.
+ * If unable to convert in any other way, resorts to creating
+ * a new collection of the specified type containing the
+ * specified object.
+ */
+ static public Collection getCollection( Object anObject, Class aCollectionClass )
+ {
+ if ( anObject == null ) return null;
+ if ( aCollectionClass.isAssignableFrom( anObject.getClass() ) )
+ {
+ return (Collection) anObject;
+ }
+
+ Collection converted = null;
+
+ // convert to collection class
+ if ( anObject instanceof Collection )
+ {
+ converted = (Collection) anObject;
+ }
+ else
+ // try to convert an array
+ if ( anObject.getClass().isArray() )
+ {
+ try
+ {
+ int length = Array.getLength( anObject );
+ converted = new LinkedList();
+ for ( int i = 0; i < length; i++ )
+ {
+ converted.add( Array.get( anObject, i ) );
+ }
+ }
+ catch ( Exception exc )
+ {
+ // try another approach
+ }
+ }
+ else
+ // convert map values to collection and pass through
+ if ( anObject instanceof Map )
+ {
+ converted = ((Map)anObject).values();
+ }
+
+ // fall back on list containing the object
+ if ( converted == null )
+ {
+ converted = new LinkedList();
+ converted.add( anObject );
+ }
+
+ Collection result = null;
+
+ if ( converted != null )
+ {
+ try
+ {
+ // collections required to have the copy constructor.
+ Constructor ctor = aCollectionClass.getConstructor(
+ new Class[] { Collection.class } );
+ result = (Collection) ctor.newInstance( new Object[] { converted } );
+ }
+ catch ( Exception exc )
+ {
+ try
+ {
+ result = new LinkedList();
+ result.addAll( converted );
+ }
+ catch ( Exception exc2 )
+ {
+ // all attempts failed
+ result = null;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Convert the object to the specified array type.
+ */
+ static public Object getArray( Object anObject, Class anArrayClass )
+ {
+ if ( anObject == null ) return null;
+
+ // try to convert an array
+ if ( anObject.getClass().isArray() )
+ {
+ try
+ {
+ int length = Array.getLength( anObject );
+ Object result = Array.newInstance(
+ anArrayClass.getComponentType(), length );
+ for ( int i = 0; i < length; i++ )
+ {
+ Array.set( result, i, Array.get( anObject, i ) );
+ }
+ return result;
+ }
+ catch ( Exception exc )
+ {
+ // try another approach
+ }
+ }
+ // convert map values to collection and pass through
+ if ( anObject instanceof Map )
+ {
+ anObject = ((Map)anObject).values();
+ }
+ // try to convert a collection
+ if ( anObject instanceof Collection )
+ {
+ try
+ {
+ int length = ((Collection)anObject).size();
+ Object result = Array.newInstance(
+ anArrayClass.getComponentType(), length );
+ Iterator it = ((Collection)anObject).iterator();
+ for ( int i = 0; i < length; i++ )
+ {
+ Array.set( result, i, it.next() );
+ }
+ return result;
+ }
+ catch ( Exception exc )
+ {
+ // try another approach
+ }
+ }
+ // if appropriate type, put the object in a single element array
+ if ( anObject.getClass().equals( anArrayClass.getComponentType() ) )
+ {
+ try
+ {
+ Object result = Array.newInstance(
+ anArrayClass.getComponentType(), 1 );
+ Array.set( result, 0, anObject );
+ return result;
+ }
+ catch ( Exception exc )
+ {
+ // try another approach
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get an appropriate Date from the given object.
+ */
+ static public java.util.Date getDate( Object anObject )
+ {
+ if ( anObject == null ) return new java.util.Date( 0 );
+ if ( anObject instanceof java.util.Date )
+ return (java.util.Date) anObject;
+
+ if ( anObject instanceof Number )
+ {
+ return new java.util.Date( getLongValue( anObject ) );
+ }
+
+ try
+ {
+ return dateFormat.parse( anObject.toString() );
+ }
+ catch ( Exception exc )
+ {
+ return null;
+ }
+ }
+
+ static private java.text.DateFormat dateFormat =
+ new java.text.SimpleDateFormat();
+ static public java.text.DateFormat getDateFormat()
+ {
+ return dateFormat;
+ }
+ static public void setDateFormat( java.text.DateFormat aDateFormat )
+ {
+ if ( aDateFormat != null )
+ {
+ dateFormat = aDateFormat;
+ }
+ }
+
+ /**
+ * Returns the "inverted" value of the specified object.
+ * Numbers except for chars and bytes are converted to
+ * their negative representation. Chars and bytes are
+ * treated as booleans. String are converted to booleans.
+ * Booleans are converted to their opposite.
+ * All other types return null.
+ */
+ public static Object invert( Object anObject )
+ {
+ if ( anObject == null ) return null;
+ Class aClass = anObject.getClass();
+
+ if ( ( ( anObject instanceof Number )
+ &&! ( anObject instanceof Byte )
+ &&! ( anObject instanceof Character ) )
+ || ( aClass == short.class )
+ || ( aClass == int.class )
+ || ( aClass == long.class )
+ || ( aClass == float.class )
+ || ( aClass == double.class ) )
+ {
+ return convertObjectToClass(
+ new Double( getDoubleValue( anObject ) * -1 ), aClass );
+ }
+
+ Boolean converted = getBoolean( anObject );
+ if ( converted != null )
+ {
+ if ( converted.booleanValue() )
+ {
+ return convertObjectToClass(
+ Boolean.FALSE, anObject.getClass() );
+ }
+ else
+ {
+ return convertObjectToClass(
+ Boolean.TRUE, anObject.getClass() );
+ }
+ }
+
+ return null;
+ }
+}
+
+/*
+ * $Log$
+ * Revision 1.2 2006/02/16 13:11:47 cgruber
+ * Check in all sources in eclipse-friendly maven-enabled packages.
+ *
+ * Revision 1.4 2002/10/11 15:33:53 mpowers
+ * Now supporting "!" to invert the value of a string property.
+ *
+ * Revision 1.3 2001/07/02 16:29:08 mpowers
+ * XMLRPC decoder was relying on ValueConverter to convert LinkedLists into
+ * the appropriate type. This is now implemented in ValueConverter.
+ *
+ * Revision 1.2 2001/03/01 20:36:35 mpowers
+ * Better error handling and better handling of nulls.
+ *
+ * Revision 1.1.1.1 2000/12/21 15:52:33 mpowers
+ * Contributing wotonomy.
+ *
+ * Revision 1.8 2000/12/20 16:25:48 michael
+ * Added log to all files.
+ *
+ *
+ */
+