Geoff McLennan
Geoff McLennan

Reputation: 448

Java: Is casting to generic type in parent class safe when generic is <T extends Parent>?

I have a parent class for all of my custom exceptions, ParentException. I want all child exceptions to have a method that adds a message to the exception. To do this I created a generic method that returns an object of generic type after adding the message to it. I use this in the parent class method to add the message then return this but since the method returns the generic type I casted it to the generic type T. This seems to work, but gives a warning. My code is as follows:

public class ParentException extends RuntimeException{

    private String message;

    public ParentException() {
        message = "";
    }

    public void addToMessage(String msg) {
        message += msg;
    }

    public void printMessage() {
        System.out.println(message);
    }

    public <T extends ParentException> T withMessage(String msg) {
        this.addToMessage(msg);
        return (T) this; // This line gives the warning
    }
}

The warning given by that line is Unchecked cast from ParentException to T. The method does seem to work as expected, so I'm not worried but I'd like a better understanding of why this gives a warning in the first place.

Will this cast always be safe? Otherwise what case would cause a runtime error?

Upvotes: 0

Views: 1952

Answers (2)

Jorn Vernee
Jorn Vernee

Reputation: 33845

Consider this case:

class SubException extends ParentException {...}

ParentException ex = new ParentException();
SubException sub = ex.withMessage("blah");

The last line will throw a class cast exception, because ParentException can not be cast to SubException.


You could create a static helper method:

class ParentException extends RuntimeException{
    ...
    protected static <T extends ParentException> T withMessage(T instance, String msg) {
        instance.addToMessage(msg);
        return instance;
    }

    public ParentException withMessage(String msg) {
        return withMessage(this, msg);
    }
}

And use covariant return types to override this method:

class SubException extends ParentException {
    @Override
    public SubException withMessage(String msg) {
        return withMessage(this, msg);
    }   
}

Then, if you have a SubException variable, the call to withMessage will return a SubException too.

Upvotes: 1

VGR
VGR

Reputation: 44308

The following code will compile, but will fail at runtime:

class ChildException extends ParentException { }

ParentException p = new ParentException();
ChildException c = p.withMessage("Connection failed");

I realize it wouldn’t make much sense to write that, but the point is that the compiler warning about an unsafe cast can prevent this landmine in the first place.

Upvotes: 1

Related Questions