Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.lang.ClassCastException with null message and cause

I work on a project using Java 8

We have a negative test similar to this:

public Integer g(Object data)
{
    try
    {
        Double d = (Double)data;
    }
    catch(ClassCastException ex)
    {
        if( ex.getMessage() == null )
        {
            return 1;
        }
    }
    return 0;
}

@Test
public void h()
{
    Integer count = 0;
    for( Integer idx = 0; idx < 100000; idx++ )
    {
        // The test
        count += g(0.7312345f);
    }
    System.out.println("Total ClassCastException's with null message: "+count);
}

The negative test expects the exception java.lang.ClassCastException with message "java.lang.Float cannot be cast to java.lang.Double" and it sometimes gets null message

I tried to debug it in eclipse but somehow when attached to debugger the exception and message were as expected all the time

like image 949
E. Levy Avatar asked Nov 09 '16 08:11

E. Levy


2 Answers

Running the complete example as given by AxelH in OpenJDK 8 revealed my suspicions to be correct.

Copying, so it doesn't go away (which he said he will delete):

public class Main{

    int cnt = 0, cntNull = 0;
    public static void main(String[] args) { 
        new Main().test();
    }

    public void test(){
        for( Integer idx = 0; idx < 200000; idx++ )
        {
            loseType(0.45642f, idx);
        }
        System.out.println(cnt + " error");
        System.out.println(cntNull + " null");
    }

    public void loseType(Object data, Integer i){
        try{
            gainType((Double)data);
        } catch(ClassCastException e){
            cnt++;
            if(e.getMessage() == null){
                cntNull++;
            }
        }
    }

    public void gainType(Double x){

    }
}

Compile with javac Main.java then run with java -Xmixed Main (same as default java Main) and your exception often has a null message. Run it with java -Xint Main and it is never null.

The reason is in mixed mode it uses the runtime interpreter until the class is compiled, then moves over to it, but using -Xint makes it always use the interpreter, in which the message is always present. It seems the compiled native code has a bug that creates the exception without a proper message.

like image 81
coladict Avatar answered Sep 30 '22 06:09

coladict


It's not a JVM bug, it's a feature ;) - See NullPointerException in Java with no StackTrace - you need to add the -XX:-OmitStackTraceInFastThrow option to the JVM args and then you'll have stack traces all the time (but slightly slower exception throwing).

like image 30
stevestorey Avatar answered Sep 30 '22 07:09

stevestorey