Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I catch ClassCastException?

I'm trying to catch a ClassCastException when deserializing an object from xml.

So,

try {
    restoredItem = (T) decoder.readObject();
} catch (ClassCastException e){
    //don't need to crash at this point,
   //just let the user know that a wrong file has been passed.
}

And yet this won't as the exception doesn't get caught. What would you suggest?

like image 294
yanchenko Avatar asked Oct 09 '08 11:10

yanchenko


People also ask

Can we catch ClassCastException?

What you can do is pass in an instance of the Class of the parameterised type (assuming it isn't generic). class MyReader<T> { private final Class<T> clazz; MyReader(Class<T> clazz) { if (clazz == null) { throw new NullPointerException(); } this. clazz = clazz; } public T restore(String from) { ...

How do you solve ClassCastException?

To prevent the ClassCastException exception, one should be careful when casting objects to a specific class or interface and ensure that the target type is a child of the source type, and that the actual object is an instance of that type.

What causes ClassCastException?

ClassCastException is a runtime exception raised in Java when we try to improperly cast a class from one type to another. It's thrown to indicate that the code has attempted to cast an object to a related class, but of which it is not an instance.

Is ClassCastException checked?

ClassCastException is one of the unchecked exception in Java. It can occur in our program when we tried to convert an object of one class type into an object of another class type.


2 Answers

The code in the question should give you an unchecked cast warning. Listen to -Xlint.

All the compiler knows about T is its bounds, which it probably doesn't have (other than explicitly extending Object and a super of the null type). So effectively the cast at runtime is (Object) - not very useful.

What you can do is pass in an instance of the Class of the parameterised type (assuming it isn't generic).

class MyReader<T> {
    private final Class<T> clazz;
    MyReader(Class<T> clazz) {
        if (clazz == null) {
            throw new NullPointerException();
        }
        this.clazz = clazz;
    }
    public T restore(String from) {
        ...
        try {
            restoredItem = clazz.cast(decoder.readObject());
            ...
            return restoredItem;
        } catch (ClassCastException exc) {
            ...
        }
    }
}

Or as a generic method:

    public <T> T restore(Class<T> clazz, String from) {
        ...
        try {
            restoredItem = clazz.cast(decoder.readObject());
            ...
like image 112
Tom Hawtin - tackline Avatar answered Oct 16 '22 05:10

Tom Hawtin - tackline


There will not be any ClassCastException, except when your T has some base:

public class GenericsTest
{
    public static void main(String[] args)
    {
        System.out.println(cast(Integer.valueOf(0)));
        System.out.println(GenericsTest.<Long> cast(Integer.valueOf(0)));
        System.out.println(GenericsTest.<Long> cast("Hallo"));

        System.out.println(castBaseNumber(Integer.valueOf(0)));
        System.out.println(GenericsTest.<Long> castBaseNumber(Integer.valueOf(0)));
        System.out.println(GenericsTest.<Long> castBaseNumber("Hallo"));
    }

    private static <T extends Number> T castBaseNumber(Object o)
    {
        T t = (T)o;
        return t;
    }

    private static <T> T cast(Object o)
    {
        T t = (T)o;
        return t;
    }
}

In the above example, there will be no ClassCastException in the first 5 calls to cast and castBaseNumber. Only the 6th call throws a ClassCastException, because the compiler effectively translates the cast() to return (Object) o and the castBaseNumber() to return (Number)o;. Wenn you write

String s = GenericsTest.<Long> cast("Hallo");

You would get a ClassCastException, but not whithin the cast-method, but at the assignment to s.

Therefore I do think, your "T" is not just "T", but "T extends Something". So you could check:

Object o = decoder.readObject();
if (o instanceof Something)
    restoredItem = (T) o;
else 
    // Error handling

But this will still lead to an error later, when the you use your class.

public Reader<T extends Number>{...}

Long l = new Reader<Long>("file.xml").getValue(); // there might be the ClassCastException

For this case only Tom's advise might help.

like image 28
Tobias Schulte Avatar answered Oct 16 '22 05:10

Tobias Schulte