[Java] NullpointerException cause

Pagina: 1
Acties:

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Topicstarter
Ik krijg zojuist een NullpointerException en als ik in de Eclipse Debugger de cause bekijk, krijg ik het volgende vreemde beeld.

Afbeeldingslocatie: http://img168.imageshack.us/img168/446/nullpointershi1.png

Het lijkt erop dat bij een nullpointerexception de cause altijd ook een nullpointerexception is. Ik weet namelijk vrijwel zeker dat mijn exceptions nooit zo diep genest kunnen zijn.

Iemand een idee?

[ Voor 2% gewijzigd door JKVA op 30-01-2007 18:11 . Reden: Verkeerde url ]

Fat Pizza's pizza, they are big and they are cheezy


  • CodeCaster
  • Registratie: Juni 2003
  • Niet online

CodeCaster

Can I get uhm...

Je bent gewoon pwned.

Kun je Eclipse niet even opnieuw installeren, of misschien een stukje relevante code?

https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...


  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

Da's normaal :+ De cause is zelf ook null. Doe maar eens e.getCause(). Wanneer je e.getCause().getCause() doet, dan krijg je een nieuwe NPE.

  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Voor mij is het ook nieuw, maar als je kijkt in de source code van Throwable dan zie je dat cause default zichzelf is:
Java:
1
2
3
// snip...
private Throwable cause = this;
// snip...

Dus vandaar de nesting in cause, dit is bij iedere exception zo tenzij een andere cause wordt opgegeven in de constructor of via de initCause methode.

In de getCause() methode wordt dit echter geneutraliseerd:
Java:
1
2
3
4
5
// snip...
public Throwable getCause() {
    return (cause==this ? null : cause);
}
// snip...

Daarom zie je het niet als je de exception cause in code uitvraagt. Waarschijnlijk is het gewoon een omslachtige manier om te bepalen of cause al een keer gezet is of niet. Ik weet niet wat degene die de initCause() methode geschreven heeft zat te roken, maar goed het lijkt uiteindelijk allemaal wel te werken.

  • bloody
  • Registratie: Juni 1999
  • Laatst online: 01-12 19:05

bloody

0.000 KB!!

misfire schreef op dinsdag 30 januari 2007 @ 19:49:

Java:
1
2
3
// snip...
private Throwable cause = this;
// snip...
Voor de duidelijkheid: eclipse kijkt rechtstreeks naar de waarden van je attributen :)

nope


  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

In een NPE kun je inderdaad geen cause stellen. Dat zou onzinnig zijn, want de oorzaak van een NPE is .. null :) De cause is alleen een placeholder voor een eventuele exceptie die de oorzaak is van de huidige exceptie.

Zie ook het volgende voorbeeld:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Test {

    public static void main(String[] args) {
        try {
            try {
                try {
                    try {
                        throw new Exception();
                    } catch (Exception e1) {
                        throw new Exception(e1);
                    }
                } catch (Exception e2) {
                    throw new Exception(e2);
                }
            } catch (Exception e3) {
                throw new Exception(e3);
            }
        } catch (Exception e4) {
            System.out.println(e4.getCause());
        }
    }

}


De NPE kent geen constructor die een Throwable accepteert, deze zal dan ook altijd null zijn.

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Maar zou je Cause dan niet gewoon null horen te zijn ipv een refference naar zichzelf te bevatten?

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
De returnwaarde van "getCause()" kan afwijken van de "cause" private member field (die in het screenshot getoond wordt). Als de cause private member field de "this" referentie is (hetzelfde object als de throwable die hem bevat), dan retourneert getCause() null ipv de waarde van cause. Zoals bloody al aangeeft zie je in de debugger echter de "cause" private member field, en niet het resultaat van getCause(). Dat verklaart waarom het er in de debugger zo maf uitziet.

  • Nick_S
  • Registratie: Juni 2003
  • Laatst online: 05:58

Nick_S

++?????++ Out of Cheese Error

