Type Safety: Unchecked Cast

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.

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?

Type safety: Unchecked cast from Object to List

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.

How to get rid of Type safety: Unchecked cast from Object to Map String,String

You can't.

Since Authentication simply defines return value of getDetails() as an Object, you have to cast, and although the type Map will be checked at runtime, there is still no guarantee that it maps String to String (because of type erasure).

This means that you may get a ClassCastException at some later point, when the Map is used. That is what the warning is trying to tell you, and you accept responsibility for that by adding @SuppressWarnings.

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 from Object

Yes - this is a natural consequence of type erasure. If o is actually an instance of Action<String> that won't be caught by the cast - you'll only see the problem when you try to use it, passing in a ClientInterface instead of a string.

You can get rid of the warning using:

@SuppressWarnings("unchecked")

as a function annotation, but you can't easily sort out the underlying problem :(

Unchecked Cast warning - shows up for Type parameters but not for Concrete types?

Unchecked cast is flagged as the compiler does not know until the runtime if the type represented by the Supertype will ever match the SubType.

That is incorrect. Not even the runtime knows whether your list is a ArrayList<String> or a ArrayList<Integer>. As far as the runtime is concerned, your list is an ArrayList (This is because of type erasure). This is why casting a List<?> to a List<String> cannot be checked by the runtime. The runtime does not know what a List<String> is - it only knows about List. To the runtime, no checks are needed, since you are just casting from List to List, which always succeeds. In fact, nothing is done for this cast at runtime - it is a completely unchecked cast.

As a result, this code runs without throwing an exception:

List<String> stringList = new ArrayList<>();
stringList.add("foo");
List<Integer> integerList = (List<Integer>)(List<?>)stringList;
System.out.println(integerList.size());

It will throw an exception, however, if you did:

List<String> stringList = new ArrayList<>();
stringList.add("foo");
List<Integer> integerList = (List<Integer>)(List<?>)stringList;
System.out.println(integerList.get(0) - 1);

Now, you are getting an integer out of the list, and doing some integer-specific operations to it. But the list contains "foo", which isn't an integer. The compiler inserts an implicit cast to cast integerList.get(0) to Integer, and that cast failed. Note that this is a checked cast, because the runtime knows about the type Integer.

The cast from Number to Double is also checked, because the runtime knows about Double.

Side note: there are also "partially unchecked casts", which are things like casting from Object to ArrayList<String>. The runtime can check whether the Object is an ArrayList, but it cannot check whether it is an array list of strings.

See all the rules for what is checked and what is unchecked here.

Type safety: Unchecked cast from WebElement to List WebElement

WebElement ele = getObject(locator);
List<WebElement> ls = (List<WebElement>) ele;

You are casting List to WebElement and that is not valid. I believe in your getObject method you are using findElement method to identify the locator. Instead of that use findElements method to get List of WebElement

Try like below,

List<WebElement> ls = driver.findElements(By.xpath(locator));

How to avoid warning Type safety: Unchecked cast from Object to ArrayList Facility

The problem is that the cast will succeed as long as the returned object is an ArrayList, but it can't guarantee that every element is a Facility because of erasure. You can do that yourself, if you wish.

ArrayList<Facility> facilities =
((ArrayList<?>) xstream.fromXML(xml)).stream()
.filter(Facility.class::isInstance)
.map(Facility.class::cast)
.collect(Collectors.toCollection(ArrayList::new));


Related Topics



Leave a reply



Submit