Java - find the first cause of an exception

2019-02-02 20:10发布

I need to check if an exception is caused by some database problem. I receive an Exception and check if its cause contains the "ORA" string and return that (something like "ORA-00001"). The problem here is that the exception I receive is nested inside other exceptions, so if I don't find out if it's an oracle exception, I have to check into the cause of that exception and so on. Is there a cleaner way to do this? Is there a way to know the first cause (the deep-nested exception) of a given exception?

My current code looks like this:

private String getErrorOracle(Throwable e){
        final String ORACLE = "ORA";
        if (e.getCause() != null && e.getCause().toString().contains(ORACLE)){
            return e.getCause().toString();
        } else if(e.getCause() != null){
            return getErrorOracle(e.getCause());
        } else {
            return null;
        }
    }

9条回答
smile是对你的礼貌
2楼-- · 2019-02-02 20:40

I think that any error that is thrown by oracle will be wrapped in a SQLException (somebody please correct me if wrong). Once you have accessed the SQLException you should be able to call

getErrorCode() Retrieves the vendor-specific exception code for this SQLException object.

Let me know if this works as I have never tried it :-)

Karl

查看更多
smile是对你的礼貌
3楼-- · 2019-02-02 20:46

You could improve your code checking for SQLException

import java.sql.SQLException;

private static final String ORACLE = "ORA";

public String doHandle(Throwable t) {
    if (t.getClass().isAssignableFrom(SQLException.class)) {
    SQLException e = (SQLException) t;
    int errCode = e.getErrorCode();
    String state = e.getSQLState();
    String msg = e.getMessage();
    if (msg.contains(ORACLE)) {
        return msg;
        }
    } else {
        if (t.getCause() != null) {
            return this.doHandle(t.getCause());
            }
        }
    return "";
}

Also, I think in Oracle "errCode" contains the number associated to ORA-nnnn

查看更多
一夜七次
4楼-- · 2019-02-02 20:47

If the exception being thrown is always going to be of a specific type, like OracleException, you can catch just that exception.

For example:

try {

    ...

} catch(OracleException oe) {

    ...

}

This would only apply if there are specific Oracle exceptions being thrown. I don't know much about Oracle, so before attempting this you will probably want to find out if that's what's happening.

查看更多
可以哭但决不认输i
5楼-- · 2019-02-02 20:49

In the interests of not reinventing the wheel, if you're using Apache Commons Lang, then look at ExceptionUtils.getRootCause().

Is it worth including a library just for that? Maybe not. But if you already have it on your classpath, it's there for you, and note that it does some things that a 'naive' implementation might not do (e.g. deal with cycles in the cause chain... ugh!)

查看更多
霸刀☆藐视天下
6楼-- · 2019-02-02 20:55

Probably a bit overkill for your usage but I think it is cleaner (and reusable)

interface ThrowablePredicate {
    boolean accept(Throwable t);
}

public OracleErrorThrowablePredicate implements ThrowablePredicate {
    private static final ORA_ERR = "ORA";

    public boolean accept(Throwable t) {
        return t.toString().contains(ORA_ERR);
    }
}


public class CauseFinder {

   private ThrowablePredicate predicate;

   public CauseFinder(ThrowablePredicate predicate) {
      this.predicate = predicate;
   }

   Throwable findCause(Throwable t) {
      Throwable cause = t.getCause();

      return cause == null ? null 
         : predicate.accept(cause) ? cause : findCause(cause)
   }
}


// Your method
private String getErrorOracle(Throwable e){
    return new CauseFinder(new OracleErrorThrowablePredicate()).findCause(e);
}
查看更多
霸刀☆藐视天下
7楼-- · 2019-02-02 21:00

you can use the getStackTrace() from the Throwable class. This would give you the stack of StackTraceElements to work with. You can iterate through the StackTraceElements[] to find "ORA" string.

Let me know if you need an example.

查看更多
登录 后发表回答