How to Address Unchecked Cast Warnings

How do I address unchecked cast warnings?

Wow; I think I figured out the answer to my own question. I'm just not sure it's worth it! :)

The problem is the cast isn't checked. So, you have to check it yourself. You can't just check a parameterized type with instanceof, because the parameterized type information is unavailable at runtime, having been erased at compile time.

But, you can perform a check on each and every item in the hash, with instanceof, and in doing so, you can construct a new hash that is type-safe. And you won't provoke any warnings.

Thanks to mmyers and Esko Luontola, I've parameterized the code I originally wrote here, so it can be wrapped up in a utility class somewhere and used for any parameterized HashMap. If you want to understand it better and aren't very familiar with generics, I encourage viewing the edit history of this answer.

public static <K, V> HashMap<K, V> castHash(HashMap input,
Class<K> keyClass,
Class<V> valueClass) {
HashMap<K, V> output = new HashMap<K, V>();
if (input == null)
return output;
for (Object key: input.keySet().toArray()) {
if ((key == null) || (keyClass.isAssignableFrom(key.getClass()))) {
Object value = input.get(key);
if ((value == null) || (valueClass.isAssignableFrom(value.getClass()))) {
K k = keyClass.cast(key);
V v = valueClass.cast(value);
output.put(k, v);
} else {
throw new AssertionError(
"Cannot cast to HashMap<"+ keyClass.getSimpleName()
+", "+ valueClass.getSimpleName() +">"
+", value "+ value +" is not a "+ valueClass.getSimpleName()
);
}
} else {
throw new AssertionError(
"Cannot cast to HashMap<"+ keyClass.getSimpleName()
+", "+ valueClass.getSimpleName() +">"
+", key "+ key +" is not a " + keyClass.getSimpleName()
);
}
}
return output;
}

That's a lot of work, possibly for very little reward... I'm not sure if I'll use it or not. I'd appreciate any comments as to whether people think it's worth it or not. Also, I'd appreciate improvement suggestions: is there something better I can do besides throw AssertionErrors? Is there something better I could throw? Should I make it a checked Exception?

How to fix 'Unchecked cast from MyClass to T'

The solution is to use T as the type here and then you can remove your casts:

// before:
// SonarContainPaging sonarObject = getSonarObjectFromPage(url, uriVariables, klass, page);
// after:
T sonarObject = getSonarObjectFromPage(url, uriVariables, klass, page);

Since according to your comment, getSonarObjectFromPage returns T, where T is the class you pass it in:

<T extends SonarContainPaging> T getSonarObjectFromPage(String url, Map<String, Object> uriVariables, Class<T> klass, List<T> page)

In this case you passed the class klass, which is a Class<T>, so getSonarObjectFromPage will return a T as well.

Type safety: Unchecked cast

Well, first of all, you're wasting memory with the new HashMap creation call. Your second line completely disregards the reference to this created hashmap, making it then available to the garbage collector. So, don't do that, use:

private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");

Secondly, the compiler is complaining that you cast the object to a HashMap without checking if it is a HashMap. But, even if you were to do:

if(getApplicationContext().getBean("someMap") instanceof HashMap) {
private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");
}

You would probably still get this warning. The problem is, getBean returns Object, so it is unknown what the type is. Converting it to HashMap directly would not cause the problem with the second case (and perhaps there would not be a warning in the first case, I'm not sure how pedantic the Java compiler is with warnings for Java 5). However, you are converting it to a HashMap<String, String>.

HashMaps are really maps that take an object as a key and have an object as a value, HashMap<Object, Object> if you will. Thus, there is no guarantee that when you get your bean that it can be represented as a HashMap<String, String> because you could have HashMap<Date, Calendar> because the non-generic representation that is returned can have any objects.

If the code compiles, and you can execute String value = map.get("thisString"); without any errors, don't worry about this warning. But if the map isn't completely of string keys to string values, you will get a ClassCastException at runtime, because the generics cannot block this from happening in this case.



Related Topics



Leave a reply



Submit