I have a unique constraint on one of my entities and whenever I get a PSQLException which occurs whenever that constraint is violated, I want to respond with a bad request.
You are catching PSQLException. Instead of that, please catch SQLException. With SQLException you will can handle all this SQL exceptions.
You can check the SQLException knowledge at this link
Then in your code just treat the SQLException as you want. The most generic catch clause is the following one:
catch (SQLException e)
{
System.out.println("ERROR: Fetch statement failed: " +
e.getMessage());
}
With this code you are printing the exception. If you want more information, check this
You might as well register an exception handler for that wrapped exception (that @radek mentioned) directly.
In your case that's:
@ExceptionHandler(DataIntegrityViolationException::class)
protected fun handleDataIntegrityException(ex: DataIntegrityViolationException, request: WebRequest) : ResponseEntity<SomeBody>{
return ResponseEntity.badRequest().body(someBodyHere)
}
The error is converted within convertHibernateAccessException
in org.springframework.orm.jpa.vendorHibernateJpaDialect
, which has already processed away from PSQL. You can add a breakpoint there and follow the stacktrace.
There is a lot of proxy'ing happening under the hood, but the takeaway is that there is always a readable, expressive Exception to use directly.
Key problem is that PSQLException
is wrapped into some Spring exception (which I assume from your code); you have to unwrap it (for example using guava's Throwables):
public DepartmentForHoliday setDepartment(DepartmentForHoliday department) {
if (department.getDepartmentId() == null) {
Department savedDepartment = new Department();
savedDepartment.setName(department.getName());
try {
departmentRepository.save(savedDepartment);
} catch (RuntimeException e) {
Throwable rootCause = com.google.common.base.Throwables.getRootCause(e);
if (rootCause instanceof SQLException) {
if ("23505".equals(((SQLException) rootCause).getSQLState())) {
// do smth interesting :)
}
}
}
}
}
Once you do that you can throw your custom exception and handle it in DatabaseExceptionHandler
This is quite late, but building on previous responses I was able to solve it as so:
try {
return this.projectRepository.saveAndFlush(patchedProjectEntity);
} catch (DataIntegrityViolationException e) {
if (e.getMostSpecificCause().getClass().getName().equals("org.postgresql.util.PSQLException") && ((SQLException) e.getMostSpecificCause()).getSQLState().equals("23505"))
throw new UniqueConstraintViolationException("", e.getMostSpecificCause());
throw e;
}
Where UniqueConstraintViolationException is a custom exception and handled with a spring controller advice.