/* * Value.java * * Created on January 4, 2001, 11:37 AM */ package org.freehep.util; import java.lang.reflect.Constructor; import java.util.Date; import java.text.SimpleDateFormat; import java.text.ParseException; /** * A class that can represent any Java object or primitive. Unlike the * built-in primitive proxies (Double, Integer etc) it is mutable. It is * used to allow values to be used without needing overloaded methods for * each primitive type, and without the overhead of object creation/deletion. * * When a value is returned by an Object method it should be assumed to be valid * only until the next method call to that Object. The use of Value should be * avoided in multi-threaded environments. * * @author tonyj * @version $Id: Value.java 9133 2006-10-13 16:25:43Z turri $ */ public class Value { private int intValue; private short shortValue; private long longValue; private float floatValue; private double doubleValue; private boolean boolValue; private byte byteValue; private char charValue; private Object obj; private Class type; public final static Class TYPE_INTEGER = Integer.TYPE; public final static Class TYPE_SHORT = Short.TYPE; public final static Class TYPE_LONG = Long.TYPE; public final static Class TYPE_FLOAT = Float.TYPE; public final static Class TYPE_DOUBLE = Double.TYPE; public final static Class TYPE_BOOLEAN = Boolean.TYPE; public final static Class TYPE_BYTE = Byte.TYPE; public final static Class TYPE_CHAR = Character.TYPE; public final static Class TYPE_STRING = String.class; public final static Class TYPE_DATE = Date.class; public Value() {} public Value( Value v ) { setValue(v); } public Value setValue(Value v) { this.type = v.getType(); this.intValue = v.intValue; this.shortValue = v.shortValue; this.longValue = v.longValue; this.floatValue = v.floatValue; this.doubleValue = v.doubleValue; this.boolValue = v.boolValue; this.byteValue = v.byteValue; this.charValue = v.charValue; this.obj = v.obj; return this; } /** * Get the Value's type * @return The Class of this Value. * */ public Class getType() { return type; } /** * Set the Value's internal value to an integer. * @param val The integer value. * @return The Value object with the given internal value. * */ public Value set(int val) { intValue = val; type = TYPE_INTEGER; return this; } /** * Set the Value's internal value to a short. * @param val The short value. * @return The Value object with the given internal value. * */ public Value set(short val) { shortValue = val; type = TYPE_SHORT; return this; } /** * Set the Value's internal value to a long. * @param val The long value. * @return The Value object with the given internal value. * */ public Value set(long val) { longValue = val; type = TYPE_LONG; return this; } /** * Set the Value's internal value to a float. * @param val The float value. * @return The Value object with the given internal value. * */ public Value set(float val) { floatValue = val; type = TYPE_FLOAT; return this; } /** * Set the Value's internal value to a double. * @param val The double value. * @return The Value object with the given internal value. * */ public Value set(double val) { doubleValue = val; type = TYPE_DOUBLE; return this; } /** * Set the Value's internal value to a boolean. * @param val The boolean value. * @return The Value object with the given internal value. * */ public Value set(boolean val){ boolValue = val; type = TYPE_BOOLEAN; return this; } /** * Set the Value's internal value to a byte. * @param val The byte value. * @return The Value object with the given internal value. * */ public Value set(byte val) { byteValue = val; type = TYPE_BYTE; return this; } /** * Set the Value's internal value to a char. * @param val The char value. * @return The Value object with the given internal value. * */ public Value set(char val) { charValue = val; type = TYPE_CHAR; return this; } /** * Set the Value's internal value to a String. * @param val The String value. * @return The Value object with the given internal value. * */ public Value set(String val) { obj = val; type = TYPE_STRING; return this; } /** * Set the Value's internal value to a Date. * @param val The Date value. * @return The Value object with the given internal value. * */ public Value set(Date val) { obj = val; type = TYPE_DATE; return this; } /** * Set the Value's internal value to an Object. * @param val The Object value. * @return The Value object with the given internal value. * */ public Value set(Object val) { obj = val; type = obj == null ? Object.class : obj.getClass(); return this; } /** * Get the integer value. * @return The int value. * @exception A ClassCastException is thrown if this Value has incompatible type. * */ public int getInt() { if (type == TYPE_INTEGER) return intValue; else if (type == TYPE_SHORT) return shortValue; else if (type == TYPE_BYTE) return byteValue; else throw new ClassCastException( "getInt cannot be called for type "+type.toString()); } /** * Get the short value. * @return The short value. * @exception A ClassCastException is thrown if this Value has incompatible type. * */ public short getShort() { if (type == TYPE_SHORT) return shortValue; else if (type == TYPE_BYTE) return byteValue; else throw new ClassCastException( "getShort cannot be called for type "+type.toString()); } /** * Get the long value. * @return The long value. * @exception A ClassCastException is thrown if this Value has incompatible type. * */ public long getLong() { if (type == TYPE_LONG) return longValue; else if (type == TYPE_INTEGER) return intValue; else if (type == TYPE_SHORT) return shortValue; else if (type == TYPE_BYTE) return byteValue; else throw new ClassCastException( "getLong cannot be called for type "+type.toString()); } /** * Get the float value. * @return The float value. * @exception A ClassCastException is thrown if this Value has incompatible type. * */ public float getFloat() { if (type == TYPE_FLOAT) return floatValue; else if (type == TYPE_INTEGER) return intValue; else if (type == TYPE_SHORT) return shortValue; else if (type == TYPE_LONG) return longValue; else if (type == TYPE_BYTE) return byteValue; else throw new ClassCastException( "getFloat cannot be called for type "+type.toString()); } /** * Get the double value. * @return The double value. * @exception A ClassCastException is thrown if this Value has incompatible type. * */ public double getDouble() { if (type == TYPE_DOUBLE) return doubleValue; else if (type == TYPE_INTEGER) return intValue; else if (type == TYPE_SHORT) return shortValue; else if (type == TYPE_LONG) return longValue; else if (type == TYPE_FLOAT) return floatValue; else if (type == TYPE_BYTE) return byteValue; else if (type == TYPE_DATE) return ((Date)obj).getTime(); else throw new ClassCastException( "getDouble cannot be called for type "+type.toString()); } /** * Get the boolean value. * @return The boolean value. * @exception A ClassCastException is thrown if this Value has incompatible type. * */ public boolean getBoolean() { if (type == TYPE_BOOLEAN) return boolValue; else throw new ClassCastException( "getBoolean cannot be called for type "+type.toString()); } /** * Get the byte value. * @return The byte value. * @exception A ClassCastException is thrown if this Value has incompatible type. * */ public byte getByte() { if (type == TYPE_BYTE) return byteValue; else throw new ClassCastException( "getByte cannot be called for type "+type.toString()); } /** * Get the char value. * @return The char value. * @exception A ClassCastException is thrown if this Value has incompatible type. * */ public char getChar() { if (type == TYPE_CHAR) return charValue; else throw new ClassCastException( "getChar cannot be called for type "+type.toString()); } /** * Get the String value. * @return The String representation of the internal value. * */ public String getString() { if (type == TYPE_STRING) return (String)obj; else if (type == TYPE_INTEGER) return String.valueOf(intValue); else if (type == TYPE_SHORT) return String.valueOf(shortValue); else if (type == TYPE_LONG) return String.valueOf(longValue); else if (type == TYPE_FLOAT) return String.valueOf(floatValue); else if (type == TYPE_DOUBLE) return String.valueOf(doubleValue); else if (type == TYPE_BOOLEAN) return String.valueOf(boolValue); else if (type == TYPE_BYTE) return String.valueOf(byteValue); else if (type == TYPE_CHAR) return String.valueOf(charValue); else if (type == TYPE_DATE) return ((Date)obj).toString(); else return obj != null ? obj.toString(): "null"; } /** * Get the Date value. * @return The Date value. * @exception A ClassCastException is thrown if this Value has incompatible type. * */ public Date getDate() { if (type == TYPE_DATE) return (Date)obj; else throw new ClassCastException( "getDate cannot be called for type "+type.toString()); } /** * Get the Object value. * @return The Object value. * */ public Object getObject() { if (obj != null) return obj; else if (type == TYPE_INTEGER) return new Integer(intValue); else if (type == TYPE_SHORT) return new Short(shortValue); else if (type == TYPE_LONG) return new Long(longValue); else if (type == TYPE_FLOAT) return new Float(floatValue); else if (type == TYPE_DOUBLE) return new Double(doubleValue); else if (type == TYPE_BOOLEAN) return new Boolean(boolValue); else if (type == TYPE_BYTE) return new Byte(byteValue); else if (type == TYPE_CHAR) return new Character(charValue); else return null; } /** * Get the String value. * @return The String representation of the internal value. * */ public String toString() { return getString(); } /** * Returns an external representation of this value */ public String toExternal() { // FIXME, does not work for arrays... return type.getName()+":"+getString(); } /** * Set to value from the external respresentation */ public Value fromExternal(String external) throws IllegalArgumentException { String[] part = external.split(":", 2); if (part.length != 2) throw new IllegalArgumentException(getClass()+": External '"+external+ "'does not contain ':' to separate type from value."); if (part[0].equals(TYPE_STRING.getName())) { return set(part[1]); } else if (part[0].equals(TYPE_SHORT.getName())) { return set(Short.parseShort(part[1])); } else if (part[0].equals(TYPE_LONG.getName())) { return set(Long.parseLong(part[1])); } else if (part[0].equals(TYPE_FLOAT.getName())) { return set(Float.parseFloat(part[1])); } else if (part[0].equals(TYPE_DOUBLE.getName())) { return set(Double.parseDouble(part[1])); } else if (part[0].equals(TYPE_BOOLEAN.getName())) { return set(Boolean.getBoolean(part[1])); } else if (part[0].equals(TYPE_BYTE.getName())) { return set(Byte.parseByte(part[1])); } else if (part[0].equals(TYPE_CHAR.getName())) { return set(part[1].charAt(0)); } else if (part[0].equals(TYPE_INTEGER.getName())) { return set(Integer.parseInt(part[1])); } else if (part[0].equals(TYPE_DATE.getName())) { try { return set(new SimpleDateFormat().parse(part[1])); } catch (ParseException e) { throw new IllegalArgumentException(e.getMessage()); } } else if (part[0].equals(Object.class.getName()) && part[1].equals("null")) { return set((Object)null); } else { // FIXME will not work for arrays, which are encoded as "[Lpackagename.classname;" try { Class cls = Class.forName(part[0]); Constructor ctor = cls.getDeclaredConstructor(new Class[] { String.class }); ctor.setAccessible(true); return set(ctor.newInstance(new Object[] { part[1] })); } catch (Exception e) { throw new IllegalArgumentException(getClass()+": Cannot reconstruct value from type: "+part[0]+", " +"and value "+part[1]+", due to "+e.getMessage()); } } } }