Question

I am converting old java code to support generics and came across this line of code which was trying to cast an object retrieved from the session into a TreeMap:

TreeMap allTransactions = (TreeMap) pageContext.getSession()
                                               .getAttribute("allTransactions");

When I tried to convert it to specific type:

TreeMap<String, MyDataBean> allTransactions = (TreeMap<String, MyDataBean>) 
                       pageContext.getSession().getAttribute("allTransactions");

It gave me a warning:

Type safety: Unchecked cast from Object to TreeMap<String,MyDataBean>

In an effort to get rid of the warning completely, I wrote a method to cast it to Map:

public static <K,V> Map<K,V> castToMap(Class<? extends K> clazz1, 
                                       Class<? extends V> clazz2, Map<?,?> c) {
    Map<K,V> map = new TreeMap<K,V>();
    for (Map.Entry<?,?> entry : c.entrySet()) {
        Object key = entry.getKey();
        Object value = entry.getValue();
        map.put(clazz1.cast(key), clazz2.cast(value));
    }
    return map;
}

Goodnews: This time I did not get any error when I modified the initial code to call this method:

Map<String, MyDataBean> allTransactions = MyUtilityClass.castToMap(String.class, 
                                                               MyDataBean.class, 
            (Map<?,?>)pageContext.getSession().getAttribute("allTransactions"));

But I still had to cast it ^^^here to call my function.

Question 1: Why it does not show any errors now when I am still using the cast (Map<?,?>) versus what I tried before (TreeMap<String,MyDataBean>)?

Question 2: My app is broken as of now since other developers have not committed the code yet, and so I am in no position to run the App and verify its correctness. Can anyone tell just by looking at it, if this casting will behave the same way as before?

Was it helpful?

Solution

If it is a Map then it is implicitly a Map<?,?> - as in, a map of anything. It considers that to be a safe cast because, since it is a map, it cannot fail. At this point, it's no different than casting it to any other object, which they're assuming is safe.

If it is a bad cast (say it's a List, not a Map) then it will explode there before anything else goes wrong. But because those types are lost at compile time, it will happily continue if the problem is in the generic types. So Map<?,?> is considered safe because it will explode because of being not being a Map if that's the problem.

As far as your second issue, it looks fine, but without more context it's hard to say. That being said, you should be able to use the history in your source control to grab an earlier version to compare against. If you can't obtain earlier versions of your code, your source control isn't very useful, now is it?

OTHER TIPS

Ad 1.: The cast itself is safe, because you don't specify any types which the compiler can not match against the method signature. Java 4 List can be safely assigned to Java 5 List<?>, but when you specify a type, you assume something, the compile can not safely check (therefore the warning).

Ad 2.: You have substituted a "hard" language cast with a "soft" method call cast, which will fail equally, if the classes are not castable into one another - I prefer the less verbose version of language casting, because one should rely one one's API.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top