How to handle JPA function exception - spring-boot

When I am calling save() of JPA it is giving exception of ConstraintViolation exception but it is inside nested exception.
First one is IllegalStateException, then NestedServletException, DataIntegrotyViolationException, ConstraintViolationException, SQLServerException
There
com.microsoft.sqlserver.jdbc.SQLServerException: Violation of UNIQUE KEY constraint 'uk_urmapping_uname_role'. Cannot insert duplicate key in object 'dbo.employee_role_mapping'. The duplicate key value is (wxy ., ABC).
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:259) ~[mssql-jdbc-6.4.0.jre8.jar:na]
at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1547) ~[mssql-jdbc-6.4.0.jre8.jar:na]
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:548) ~[mssql-jdbc-6.4.0.jre8.jar:na]
In CustomExceptionHandler class I added
#ExceptionHandler({ GenericJDBCException.class, SQLException.class, DuplicateKeyException.class,
ConstraintViolationException.class, JDBCException.class })
public ResponseEntity<Object> processSqlExceptions(SQLException e, WebRequest request) {
logger.error("SQL Error : ", e);
logger.warn("SQL Error : ", e);
ErrorResponse error = new ErrorResponse("600", e.getMessage(), tracer.currentSpan().context().spanIdString());
return handleExceptionInternal(e, error, new HttpHeaders(), HttpStatus.BAD_REQUEST, request);
}
I tried to handle some exception, still it is not able to handle exception.

It is a DataIntegrityViolationException so you should have it added in the handler.
#ExceptionHandler(value = {DataIntegrityViolationException.class})

If you use hibernate then it throws it's own version of ConstraintViolationException.
So make sure you handle org.hibernate.exception.ConstraintViolationException instead of javax.validation.ConstraintViolationException (or both).

Related

Does spring boot automatically take care of error handling in the context of JpaRepository methods?

When using Spring Boot, I am unsure if error handling is already being taken care of by the Spring Framework, or if I have to implement it. For example, consider a controller method, which handles a DELETE request:
#DeleteMapping("/{studentId}")
public ResponseEntity<Long> deleteProfilePicture(#PathVariable Long studentId) {
return ResponseEntity.ok(profilePictureService.deleteprofilePictureByStudentId(studentId));
}
Is this fine, or should I instead wrap it inside a try-catch block:
#DeleteMapping("/{studentId}")
public ResponseEntity<Long> deleteProfilePicture(#PathVariable Long studentId) throws Exception {
try {
profilePictureService.deleteProfilePictureByStudentId(studentId));
} catch (DataAccessException e) {
throw new Exception("cannot delete profile picture of student: " + studentId);
}
}
Also: If I let my method deleteProfilePicture throw this Exception, who is handling the Exception? This must somehow be taken care of by Spring Boot, since it is possible to implement it without yielding any errors. Anyhow, what is the correct way of error handling in this scenario?
Spring Boot will turn the exception into an error response to the caller of the REST API. This does not mean that you shouldn't implement your own error handling logic, which you definitely should. As an example, you could use #ControllerAdvice to have a global exception handling for your application. Something along the following lines:
#ControllerAdvice
#Slf4j
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(value = {Exception.class})
public ResponseEntity<Object> handleGenericExceptions(Exception exception, WebRequest webRequest) {
log.error("Handling: ", exception);
HttpStatus errorCode = HttpStatus.INTERNAL_SERVER_ERROR;
return this.handleExceptionInternal(exception, new ErrorInfo(errorCode.value(), "Unexpected Internal Server Error"), new HttpHeaders(), errorCode, webRequest);
}
}
You can read more about error handling in Spring Boot at https://www.baeldung.com/exception-handling-for-rest-with-spring.

Spring 5 exception handling - ResponseStatusException model

I was reading the article - https://www.baeldung.com/exception-handling-for-rest-with-spring
which says
Spring 5 introduced the ResponseStatusException class.
We can create an instance of it providing an HttpStatus and optionally
a reason and a cause:
I started implementing it , and the code is
custom exception
#ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Actor Not Found")
public class ActorNotFoundException extends Exception {
private static final long serialVersionUID = 1L;
public ActorNotFoundException(String errorMessage) {
super(errorMessage);
}
}
method in service
public String updateActor(int index, String actorName) throws ActorNotFoundException {
if (index >= actors.size()) {
throw new ActorNotFoundException("Actor Not Found in Repsoitory");
}
actors.set(index, actorName);
return actorName;
}
controller
#GetMapping("/actor/{id}")
public String getActorName(#PathVariable("id") int id) {
try {
return actorService.getActor(id);
} catch (ActorNotFoundException ex) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Actor Not Found", ex); //agreed it could be optional, but we may need original exception
}
}
repo:
https://github.com/eugenp/tutorials/tree/master/spring-5/src/main/java/com/baeldung/exception
Question:
why ResponseStatusException in controller again has to specify reason - "Actor Not Found" ?, as the service already said - ""Actor Not Found in Repsoitory"
What is the proper way to adapt to ResponseStatusException model?
It looks like a mistake. Ideally the service shouldn't use any HTTP code, so I would remove the annotation in ActorNotFoundException. Everything else seems fine, the exception is caught in the controller and ResponseStatusException is thrown which is good, because it's a proper layer to put HTTP stuff.
Overall it is better to use #ControllerAdvice instead of ResponseStatusException. it gives you a unified exception handling solution. Although it is not a good idea from a design point of view, ResponseStatusException can help you to avoid creating your custom exceptions and use it at the service level to throw in case of an Exception.
to avoid writing the message again you can use the message that is already available in thrown exception:
throw new ResponseStatusException(HttpStatus.NOT_FOUND, ex.getMessage() , ex);
for examples and more info you can refer to the following articles:
Spring Boot Exception Handling — #ControllerAdvice
Spring Boot Exception Handling — ResponseStatusException

