92

I am trying to call saveOrUpdate() in hibernate to save data. Since columns have unique index, so its throws ConstraintViolationException when I look through via Eclipse debugger.

Since root cause could be different for different exception while inserting data to table.
I wanted to know, how can I loop / traverse through getCause() to check what is the root cause of exception and its message.

Update:
Thanks everyone for your kind response, thing is I want output like in below image:
enter image description here
I need to access detailMessage field.
(I am really sorry If could not make my question more clear.)

Thanks.

Aman Gupta
  • 5,548
  • 10
  • 52
  • 88

9 Answers9

120

The Apache ExceptionUtils provide the following method:

Throwable getRootCause(Throwable throwable) 

as well as

String getRootCauseMessage(Throwable th) 
reto
  • 9,995
  • 5
  • 53
  • 52
  • 20
    You can find something similar in Guava's [Throwables](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/base/Throwables.html): `getRootCause(Throwable)` and `getStackTraceAsString(Throwable)` – Paolo Fulgoni Mar 31 '14 at 07:28
  • 1
    However Guava has an [issue](https://github.com/google/guava/issues/1173) regarding db style exception, thus creating infinite loops. – bric3 Jan 15 '18 at 11:09
  • Yes but this requires using Guava or Apache Commons, if your project is small enough it doesn't make sense, have a look at my anwser bellow I provide a 3 line util function. – Mehdi Mar 05 '19 at 18:32
  • Mehdi, your solution doesn't seem to handle possible infinite loops. – rougou Mar 29 '19 at 02:47
  • Unfortunately, Apache's solution will return the same exception if it is equal to the root cause. Sometimes that's not the intend. I would say to use Legna's. – Malvon Dec 03 '19 at 03:59
  • See also https://stackoverflow.com/a/65442410/548473 in case you have Spring dependency (`NestedExceptionUtils.getRootCause`) – Grigory Kislin Dec 24 '20 at 21:44
93

I normally use the implementation below instead of Apache's one.

Besides its complexity, Apache's implementation returns null when no cause is found, which force me to perform an additional check for null.

Normally when looking for an exception's root/cause I already have a non-null exception to start with, which is for all intended proposes is the cause of the failure at hand, if a deeper cause can't be found.

Throwable getCause(Throwable e) {
    Throwable cause = null; 
    Throwable result = e;

    while(null != (cause = result.getCause())  && (result != cause) ) {
        result = cause;
    }
    return result;
}
Legna
  • 1,632
  • 15
  • 15
  • 2
    Indeed its helpful ! :) Thanks ! – Aman Gupta Mar 09 '15 at 05:56
  • 15
    I believe such answers should be prefered by the questioner and the community as opposed to the answers with only a tool or lib recommendation. – Aleksandr Erokhin Jun 05 '15 at 12:23
  • 10
    The implementation I provided above is guards you from cyclically chained exceptions of just one step in depth, meaning when the exception chains to itself e = e.getCause() (the most common and only situation I have met). Nevertheless apache's implementation will really guard your code from cyclic exception chains of any depth e = e.getCause().getCause()... etc .. .getCause(); – Legna Jun 05 '15 at 21:30
  • in which cases (result != cause) will help? – Kulbhushan Singh Jun 30 '16 at 08:49
  • @KulbhushanSingh '(result != cause)' will help every single time 'result' has a non null cause. the condition/expression on the while statement evaluates in the following order: 1.- assign cause = result.getCause() 2.- evaluates the result of the assignment above for null. null != cause 3.- if cause == null the whole expression evaluates to false, otherwise it proceeds to 4.- evaluate (result != cause) and that's your result – Legna Nov 15 '16 at 00:09
  • No additional libraries or frameworks, simple and doable logic, thanks for this answer! – rado Feb 18 '18 at 03:33
  • -1: *Apache's implementation returns null when no cause is found, which force me to perform an additional check for null.*: er? `ExceptionUtils.getRootCause(new Exception())` returns the input Exception, so I think the whole benefit argument provided in the answer is misguided. In fact, the implementation in the answer produces the exact same result as `ExceptionUtils.getRootCause()`, but unlike Apache's, has only marginal handling for cyclic causes so can go into an infinite loop. – antak Dec 20 '19 at 04:15
  • would there be any concern with using such code in production? – Daniel Pop Mar 23 '21 at 09:04
