Eclipse is giving me a warning of the following form:
Type safety: Unchecked cast from Object to HashMap
This is from a call to an API that I have no control over which returns Object:
HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {
HashMap<String, String> theHash = (HashMap<String, String>)session.getAttribute("attributeKey");
return theHash;
}
I'd like to avoid Eclipse warnings, if possible, since theoretically they indicate at least a potential code problem. I haven't found a good way to eliminate this one yet, though. I can extract the single line involved out to a method by itself and add @SuppressWarnings("unchecked")
to that method, thus limiting the impact of having a block of code where I ignore warnings. Any better options? I don't want to turn these warnings off in Eclipse.
Before I came to the code, it was simpler, but still provoked warnings:
HashMap getItems(javax.servlet.http.HttpSession session) {
HashMap theHash = (HashMap)session.getAttribute("attributeKey");
return theHash;
}
Problem was elsewhere when you tried to use the hash you'd get warnings:
HashMap items = getItems(session);
items.put("this", "that");
Type safety: The method put(Object, Object) belongs to the raw type HashMap. References to generic type HashMap<K,V> should be parameterized.
In this particular case, I would not store Maps into the HttpSession directly, but instead an instance of my own class, which in turn contains a Map (an implementation detail of the class). Then you can be sure that the elements in the map are of the right type.
But if you anyways want to check that the contents of the Map are of right type, you could use a code like this:
In Eclipse Preferences, Go to Java->Compiler->Errors/Warnings->Generic types and check the
Ignore unavoidable generic type problems
check-box.This satisfies the intent of the question, i.e.
if not the spirit.
Just typecheck it before you cast it.
And for anyone asking, it's quite common to receive objects where you aren't sure of the type. Plenty of legacy "SOA" implementations pass around various objects that you shouldn't always trust. (The horrors!)
EDIT Changed the example code once to match the poster's updates, and following some comments I see that instanceof doesn't play nicely with generics. However changing the check to validate the outer object seems to play well with the commandline compiler. Revised example now posted.
In the HTTP Session world you can't really avoid the cast, since the API is written that way (takes and returns only
Object
).With a little bit of work you can easily avoid the unchecked cast, 'though. This means that it will turn into a traditional cast giving a
ClassCastException
right there in the event of an error). An unchecked exception could turn into aCCE
at any point later on instead of the point of the cast (that's the reason why it's a separate warning).Replace the HashMap with a dedicated class:
Then cast to that class instead of
Map<String,String>
and everything will be checked at the exact place where you write your code. No unexpectedClassCastExceptions
later on.Warning suppression is not a solution. You should not be doing two level casting in one statement.
This stuff is hard, but here are my current thoughts:
If your API returns Object, then there's nothing you can do -- no matter what, you will be blindly casting the object. You let Java throw ClassCastExceptions, or you can check each element yourself and throw Assertions or IllegalArgumentExceptions or some such, but these runtime checks are all equivalent. You have to suppress the compile time unchecked cast no matter what you do at runtime.
I'd just prefer to blind cast and let the JVM perform its runtime check for me since we "know" what the API should return, and are usually willing to assume that the API works. Use generics everywhere above the cast, if you need them. You aren't really buying anything there since you still have the single blind cast, but at least you can use generics from there on up so the JVM can help you avoid blind casts in other pieces of your code.
In this particular case, presumably you can see the call to SetAttribute and see the type is going in, so just blind-casting the type to same on the way out is not immoral. Add a comment referencing the SetAttribute and be done with it.