#ControllerAdvice and Create Error Message in Business Layer

Assume i have defined #ControllerAdvice
#ControllerAdvice
public class ErrorHandler {
// example
#ExceptionHandler(ParseException.class)
public void handleParseException(ParseException exception, HttpServletResponse response) {
// return response - error message, error description, error type (ERROR or EXCEPTION)
}
}
The problem is where i will formulate the error message text with parameters and also the message type - ERROR or EXCEPTION
Example, Assume file not found exception is thrown for the given file name
Generally, in message.properties file we will be having text as File Doesn't Exist for file {0}
The translation of error message usually happens in the presentation layer.....
Now if we need to pass the error message so that controller advice takes care of passing it to the UI....
Do we need to construct the error message in the service layer before sending ??? Where the exception and the parameters will be binded ???
for example
public void accessFile(String fileName) {
File file = new File(fileName);
if(!file.exists()) {
throw new FileNotFoundException(Constants.FILE_NOT_FOUND.....);
How to construct the error message with property key and sending with
proper error message binded with exception???
so that in controller advice we would just use exception.getMessage()
which will have the translated text.
}
}
Please let me know how to do it.
I would have a method like below to create a json object and use the same in UI to populate error message.
#RestControllerAdvice
public class ExceptionProcessor {
//.....
//.....
#ExceptionHandler(IOException.class)
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResource handleParseException(final IOException ex, final WebRequest request) {
// return response - error message, error description, error type (ERROR or EXCEPTION)
return _errorBuilder.build(ex, GenericErrorCode.ERR0500, request)
.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value())// error code
.setMessage("Internal server error") //message
.setDetails(new ErrorDetailResource.Builder()
.setLocationType("system")
.setMessage(ex.getMessage())// description
.build())
.build();
}
So basically you are creating an object from your exception and passing it back as your response so that UI can handle this error message appropriately.
Now you can design your object to pass it to UI
and you can build your error message in business layer while throwing excpetion or read it from property as given below.
#Value("${error.invalidfile.message}")
private String parseErrMessage;
and then in that method when you are creating a message, use this message
---------Edit 2
If you need to pass something other than excpetion message then create your own exception.
MyIOException extends IOException{
//...
String exceptionMessagKey;
//getter and setter
}
Then throw and catch this exception and build your message accordinggly from message and the exceptionMessagKey in the excpetion object.
public ErrorResource handleParseException(final MyIOException ex, final WebRequest request){
...
// Use ex.getExceptionMessagKey() and ex.getMessage()
....
}

Spring Exception Handler log all exceptions but return original response

So I am trying to log all uncaught exceptions returned by the controllers of a spring project in a generic fashion.
I was able to do this with the following exception handler:
#ControllerAdvice
public class ControllerConfig {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public static final String DEFAULT_ERROR_VIEW = "error";
#ExceptionHandler(HttpMessageNotReadableException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
public void handleBadRequest(HttpMessageNotReadableException e) {
logger.warn("Returning HTTP 400 Bad Request", e);
throw e;
}
#ExceptionHandler(AccessDeniedException.class)
public void defaultErrorHandler(HttpServletRequest request, Exception e) throws Exception {
logger.error("Error in request:" + request.getRequestURL(), e);
throw e;
}
This also returns the error responses of the request, so I don't have to differentiate between all the different error response codes.
However, for every invocation of the method a second error log is created because of the exception thrown in the method:
Code is from org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#doResolveHandlerMethodException
try {
if (logger.isDebugEnabled()) {
logger.debug("Invoking #ExceptionHandler method: " + exceptionHandlerMethod);
}
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception);
}
catch (Exception invocationEx) {
if (logger.isErrorEnabled()) {
logger.error("Failed to invoke #ExceptionHandler method: " + exceptionHandlerMethod, invocationEx);
}
return null;
}
So is there a smarter way to return the original exception of the method?
It depends on what do you mean by "a smarter way to return the original exception". What exactly would you like to return to the client? If this is just the message of the exception you can simply return it from the exception handler and annotate the method with #ResponseBody. Spring will do the rest for you.
#ExceptionHandler(HttpMessageNotReadableException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public String handleBadRequest(HttpMessageNotReadableException e) {
logger.warn("Returning HTTP 400 Bad Request", e);
throw e.getMessage();
}
You can also return some custom object which wraps the exception information and any other data that you desire.

Why exception handler is not catching error in Spring MVC

I want to catch an Error in springMVC3 using exception handler. I annotated the exception. I can catch throwable and any exception. But when I tried with Error, It is not catching the exception. Any idea why it is so? The below code catches exceptions
ExceptionHandler(InvalidDataException.class)
public ModelMap handleException(InvalidDataException ex) {
logger.debug("exception catched :" + ex);
return new ModelMap();
}
But the below is not catching;
#ExceptionHandler(Error.class)
public ModelMap handleException(Error ex) {
logger.debug("exception catched :" + ex);
return new ModelMap();
}
The second example is not working because you are catching an Error, which extends Throwable and not Exception. You will find that the code will work if you change to the '#ExceptionHandler' and the 'handleException()' method to either 'Exception', 'InvalidDataException' or any other exception that is of interest.
Even I too faced the same problem ,I think #ExceptionHandler can deal with exceptions only not with throwable and errors
Refer the link:ExceptionHandler doesn't work with Throwable

Resources