Reputation: 809
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
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
Reputation: 86
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
Reputation: 131
Insert a catch
statement like this:
catch (DataIntegrityViolationException e) {
String message = e.getMostSpecificCause().getMessage();
}
Upvotes: 13
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