Wat je ook in de debugger ziet, is het ID van het object, welke in dit geval telkens dezelfde is. Hierdoor heb je eigenlijk een circular tree, die dus oneindig is.

Als de NPE een link naar zichzelf bevat, dan is de link in de link dus weer een link naar zichzelf, etc.

'Nae King! Nae quin! Nae Laird! Nae master! We willna' be fooled agin!'


  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Topicstarter
Hmm, ik heb in dezelfde applicatie ook een recursief stukje code die de diepste Exception achterhaalt. Blijkbaar dus wel slim om zelf verantwoordelijkheid te nemen en te checken dat de cause niet 'this' is.

De oude variant:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    private void verwerkException(Exception e) {
        LOGGER.debug("verwerkException(): " + e);
        if (e instanceof ApplicatieException) {
            verwerkApplicatieException((ApplicatieException) e);
        } else if (e instanceof SysteemException) {
            verwerkSysteemException((SysteemException) e);
        } else if (e.getCause() != null) {
            // Is niet oneindig, eerdere if's zijn de guard
            verwerkException((Exception) (e.getCause()));
        } else {
            String timestamp = DateUtil.dateAndTimeAsString(DateUtil.now());
            LOGGER.debug("Niet afgevangen Exception op tijdstip " + timestamp + ": ", e);
            toonFoutpagina(e, timestamp);
        }
    }


De nieuwe, veiligere variant;
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    private void verwerkException(Exception e) {
        LOGGER.debug("verwerkException(): " + e);
        if (e instanceof ApplicatieException) {
            verwerkApplicatieException((ApplicatieException) e);
        } else if (e instanceof SysteemException) {
            verwerkSysteemException((SysteemException) e);
        } else if (e.getCause() != null && e.getCause() != e) { //###### dit is dus aangepast #######
            // Is niet oneindig, eerdere if's zijn de guard
            verwerkException((Exception) (e.getCause()));
        } else {
            String timestamp = DateUtil.dateAndTimeAsString(DateUtil.now());
            LOGGER.debug("Niet afgevangen Exception op tijdstip " + timestamp + ": ", e);
            toonFoutpagina(e, timestamp);
        }
    }

Fat Pizza's pizza, they are big and they are cheezy


  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Die extra controle is niet nodig omdat dit in de Throwable.getCause() al voor je wordt afgehandeld. :) Zie de eerdere code snippet of de Trowable source code. De rare manier hoe cause wordt geïnitialiseerd blijft beperkt tot wat verwarring in de debugger, als je netjes getCause() doet krijg je gewoon null terug.

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Topicstarter
Dat klopt, maar in productie ben ik liever safe than sorry. Heb geen tijd om de spec erbij te pakken, maar ik weet niet uit mijn hoofd wat bijvoorbeeld JRockit ermee doet. Waarschijnlijk blijft het werken, maar ik ben liever zeker in zulke gevallen.

Performance speelt toch bijna niet in dit stukje code...

Fat Pizza's pizza, they are big and they are cheezy


  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Ik denk niet dat je op dit punt bang hoeft te zijn over verschillen in JRE implementaties, maar aangezien getCause() kan worden overridden kan het nuttig zijn om op te checken. Als je het toch over productiecode hebt: het resultaat van getCause() kan niet altijd gecast worden naar Exception. Het kan namelijk ook een Error zijn, en dan klapt de methode er nu uit met een ClassCastException.

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Topicstarter
misfire schreef op donderdag 01 februari 2007 @ 11:14:
Ik denk niet dat je op dit punt bang hoeft te zijn over verschillen in JRE implementaties, maar aangezien getCause() kan worden overridden kan het nuttig zijn om op te checken. Als je het toch over productiecode hebt: het resultaat van getCause() kan niet altijd gecast worden naar Exception. Het kan namelijk ook een Error zijn, en dan klapt de methode er nu uit met een ClassCastException.
Goed punt :)

Fat Pizza's pizza, they are big and they are cheezy

Pagina: 1