Get generic return type from input class
I try to replace lots of getXXX() methods that do basically the same but just differs in the datatype of a value to get with something like this:
/**
* Get column value as an instance of a specific class. Example:
* Integer in = getColumnValue(rs, "Age", Integer.class);
*
* @param rs ResultSet to get value from.
* @param colName Name of column.
* @param clazz Target type.
* @return The column value as an instance of the specified target class.
* @throws SQLException on error.
*/
staticpublicfinal <Textends Object> T getColumnValue(final ResultSet rs,final String colName, T clazz)throws SQLException{
T result =null;
if (rs !=null && colName !=null){
Object o = rs.getObject(colName);
if (clazz == Integer.class){
result =new Integer(""+o);//Type mismatch: cannot convert from Integer to T
}else{
result = o;//Type mismatch: cannot convert from Object to T
}
}
return result;
}//getObject
But this doesn't compile (error messages as comments). What's wrong here?
> I removed the T extends Object, becuase I don't see
> it buys you anything.
>
> Then you can write the following, but it's
> essentially the same thing:
>
> > return clazz.cast(o);
>
Okay, I got it to work:
/**
* Convert an instance to a specific type (kind of intelligent casting).
*
* @param type Destination type (e.g. Boolean.class).
* @param object Instance to convert.
* @return Converted instance.
*/
static public <T> T toType(Class<T> type, Object object) {
T result = null;
if (object != null) {
final String so = ""+object;
//custom type conversions:
if (type == Boolean.class || type == Boolean.TYPE) {
Boolean r = null;
if ("1".equals(so) || "true".equalsIgnoreCase(so) || "yes".equalsIgnoreCase(so) || "on".equalsIgnoreCase(so)) {
r = Boolean.TRUE;
} else if ("0".equals(object) || "false".equalsIgnoreCase(so) || "no".equalsIgnoreCase(so) || "off".equalsIgnoreCase(so)) {
r = Boolean.FALSE;
} else {
r = Boolean.valueOf(so);
}
result = type.cast(r);
if (type == Boolean.TYPE) { // boolean instead of Boolean?
result = type.cast(r.booleanValue()); //auto-boxing ... :-(
}
} else if (type == Integer.class || type == Integer.TYPE) {
Integer i = Integer.valueOf(so);
result = type.cast(i);
if (type == Integer.TYPE) {
result = type.cast(i.intValue()); //auto-boxing ... :-(
}
} else { //hard cast:
try {
result = type.cast(object);
} catch (ClassCastException cce) {
//ignore
}
}
}//else: input unavailable
return result;
}//toType()
but it doesn't work for basic types (boolean, integer, ...) as they get autoboxed to the object types (Boolean, Integer). When I try
int i = ICUtils.toType(Integer.TYPE, "45");
I get a ClassCastException during runtime - probably because of auto-boxing.
Well, I got it to work even with primitives. So, a line
int i = toType("45", Integer.TYPE);
finally works (also with help of autoboxing). :-)
Here's the code:
/**
* Convert an instance to a specific type (kind of intelligent casting).
* Note: you can set primitive types as input <i>type</i> but the return type will be the corresponding wrapper type
* (e.g. Integer.TYPE will result in Integer.class) with the difference that instead of a result 'null' a numeric 0
* (or boolean false) will be returned because primitive types can't be null.
*
* Supported simple destination types are:
* <ul>
* <li>java.lang.Boolean, Boolean.TYPE (= boolean.class)
* <li>java.lang.Byte, Byte.TYPE (= byte.class)
* <li>java.lang.Character, Character.TYPE (= char.class)
* <li>java.lang.Double, Double.TYPE (= double.class)
* <li>java.lang.Float, Float.TYPE (= float.class)
* <li>java.lang.Integer, Integer.TYPE (= int.class)
* <li>java.lang.Long, Long.TYPE (= long.class)
* <li>java.lang.Short, Short.TYPE (= short.class)
* <li>java.lang.String
* <li>java.math.BigDecimal
* <li>java.math.BigInteger
* </ul>
*
* @param object Instance to convert.
* @param type Destination type (e.g. Boolean.class).
* @return Converted instance/datatype/collection or null if input object is null.
* @throws ClassCastException if <i>object</i> can't be converted to <i>type</i>.
* @since 2.11.0
*/
@SuppressWarnings("unchecked")
static public <T> T toType(final Object object, final Class<T> type) {
T result = null;
if (object == null) {
//initalize primitive types:
if (type == Boolean.TYPE) {
result = ((Class<T>) Boolean.class).cast(false);
} else if (type == Byte.TYPE) {
result = ((Class<T>) Byte.class).cast(0);
} else if (type == Character.TYPE) {
result = ((Class<T>) Character.class).cast(0);
} else if (type == Double.TYPE) {
result = ((Class<T>) Double.class).cast(0.0);
} else if (type == Float.TYPE) {
result = ((Class<T>) Float.class).cast(0.0);
} else if (type == Integer.TYPE) {
result = ((Class<T>) Integer.class).cast(0);
} else if (type == Long.TYPE) {
result = ((Class<T>) Long.class).cast(0);
} else if (type == Short.TYPE) {
result = ((Class<T>) Short.class).cast(0);
}
} else {
final String so = ""+object;
//custom type conversions:
if (type == BigDecimal.class) {
result = type.cast(toBigDecimal(so, ICConstants.FORMAT_DECIMAL));
} else if (type == BigInteger.class) {
result = type.cast(new BigInteger(so));
} else if (type == Boolean.class || type == Boolean.TYPE) {
Boolean r = null;
if ("1".equals(so) || "true".equalsIgnoreCase(so) || "yes".equalsIgnoreCase(so) || "on".equalsIgnoreCase(so)) {
r = Boolean.TRUE;
} else if ("0".equals(object) || "false".equalsIgnoreCase(so) || "no".equalsIgnoreCase(so) || "off".equalsIgnoreCase(so)) {
r = Boolean.FALSE;
} else {
r = Boolean.valueOf(so);
}
if (type == Boolean.TYPE) {
result = ((Class<T>) Boolean.class).cast(r); //avoid ClassCastException through autoboxing
} else {
result = type.cast(r);
}
} else if (type == Byte.class || type == Byte.TYPE) {
Byte i = Byte.valueOf(so);
if (type == Byte.TYPE) {
result = ((Class<T>) Byte.class).cast(i); //avoid ClassCastException through autoboxing
} else {
result = type.cast(i);
}
} else if (type == Character.class || type == Character.TYPE) {
Character i = new Character(so.charAt(0));
if (type == Character.TYPE) {
result = ((Class<T>) Character.class).cast(i); //avoid ClassCastException through autoboxing
} else {
result = type.cast(i);
}
} else if (type == Double.class || type == Double.TYPE) {
Double i = Double.valueOf(so);
if (type == Double.TYPE) {
result = ((Class<T>) Double.class).cast(i); //avoid ClassCastException through autoboxing
} else {
result = type.cast(i);
}
} else if (type == Float.class || type == Float.TYPE) {
Float i = Float.valueOf(so);
if (type == Float.TYPE) {
result = ((Class<T>) Float.class).cast(i); //avoid ClassCastException through autoboxing
} else {
result = type.cast(i);
}
} else if (type == Integer.class || type == Integer.TYPE) {
Integer i = Integer.valueOf(so);
if (type == Integer.TYPE) {
result = ((Class<T>) Integer.class).cast(i); //avoid ClassCastException through autoboxing
} else {
result = type.cast(i);
}
} else if (type == Long.class || type == Long.TYPE) {
Long i = Long.valueOf(so);
if (type == Long.TYPE) {
result = ((Class<T>) Long.class).cast(i); //avoid ClassCastException through autoboxing
} else {
result = type.cast(i);
}
} else if (type == Short.class || type == Short.TYPE) {
Short i = Short.valueOf(so);
if (type == Short.TYPE) {
result = ((Class<T>) Short.class).cast(i); //avoid ClassCastException through autoboxing
} else {
result = type.cast(i);
}
} else { //hard cast:
result = type.cast(object);
}
}
return result;
}//toType()