Avoid creating a stacktrace prior to JDK 1.7

Discussion in 'Java' started by Jan Burse, Sep 30, 2011.

  1. Jan Burse

    Jan Burse Guest

    Dear All,

    I have the following code deep down in a
    recursion which eats up a lot of stack.
    The recursion is not shown but only
    the code:

    Class<?> class;
    try {
    class = Class.forName(str);
    } catch (ClassNotFoundException x) {
    class = null;
    }

    Will it every time I call it for a
    non-existing class build the whole stack
    trace for the exception x and then
    immediately forget about it?

    Now I see in JDK 1.7 (*) a protected
    constructor:

    package java.lang;

    protected Throwable(String message,
    Throwable cause,
    boolean enableSuppression,
    boolean writableStackTrace)

    If I were to write my own forName()
    method I would set the writableStackTrace
    to false if the exception is only needed
    to immediately notify the callee about
    something.

    But what if I have JDK 1.6 only available
    and not JDK 1.7. Can I instruct an exception
    to not fill the stack trace? And way
    arround?

    Bye

    (*)
    http://download.oracle.com/javase/7/docs/api/
    Jan Burse, Sep 30, 2011
    #1
    1. Advertising

  2. Fri, 30 Sep 2011 15:57:57 +0200, /Jan Burse/:

    > I have the following code deep down in a
    > recursion which eats up a lot of stack.
    > The recursion is not shown but only
    > the code:
    >
    > Class<?> class;
    > try {
    > class = Class.forName(str);
    > } catch (ClassNotFoundException x) {
    > class = null;
    > }
    >
    > Will it every time I call it for a
    > non-existing class build the whole stack
    > trace for the exception x and then
    > immediately forget about it?


    I guess so.

    > [...]
    > Can I instruct an exception
    > to not fill the stack trace? And way
    > arround?


    You may perform a check which avoids the exceptional situation like:

    Class<?> class;
    try {
    class = (Class.getResource(str + ".class") != null)
    ? Class.forName(str)
    : null;
    } catch (ClassNotFoundException x) {
    class = null;
    }

    The Class.forName(String) could still fail if the access to the
    resource content is restricted, I imagine.

    --
    Stanimir
    Stanimir Stamenkov, Oct 1, 2011
    #2
    1. Advertising

  3. Jan Burse

    Jan Burse Guest

    Stanimir Stamenkov schrieb:
    > Fri, 30 Sep 2011 15:57:57 +0200, /Jan Burse/:
    >
    >> I have the following code deep down in a
    >> recursion which eats up a lot of stack.
    >> The recursion is not shown but only
    >> the code:
    >>
    >> Class<?> class;
    >> try {
    >> class = Class.forName(str);
    >> } catch (ClassNotFoundException x) {
    >> class = null;
    >> }
    >>
    >> Will it every time I call it for a
    >> non-existing class build the whole stack
    >> trace for the exception x and then
    >> immediately forget about it?

    >
    > I guess so.
    >
    >> [...]
    >> Can I instruct an exception
    >> to not fill the stack trace? And way
    >> arround?

    >
    > You may perform a check which avoids the exceptional situation like:
    >
    > Class<?> class;
    > try {
    > class = (Class.getResource(str + ".class") != null)
    > ? Class.forName(str)
    > : null;
    > } catch (ClassNotFoundException x) {
    > class = null;
    > }
    >
    > The Class.forName(String) could still fail if the access to the resource
    > content is restricted, I imagine.
    >


    Yes, this would change the role of exceptions,
    not use it for business logic, only for
    exceptional flow.

    gr8, thx

    Bye
    Jan Burse, Oct 1, 2011
    #3
  4. Jan Burse

    Lew Guest

    Jan Burse wrote:
    > Stanimir Stamenkov schrieb:
    >> You may perform a check which avoids the exceptional situation like:
    >>
    >> Class<?> class;
    >> try {
    >> class = (Class.getResource(str + ".class") != null)
    >> ? Class.forName(str)
    >> : null;
    >> } catch (ClassNotFoundException x) {
    >> class = null;
    >> }
    >>
    >> The Class.forName(String) could still fail if the access to the resource
    >> content is restricted, I imagine.
    >>

    > Yes, this would change the role of exceptions,


    No, it would /restore/ the role of exceptions.

    The role of exceptions is to
    > not use it for business logic, only for
    > exceptional flow.


    in the first place.

    /Effective Java/, Joshua Bloch, "Item 57: Use exceptions only for exceptional conditions".

    --
    Lew
    Lew, Oct 1, 2011
    #4
  5. Sat, 01 Oct 2011 13:27:39 +0300, /Stanimir Stamenkov/:

    > You may perform a check which avoids the exceptional situation like:
    >
    > Class<?> class;
    > try {
    > class = (Class.getResource(str + ".class") != null)


    I guess the above line should be rewritten like:

    String resourceName = '/' + str.replace('.', '/') + ".class";
    class = (Class.getResource(resourceName) != null)

    to function properly.

    > ? Class.forName(str)
    > : null;
    > } catch (ClassNotFoundException x) {
    > class = null;
    > }


    --
    Stanimir
    Stanimir Stamenkov, Oct 1, 2011
    #5
  6. Sat, 1 Oct 2011 09:10:16 -0700 (PDT), /Lew/:
    > Jan Burse wrote:
    >> Stanimir Stamenkov schrieb:
    >>
    >>> You may perform a check which avoids the exceptional situation like:
    >>>
    >>> Class<?> class;
    >>> try {
    >>> class = (Class.getResource(str + ".class") != null)
    >>> ? Class.forName(str)
    >>> : null;
    >>> } catch (ClassNotFoundException x) {
    >>> class = null;
    >>> }
    >>>
    >>> The Class.forName(String) could still fail if the access to the resource
    >>> content is restricted, I imagine.
    >>>

    >> Yes, this would change the role of exceptions,

    >
    > No, it would /restore/ the role of exceptions.
    >
    > The role of exceptions is to
    >> not use it for business logic, only for
    >> exceptional flow.

    >
    > in the first place.
    >
    > /Effective Java/, Joshua Bloch, "Item 57: Use exceptions only for exceptional conditions".


    I don't think handling the ClassNotFoundException from
    Class.forName(String) contradicts the above statement. In this
    exact case one may consider handling the exception a better
    alternative if the code in question is invoked multiple times with
    possibly the same class name, which class could have been
    initialized already and Class.forName() would just return the Class
    object. The resource lookup may be more expensive operation, if
    repeated every time, just to avoid the exception. One may also
    cache the resource lookup results.

    --
    Stanimir
    Stanimir Stamenkov, Oct 1, 2011
    #6
  7. Jan Burse

    Jan Burse Guest

    Lew schrieb:
    > in the first place.
    >
    > /Effective Java/, Joshua Bloch, "Item 57: Use exceptions only for exceptional conditions".


    The JDK itself violates this rule. For example
    each time a Thread is created the following
    check is run:

    /**
    * Performs reflective checks on given subclass to verify
    * that it doesn't override security-sensitive non-final
    * methods. Returns true if the subclass overrides any of
    * the methods, false otherwise.
    */
    private static boolean auditSubclass(final Class subcl) {
    Boolean result = AccessController.doPrivileged(
    new PrivilegedAction<Boolean>() {
    public Boolean run() {
    for (Class cl = subcl;
    cl != Thread.class;
    cl = cl.getSuperclass())
    {
    try {

    cl.getDeclaredMethod("getContextClassLoader", new Class[0]);
    return Boolean.TRUE;
    } catch (NoSuchMethodException ex) {
    }
    try {
    Class[] params = {ClassLoader.class};

    cl.getDeclaredMethod("setContextClassLoader", params);
    return Boolean.TRUE;
    } catch (NoSuchMethodException ex) {
    }
    }
    return Boolean.FALSE;
    }
    }
    );
    return result.booleanValue();
    }

    In the above the sunshine flow is that we get a boolean
    value false, which means that two NoSuchMethodExceptions
    are thrown. It seems that in connection with the reflection
    API using the exceptions for business logic has become
    the prefered idiom contrary to the advice.

    But this is probably due to a lack of a better reflection
    API. Or we can even analysis it deeper. Since the reflection
    API methods can return so much information AND since java
    does not have multi valued returns, the exceptions have
    been abused for returning additional information.

    In the Go Programming language one would do something:

    getDeclaredMethod(String,Class[]) (Method,Error)

    Shit happens!

    P.S.: Actually the situation is worse in JDK 1.7, the
    audit is done but then cached during the call of
    isCCLOverridden(). This is good. But each call of
    isCCLOverridden() does also poll the cache for
    removal of inaccessible keys! Hm, not sure what
    I should think about that.

    Bye
    Jan Burse, Oct 1, 2011
    #7
  8. Jan Burse

    Jan Burse Guest

    Hi

    And how about suppressing back trace fetch in
    an exception class, can this be done prior to
    JDK 1.6?

    Bye

    Stanimir Stamenkov schrieb:
    > Sat, 01 Oct 2011 13:27:39 +0300, /Stanimir Stamenkov/:
    >
    >> You may perform a check which avoids the exceptional situation like:
    >>
    >> Class<?> class;
    >> try {
    >> class = (Class.getResource(str + ".class") != null)

    >
    > I guess the above line should be rewritten like:
    >
    > String resourceName = '/' + str.replace('.', '/') + ".class";
    > class = (Class.getResource(resourceName) != null)
    >
    > to function properly.
    >
    >> ? Class.forName(str)
    >> : null;
    >> } catch (ClassNotFoundException x) {
    >> class = null;
    >> }

    >
    Jan Burse, Oct 1, 2011
    #8
  9. Sat, 01 Oct 2011 20:04:29 +0200, /Jan Burse/:

    > And how about suppressing back trace fetch in
    > an exception class, can this be done prior to
    > JDK 1.6?


    May be just as global JVM specific setting, but I'm not aware of one.

    --
    Stanimir
    Stanimir Stamenkov, Oct 1, 2011
    #9
  10. Jan Burse

    Lew Guest

    Jan Burse wrote:
    > Lew schrieb:
    >> in the first place.
    >>
    >> /Effective Java/, Joshua Bloch, "Item 57: Use exceptions only for exceptional conditions".

    >
    > The JDK itself violates this rule. For example
    > each time a Thread is created the following
    > check is run:
    > ... [snip excellent example] ...
    >
    > In the above the sunshine flow is that we get a boolean
    > value false, which means that two NoSuchMethodExceptions
    > are thrown. It seems that in connection with the reflection
    > API using the exceptions for business logic has become
    > the prefered idiom contrary to the advice.
    >
    > But this is probably due to a lack of a better reflection
    > API. Or we can even analysis it deeper. Since the reflection
    > API methods can return so much information AND since java
    > does not have multi valued returns, the exceptions have
    > been abused for returning additional information.
    >
    > In the Go Programming language one would do something:
    >
    > getDeclaredMethod(String,Class[]) (Method,Error)
    >
    > Shit happens!
    >
    > P.S.: Actually the situation is worse in JDK 1.7, the
    > audit is done but then cached during the call of
    > isCCLOverridden(). This is good. But each call of
    > isCCLOverridden() does also poll the cache for
    > removal of inaccessible keys! Hm, not sure what
    > I should think about that.


    Excellent analysis and conclusions.

    In bringing up the rule "Use exceptions only for exceptional conditions" [/op cit./] I omitted to mention another important rule, or set of rules:
    - There are no universal rules.
    and its corollaries/consequents,
    - Rules were made to be broken.
    - The virtuoso knows when to break the rules. (The master creates the rules.)
    - The exception probes the rule. [original intent of the cliché preserved]

    Like all the engineering decisions we make, the use of exceptions balances alternatives. One could argue that the conditions you showed in your example were "exceptional" enough to merit handling by exception. Pragmatically, the alternatives suck by comparison anyway. Y'know, that motivating "exceptional conditions" clause leaves a whole lotta wiggle room.

    It's a common joke in engineering disciplines to issue harsh directives that boil down to, "Do what thou wilt, but use good judgment." This does not detract from the wisdom of the advice.

    --
    Lew
    Lew, Oct 1, 2011
    #10
  11. Jan Burse

    Jan Burse Guest

    Lew schrieb:
    > - Rules were made to be broken.


    Yes, a well known common place.

    Now back to the original question of my
    post, I was giving the ClassNotFoundException
    only as a motivation, can I suppress the
    fetching of the backtrace in a Java
    Exception object prior to JDK 1.7?

    Bye
    Jan Burse, Oct 1, 2011
    #11
  12. Jan Burse

    Eric Sosman Guest

    On 10/1/2011 4:04 PM, Jan Burse wrote:
    > Lew schrieb:
    >> - Rules were made to be broken.

    >
    > Yes, a well known common place.
    >
    > Now back to the original question of my
    > post, I was giving the ClassNotFoundException
    > only as a motivation, can I suppress the
    > fetching of the backtrace in a Java
    > Exception object prior to JDK 1.7?


    Quoth the Java SE 6 Javadoc: "A throwable [sic] contains a
    snapshot of the execution stack of its thread at the time it was
    created." That is, the Javadoc promises that a Throwable carries
    a stack trace. A Throwable with no stack trace breaches the
    promise, and since that promise was still in force as of 1.6 I
    deduce that there's no such thing as a stackless Throwable in that
    version, or that it's a bug if there is.

    However, it's the trace of the stack that *creates* the
    Throwable, not necessarily that of the stack that *throws* it.
    So you could create a Throwable once and throw it as many times
    from as many different contexts as you like:

    class MasochismInAction {
    private static OriginUnknownException mystery =
    new OriginUnknownException("Ha-ha, can't find me!");
    public void foolMeOnce() throws OriginUnknownException {
    if (iFeelLikeIt) {
    throw mystery;
    }
    }
    public void foolMeTwice() throws OriginUnknownException {
    if (Math.random() < 0.3) {
    throw mystery;
    }
    }
    ...
    }

    .... and there you have it: Exceptions without (most of) the expense
    of filling a stack trace. Also, it must be noted, Exceptions with
    less ability to help in debugging than almost any others. ("Almost"
    because I've heard somewhere that the JVM creates a few Throwables
    like VirtualMachineError in advance, because by the time they're
    needed the JVM can no longer trust itself to fill them in properly.)

    Personally, I think "Don't Do That" is sage advice here.

    --
    Eric Sosman
    d
    Eric Sosman, Oct 1, 2011
    #12
  13. Jan Burse

    Jan Burse Guest

    Eric Sosman schrieb:
    > ... and there you have it: Exceptions without (most of) the expense
    > of filling a stack trace. Also, it must be noted, Exceptions with
    > less ability to help in debugging than almost any others.


    Actually this is a good solution. To pre-allocate exceptions
    with a small stack trace! Thank you for the good idea.

    The solution could be even spun further. Why not create
    a separate thread, that will provide a service that
    will create exceptions without a big stack trace. Will
    need a little synchronize, but could also work.

    > Personally, I think "Don't Do That" is sage advice here.


    Well it exists in JDK 1.7 for some reason. But you cannot
    do it off hand, you can only do it for your own exceptions
    since the constructor is protected.

    I guess a typical usage scenario would be the creation
    of a stack overflow exception or a memory exception, so
    as to allow the application to recover.

    Usually a stack overflow exception is not so interesting,
    most often it is caused by a loop that starts somewhere
    and all you have is the same method displayed over an over.

    > ("Almost" because I've heard somewhere that the JVM
    > creates a few Throwables like VirtualMachineError in
    > advance, because by the time they're needed the JVM
    > can no longer trust itself to fill them in properly.)


    gr8, one more business case!

    Bye
    Jan Burse, Oct 1, 2011
    #13
  14. Jan Burse

    Eric Sosman Guest

    On 10/1/2011 5:14 PM, Jan Burse wrote:
    > Eric Sosman schrieb:
    >> ... and there you have it: Exceptions without (most of) the expense
    >> of filling a stack trace. Also, it must be noted, Exceptions with
    >> less ability to help in debugging than almost any others.

    >
    > Actually this is a good solution. To pre-allocate exceptions
    > with a small stack trace! Thank you for the good idea.
    > [...]
    > > Personally, I think "Don't Do That" is sage advice here.


    I'm sticking with DDT. You are doing yourself no favors by
    working hard to *prevent* Java from helping you find bugs.

    --
    Eric Sosman
    d
    Eric Sosman, Oct 1, 2011
    #14
  15. Sat, 01 Oct 2011 16:24:46 -0400, /Eric Sosman/:

    > Quoth the Java SE 6 Javadoc: "A throwable [sic] contains a
    > snapshot of the execution stack of its thread at the time it was
    > created." That is, the Javadoc promises that a Throwable carries
    > a stack trace. A Throwable with no stack trace breaches the
    > promise, and since that promise was still in force as of 1.6 I
    > deduce that there's no such thing as a stackless Throwable in that
    > version, or that it's a bug if there is.


    You may be right, but I've read in the Javadoc for
    java.util.logging.Logger, for example
    <http://download.oracle.com/javase/6/docs/api/java/util/logging/Logger.html>:

    | For the methods that do not take an explicit source name and
    | method name, the Logging framework will make a "best effort" to
    | determine which class and method called into the logging method.
    | However, it is important to realize that this automatically
    | inferred information may only be approximate (or may even be
    | quite wrong!). Virtual machines are allowed to do extensive
    | optimizations when JITing and may entirely remove stack frames,
    | making it impossible to reliably locate the calling class and
    | method.

    So it seems stack trace information is not guaranteed to be
    available to user code. This detail may be given somewhere in the
    language or VM specifications.

    --
    Stanimir
    Stanimir Stamenkov, Oct 1, 2011
    #15
  16. Jan Burse <> wrote:
    > Eric Sosman schrieb:
    >> ... and there you have it: Exceptions without (most of) the expense
    >> of filling a stack trace. Also, it must be noted, Exceptions with
    >> less ability to help in debugging than almost any others.

    > Actually this is a good solution. To pre-allocate exceptions
    > with a small stack trace! Thank you for the good idea.


    I just can't see, how you'd make Class.forName(...) throw your
    pre-allocated exception rather than a new one.

    If anything were to be changed in forName(), then it might
    rather be offering a variant that returns null instead of
    throwing an exception. But then again, I think, this particular
    scenario(*) is rare enough that it doesn't really matter.

    (*): namely the scenario of bulk-classloading requiring a cheap
    fail-path.
    Andreas Leitgeb, Oct 2, 2011
    #16
  17. Jan Burse

    Jan Burse Guest

    Stanimir Stamenkov schrieb:
    > quite wrong!). Virtual machines are allowed to do extensive
    > | optimizations when JITing and may entirely remove stack frames,
    > | making it impossible to reliably locate the calling class and
    > | method.
    >
    > So it seems stack trace information is not guaranteed to be available to
    > user code. This detail may be given somewhere in the language or VM
    > specifications.


    Yes, you usually don't get a stack overflow
    when you do tail recursion for example. So
    a method:

    void p(int a) {

    ...
    p(b);
    }

    Is the same as a loop:

    void p(int a) {
    for (;;) {
    ...
    a = b;
    }
    }

    The simplest obtimisation a JIT can do is replace
    the last call p(b) by a jump, so not pushing a
    new return address on the stack and reusing the
    already pushed return address.

    Etc... Etc...

    Bye
    Jan Burse, Oct 2, 2011
    #17
  18. Jan Burse

    Lew Guest

    Stanimir Stamenkov wrote:
    > You may be right, but I've read in the Javadoc for
    > java.util.logging.Logger, for example
    > <http://download.oracle.com/javase/6/docs/api/java/util/logging/Logger.html>:
    >
    > | For the methods that do not take an explicit source name and
    > | method name, the Logging framework will make a "best effort" to
    > | determine which class and method called into the logging method.
    > | However, it is important to realize that this automatically
    > | inferred information may only be approximate (or may even be
    > | quite wrong!). Virtual machines are allowed to do extensive
    > | optimizations when JITing and may entirely remove stack frames,
    > | making it impossible to reliably locate the calling class and
    > | method.
    >
    > So it seems stack trace information is not guaranteed to be
    > available to user code. This detail may be given somewhere in the
    > language or VM specifications.


    Stack trace information is available; the difficulty to which the documentation alludes is that the stack might be in an odd state, not that it wouldn't be available. So it seems stack trace information is guaranteed to be available. Just not necessarily useful in the way you'd like.

    --
    Lew
    Lew, Oct 2, 2011
    #18
  19. Sat, 1 Oct 2011 20:06:23 -0700 (PDT), /Lew/:
    > Stanimir Stamenkov wrote:
    >
    >> You may be right, but I've read in the Javadoc for
    >> java.util.logging.Logger, for example
    >> <http://download.oracle.com/javase/6/docs/api/java/util/logging/Logger.html>:
    >> [...]
    >> So it seems stack trace information is not guaranteed to be
    >> available to user code. This detail may be given somewhere in the
    >> language or VM specifications.

    >
    > Stack trace information is available; the difficulty to which the
    > documentation alludes is that the stack might be in an odd state,
    > not that it wouldn't be available. So it seems stack trace
    > information is guaranteed to be available. Just not necessarily
    > useful in the way you'd like.


    So while Throwable.getStackTrace() might not be null it could be
    empty which effectively means no stack trace information available
    <http://download.oracle.com/javase/6/docs/api/java/lang/Throwable.html#getStackTrace%28%29>:

    | Some virtual machines may, under some circumstances, omit one or
    | more stack frames from the stack trace. In the extreme case, a
    | virtual machine that has no stack trace information concerning
    | this throwable is permitted to return a zero-length array from
    | this method.

    --
    Stanimir
    Stanimir Stamenkov, Oct 2, 2011
    #19
  20. Jan Burse

    Lew Guest

    Stanimir Stamenkov wrote:
    > /Lew/:
    >> Stanimir Stamenkov wrote:
    >>
    >>> You may be right, but I've read in the Javadoc for
    >>> java.util.logging.Logger, for example
    >>> <http://download.oracle.com/javase/6/docs/api/java/util/logging/Logger.html>:
    >>> [...]
    >>> So it seems stack trace information is not guaranteed to be
    >>> available to user code. This detail may be given somewhere in the
    >>> language or VM specifications.

    >>
    >> Stack trace information is available; the difficulty to which the
    >> documentation alludes is that the stack might be in an odd state,
    >> not that it wouldn't be available. So it seems stack trace
    >> information is guaranteed to be available. Just not necessarily
    >> useful in the way you'd like.

    >
    > So while Throwable.getStackTrace() might not be null it could be
    > empty which effectively means no stack trace information available
    > <http://download.oracle.com/javase/6/docs/api/java/lang/Throwable.html#getStackTrace%28%29>:
    >
    > | Some virtual machines may, under some circumstances, omit one or
    > | more stack frames from the stack trace. In the extreme case, a
    > | virtual machine that has no stack trace information concerning
    > | this throwable is permitted to return a zero-length array from
    > | this method.


    Right, but in those "extreme" cases you have a situation where no stack trace information is available to be made available, if you get my drift. Andthey don't help the OP, because he's trying to suppress stack trace information when it could be made available, and he can't count on there being nostack trace available to be available.

    My point was that it isn't quite accurate to say that stack trace information isn't available to user code - in the even that there is any stack traceinformation, that is. If there isn't, the Throwable at least reports thatthere is nothing to report, which gives the programmer more information than would a failure to report.

    So it seems stack trace information is guaranteed to be available. Just not necessarily useful in the way you'd like. But still useful to some degree, more than not making available whatever paucity of information there is.

    There's a difference between "no information" and "information that there is no information". The latter tells you something, at least.

    --
    Lew
    Lew, Oct 2, 2011
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Babar
    Replies:
    1
    Views:
    411
    Chris Smith
    May 20, 2004
  2. Thomas G. Marshall
    Replies:
    5
    Views:
    785
    Thomas G. Marshall
    Aug 6, 2004
  3. Ulf Meinhardt
    Replies:
    0
    Views:
    6,395
    Ulf Meinhardt
    Aug 10, 2006
  4. Jaggu
    Replies:
    3
    Views:
    965
    Nigel Wade
    Jan 8, 2007
  5. Pep

    JDK 1.5 or JDK 1.6

    Pep, Jul 11, 2007, in forum: Java
    Replies:
    19
    Views:
    1,702
    ~kurt
    Jul 15, 2007
Loading...

Share This Page