28

Using java 8 Stream API, this can be achieved by:

Optional<Throwable> rootCause = Stream.iterate(exception, Throwable::getCause)
                                      .filter(element -> element.getCause() == null)
                                      .findFirst();

Note that this code is not immune to exception cause loops and therefore should be avoided in production.

Oliver
  • 3,815
  • 8
  • 35
  • 63
SpaceTrucker
  • 13,377
  • 6
  • 60
  • 99
  • 3
    I like this code, but failed to understand why it should be avoided in production, is there an example? – A. S. Ranjan Aug 24 '20 at 11:44
  • @A.S.Ranjan I think you should post a question of its own on SO and ask what a exeption cause loop is and why this can be dangerous in production to encounter. – SpaceTrucker Aug 25 '20 at 05:26
10

Are you asking for something like this?

Throwable cause = originalException;
while(cause.getCause() != null && cause.getCause() != cause) {
    cause = cause.getCause();
}

or am I missing something?

morgano
  • 17,210
  • 10
  • 45
  • 56
  • 8
    Exception is basically of DB type exceptions. so above while loop goes in indefinite loop. – Aman Gupta Jul 19 '13 at 13:52
  • 1
    It can be N causes deep.... cause.getCause().getCause().getCause().. hence the need for something like Apache ExceptionUtils.getRootCause() – johnm Jun 02 '15 at 16:21
8

Guava's Throwables provides the following methods:

Throwable getRootCause(Throwable throwable)

as well as

String getStackTraceAsString(Throwable throwable)
schnatterer
  • 7,525
  • 7
  • 61
  • 80
4

In APACHE; the implementation is like below.

The highlight is list.contains(throwable) == false

public static Throwable getRootCause(final Throwable throwable) {
    final List<Throwable> list = getThrowableList(throwable);
    return list.size() < 2 ? null : (Throwable)list.get(list.size() - 1);
}

public static List<Throwable> getThrowableList(Throwable throwable) {
    final List<Throwable> list = new ArrayList<Throwable>();
    while (throwable != null && list.contains(throwable) == false) {
        list.add(throwable);
        throwable = ExceptionUtils.getCause(throwable);
    }
    return list;
}
Kanagavelu Sugumar
  • 18,766
  • 20
  • 94
  • 101
3
} catch (Exception ex) {
    while (ex.getCause() != null)
        ex = ex.getCause();
    System.out.println("Root cause is " + ex.getMessage());
}

Were you expecting something more complicated?

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
  • actually I am getting database regarding exception, so in that case above logic is not working. anyway thanks for your response. :) – Aman Gupta Jul 19 '13 at 13:50
  • 3
    This is not immune to loops - the case where an exception cause points to exception itself. – brabec Mar 14 '14 at 17:18
  • @agpt why the above logic does not work with the database in relation to exclusion? – Alex78191 Sep 04 '19 at 17:18
3

Try this, you can put this function in a kind of Util class:

public static Throwable getRootException(Throwable exception){
 Throwable rootException=exception;
 while(rootException.getCause()!=null){
  rootException = rootException.getCause();
 }
 return rootException;
}

Example of usage :

catch(MyException e){
  System.out.println(getRootException(e).getLocalizedMessage());
}

Source : How to get the root exception of any exception

Mehdi
  • 1,340
  • 15
  • 23
2

Recursively:

public static Throwable getRootCause(Throwable e) {
    if (e.getCause() == null) return e;
    return getRootCause(e.getCause());
}
Roman Khomyshynets
  • 724
  • 1
  • 9
  • 12
  • Might want to replace `if (e.getCause() == null)` with `if (e == null)` else you'll lose one level information. – sbrk May 26 '20 at 09:14