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?

[1998 byte] By [MartinHilperta] at [2007-10-2 20:20:39]
# 1
You have to cast:result = (T) new Integer(""+o);
DrClapa at 2007-7-13 23:03:02 > top of Java-index,Core,Core APIs...
# 2

Is that really the code, or did you make a typo in the forum? Should it be:

static public final <T> T getColumnValue(final ResultSet rs, final String colName, Class<T> clazz)

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);

lord_pixela at 2007-7-13 23:03:02 > top of Java-index,Core,Core APIs...
# 3
> You have to cast:result = (T) new Integer(""+o);This gives me:Type safety: The cast from Integer to T is actually checking against the erased type Object
MartinHilperta at 2007-7-13 23:03:02 > top of Java-index,Core,Core APIs...
# 4

> 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.

MartinHilperta at 2007-7-13 23:03:02 > top of Java-index,Core,Core APIs...
# 5

The problem is that T can not be primative.

result = type.cast(i.intValue())

does nothing at all! Since i is reboxed into an Integer.

When you return T, it will be boxed as necessary, and when the calling method assigns it to int, it will be unboxed.

Either do:

in your method, when you determine that type is Integer.TYPE, assign type to Integer.class so that the cast works. (same for other types)

or

call with Integer.class instead of Integer.TYPE.

PS

You can use int.class intstead of Integer.TYPE

subartsha at 2007-7-13 23:03:02 > top of Java-index,Core,Core APIs...
# 6

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()

MartinHilperta at 2007-7-13 23:03:02 > top of Java-index,Core,Core APIs...