Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using generics causes unchecked conversion warning

I have the following code

String innerText = null;
innerText = this.getException(detail.getChildElements());

causing this warning

Type safety: The expression of type Iterator needs unchecked conversion to conform to Iterator

The referenced method is

private String getException(Iterator<OMElementImpl> iterator) { ... }

The other method, getChildElements(), is in a JAR file that I can't touch. There are no other warnings or errors.

From Googling, it seems like the usual way to get rid of this sort of warning is

@SuppressWarnings("unchecked")
String innerText = this.getException(detail.getChildElements());

because the compiler can't guarantee safety ahead of time, but I'd prefer to avoid using SuppressWarnings if possible... is there a better way?

EDIT: getChildElements() is documented here

like image 994
Pops Avatar asked Oct 02 '09 15:10

Pops


1 Answers

You can suppress the warning, but if you do so, you are relying 100% on the third-party library, and discarding the assurance of Java generic types: that any ClassCastException raised at runtime will occur right at an explicit cast.

Our coding standard is to suppress warnings only when we can prove the code is type safe—and we treat any calls outside the package as a black box, and don't rely on any comments about the content of a raw collection. So, suppression is extremely rare. Usually, if the code is type safe, the compiler can determine it, although sometimes we have to give it some help. The few exceptions involve arrays of generic type that don't "escape" from a private context.

If you don't fully trust the third-party library, create a new collection, and add the contents after casting them to OMEElementImpl. That way, if there is a bug in the library, you find out about it right away, rather than having some code far distant in time and space blow up with a ClassCastException.

For example:

Iterator<?> tmp = detail.getChildElements();
Collection<OMElementImpl> elements = new ArrayList<OMElementImpl>();
while (tmp.hasNext())
  elements.add((OMElementImpl) tmp.next()); /* Any type errors found here! */
String innerText = getException(elements.iterator());

Remember, generics were not invented to make code look pretty and require less typing! The promise of generics is this: Your code is guaranteed to be type-safe if it compiles without warnings. That is it. When warnings are ignored or suppressed, code without a cast operator can mysteriously raise a ClassCastException.


Update: In this case, especially, it seems extremely risky to assume that the result of getChildElements is a iterator of OMElementImpl. At best, you might assume that they are OMElement, and that's only implied from the class, not anything on the method in particular.

like image 76
erickson Avatar answered Nov 10 '22 02:11

erickson