Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I "fake" the stack trace of an exception in Java?

If I run the following test, it fails:

public class CrazyExceptions {
    private Exception exception;

    @Before
    public void setUp(){
        exception = new Exception();
    }

    @Test
    public void stackTraceMentionsTheLocationWhereTheExceptionWasThrown(){
        String thisMethod = new Exception().getStackTrace()[0].getMethodName();
        try {
            throw exception;
        }
        catch(Exception e) {
            assertEquals(thisMethod, e.getStackTrace()[0].getMethodName());
        }
    }
}

With the following error:

Expected :stackTraceMentionsTheLocationWhereTheExceptionWasThrown
Actual   :setUp

The stack trace is just flat out lying.

Why isn't the stack trace rewritten when the exception is thrown? I am not a Java dev, and maybe I'm missing something here.

like image 720
R. Martinho Fernandes Avatar asked Nov 08 '09 14:11

R. Martinho Fernandes


1 Answers

The stack trace is created when the exception is instantiated, not when it is thrown. This is specified behaviour of the Java Language Specification

20.22.1  public Throwable()

This constructor initializes a newly created Throwable object with null as
its error message string. Also, the method fillInStackTrace (§20.22.5) is
called for this object. 

....

20.22.5  public Throwable fillInStackTrace()

This method records within this Throwable object information about the
current state of the stack frames for the current thread. 

I don't know why they did it that way, but if the specification defines it like that, it is at least consistent on all the various Java VMs.

However, you can refresh it by calling exception.fillInStackTrace() manually.

Also note that you should use Thread.currentThread().getStackTrace() instead of using new Exception().getStackTrace() (bad style).

like image 96
2 revs Avatar answered Sep 21 '22 04:09

2 revs