Hemang
Hemang

Reputation: 1671

Type safety: Unchecked cast from Class<capture#2-of ?> to Class<? extends Throwable>

I am creating a function where I want to register different type of Exception in external library. They already have a method defined which accept Class as parameter.

I want to read different exception from configuration and register it, however I am getting typecast warning. I can ignore/suppress it, but is there any way to not suppress it?

The exact warning is Type safety: Unchecked cast from Class<capture#2-of ?> to Class<? extends Throwable>

Here is the sample code which throws warning

Class<?> exceptionClass = Class.forName("java.lang.Exception"); //Getting this value from Config. Let us assume that config is good and I get only valid classname which extends Throwable
registerExceptionInExternalLibrary((Class<? extends Throwable>)exceptionClass); // Getting the warning here

I think I cannot do casting here, since there is not object. But if I do not use casting, then I get this warning

The method registerExceptionInExternalLibrary(Class<? extends Throwable>) in the type XXXXX is not applicable for the arguments (Class<capture#2-of ?>)

Here is that code sample

Class<?> exceptionClass = Class.forName("java.lang.Exception"); //Getting this value from Config. Let us assume that config is good and I get only valid classname which extends Throwable
registerExceptionInExternalLibrary(exceptionClass); // Getting the warning here

Upvotes: 0

Views: 1633

Answers (2)

Kayaman
Kayaman

Reputation: 73568

You can use Class.asSubClass for this.

Class<?> exceptionClass = Class.forName("java.lang.Exception");
registerExceptionInExternalLibrary(exceptionClass.asSubclass(Throwable.class));

The complete code of the method is as follows and shows you're just offloading the cast (and warning suppression) to a JDK method, so there's nothing too magical about it. But it's very handy in map() chains, and works nicely here too. Also it does verify that you're making a correct cast with isAssignableFrom, which is the extra functionality that you'd forget to write if you just did the cast yourself and suppressed the warning.

@SuppressWarnings("unchecked")
public <U> Class<? extends U> asSubclass(Class<U> clazz) {
    if (clazz.isAssignableFrom(this))
        return (Class<? extends U>) this;
    else
        throw new ClassCastException(this.toString());
}

Upvotes: 5

David
David

Reputation: 371

There's a similar question about unchecked casts.

In short, the compiler can't be sure if the exceptionClass is a variable of type Class<? extends Throwable>, so you will get a warning anyway.

You can use @SuppressWarnings annotation with limited scope:

@SuppressWarnings("unchecked")
Class<? extends Throwable> exceptionClass = (Class<? extends Throwable>)Class.forName("java.lang.Exception");

The annotation here will not affect the entire method.

Upvotes: 0

Related Questions