SqlOutParameter out = new SqlOutParameter("out_refcursor",OracleTypes.CURSOR
,new StudentRowMapper());
// some code..
MapSqlParameterSource parameters = createMapSqlParameterSource();
parameters.addValue("in_studentid","101");
Map<String, Object> result = simpleJdbcCall.execute(parameters);
List<Student> students = (List<Student>) result.get("out_refcursor"); // here I get a warning
Definition of execute()
method:
Map<String, Object> org.springframework.jdbc.core.simple.SimpleJdbcCall.execute(SqlParameterSource parameterSource)
"Execute the stored procedure and return a map of output params, keyed by name as in parameter declarations.."
The warning on the above line : List<Student> students = (List<Student>) result.get("out_refcursor");
is:
Type safety: Unchecked cast from Object to List
I understand it is only a compile time warning, and Off course I can do a @SuppressWarnings("unchecked")
to suppress it.
Question: But how do I properly cast it?
One way I tried out is
List<Student> students = castObject( result.get("out_refcursor"));
@SuppressWarnings("unchecked")
private static <T extends List<?>> T castObject(Object obj){
return (T)obj;
}
Still I had to put @SuppressWarnings("unchecked")
in the castObject()
method. And I don't know if this is correct way of doing.
Second way I tried is,
List<?> students = castObject( result.get("out_refcursor"));
Student student = (Student)students.get(0);
private static <T extends List<?>> List<?> castObject(Object obj){
if(obj instanceof List<?>) {
return (List<Student>)obj;
}
return null;
}
Any suggestions/advice are welcome.
Some thing like that could work, as long as you know the class name of the element of the List
. One issue here, the hard coded ArrayList
instantiation.
public static <T> List<T> castList(Object obj, Class<T> clazz)
{
List<T> result = new ArrayList<T>();
if(obj instanceof List<?>)
{
for (Object o : (List<?>) obj)
{
result.add(clazz.cast(o));
}
return result;
}
return null;
}
Usage :
List<Student> students = castList(result.get("out_refcursor"), Student.class);
Your second solution won't help (due to Type Erasure), and will cause other problems too so probably not a good idea.
The first method will probably work in practice, but is a bit dodgy really. There's a subtle (but huge) difference between sub-classing Generic types and subclassing their parameters in Java - i.e. ArrayList<Integer>
is not a subclass of ArrayList<Object>
, but ArrayList<String>
is a sub-type of Collection<String>
: see a more fun example. More formal Computer Sciencey background in Wikipedia entry on Covariance.
So, IMO you should keep the casting there, keep the (necessary) annotation, and catch the ClassCastException
to make sure that the exceptional (hence the name) cases are covered.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With