Arthur Accioly
Arthur Accioly

Reputation: 809

How to get the constraint name in a org.springframework.dao.DataIntegrityViolationException?

In my application when a violation key is raised, I would like to get the constraint name, but I'm not finding any method to get this information. The message returned by "getMessage()" is very summarized and I need more information about the error to make a customizable error message to the end user.

The stack trace:

84732 [http-8080-1] WARN  org.hibernate.util.JDBCExceptionReporter  - SQL Error: 0, SQLState: 23505
84732 [http-8080-1] ERROR org.hibernate.util.JDBCExceptionReporter  - ERROR: duplicate key value violates unique constraint "ix_tb_oferta_vaga"
  Detalhe: Key (cd_pj, cd_curso)=(680, 29) already exists.
187405 [http-8080-1] WARN  org.hibernate.util.JDBCExceptionReporter  - SQL Error: 0, SQLState: 23505
187405 [http-8080-1] ERROR org.hibernate.util.JDBCExceptionReporter  - ERROR: duplicate key value violates unique constraint "ix_tb_oferta_vaga"
  Detalhe: Key (cd_pj, cd_curso)=(680, 29) already exists.

The getMessage():

could not insert: [br.gov.ce.seduc.estagio.model.bean.OfertaVaga]; nested exception is org.hibernate.exception.ConstraintViolationException: could not insert: [br.gov.ce.seduc.estagio.model.bean.OfertaVaga]

Thanks.

Arthur

Upvotes: 13

Views: 11216

Answers (4)

ebey
ebey

Reputation: 153

You can handle like that

catch (DataIntegrityViolationException ex){
     String constraintName = ((ConstraintViolationException)ex.getCause()).getConstraintName();
 ...

But be careful import will be

 import org.hibernate.exception.ConstraintViolationException;

not

 import javax.validaiton;

Upvotes: 4

If you are using PostgreSQL and you are really interested to find detailed cause of the exception, then you can use PostgreSQL in compilation time, as so:

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <!--<scope>runtime</scope>-->
</dependency>

This way, you will have utility methods and the PSQLException class. With this, now you can cast most specific cause to it.

var exceptionCause = exception.getMostSpecificCause();

if (exceptionCause instanceof PSQLException psqlException) {
    var serverErrorMessage = psqlException.getServerErrorMessage();

    if (serverErrorMessage != null) {
        var detail = serverErrorMessage.getDetail();
        exceptionCause = new Exception(detail);
    }
}

As you can see, now you can throw or handle this exceptionCause that will have your detailed or human-readable message.

Upvotes: 0

Guilherme Berghauser
Guilherme Berghauser

Reputation: 131

Insert a catch statement like this:

catch (DataIntegrityViolationException e) {
        String message = e.getMostSpecificCause().getMessage();
}

Upvotes: 13

Nathan Hughes
Nathan Hughes

Reputation: 96454

Wrapping exceptions usually have a way to nest the original exception within them. For Hibernate, your ConstraintViolationException is a JDBCException, it has a method called getSQLException that returns the actual exception. So call getCause on the Spring DataIntegrityViolationException (in order to get the Hibernate exception), call getSQLException on that, and finally call getMessage() on the SQLException. The message should be the same as what you see logged by the Hibernate JDBCExceptionReporter, if you want only the constraint name you will have to parse the string.

Upvotes: 6

Related Questions