Java Spring persist stack trace when 500 error happens - spring

I am hosting an Spring boot application on Amazon EC2. Sometimes in the morning when I go to the webpage I will see
"Could not open JPA EntityManager for transaction; nested exception is javax.persistence.PersistenceException: org.hibernate.TransactionException: JDBC begin transaction failed:"
from the browser. However I have no way to get back the stack trace. So is this possible in Spring: When 500 error happens, spring will catch the exception and store it in database or local file so I can get it back later. I think it would be helpful for debug the hard-to-reproduce 500 errors.

Yes it is possible you just need configure your controllers to use Spring exception handling https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
Then you can configure which level of exceptions you want to catch(in your case general Exception would be ok, or if you know the specific exception much better)
// Total control - setup a model and return the view name yourself. Or consider
// subclassing ExceptionHandlerExceptionResolver (see below).
#ExceptionHandler(Exception.class)
public ModelAndView handleError(HttpServletRequest req, Exception exception) {
logger.error("Request: " + req.getRequestURL() + " raised " + exception);
//Here you can persist the exception or just write in the log
ModelAndView mav = new ModelAndView();
mav.addObject("exception", exception);
mav.addObject("url", req.getRequestURL());
mav.setViewName("error");
return mav;
}
}

Related

How can I configure a Spring Application to Include the thrown Exception as a message in Error 500 (Internal Server Error)?

I have a spring backend application which throws some helpful custom Java exceptions in response to faulty REST API calls, and I have seen tutorials where the thrown exception also shows up as a message value in the returned code 500 internal server error. I'm wondering if there is a way to configure spring such that these thrown exception messages are sent back with the 500 error response.
This can be achieved using this code.
#ControllerAdvice
class GlobalExceptionHandler {
#ExceptionHandler(Exception.class)
ResponseEntity onAnyUnknownException(Exception exception) {
logger.error("Some unknown exception occured", exception);
Map<String, Object> userResponse = new HashMap<>();
userResponse.put("ERROR", "Your custom message");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(userResponse);
}
}

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

Can not handle JDBCConnectionException in spring rest with custom exception handler

I use a global exception handler in my spring rest app and I would like to hide jdbc exceptions, but it doesn't work as expected. I shut down the database to force a connection exception and I can see the following exception in the log and I receive the default spring error response, but not the one I defined in the exception handler
java.lang.IllegalStateException: Could not resolve parameter [1] in public org.springframework.http.ResponseEntity<java.lang.Object> ...
throws java.io.IOException: No suitable resolver
Here's the code.
#ControllerAdvice
public class CustomGlobalExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler({JDBCConnectionException.class})
public ResponseEntity<Object> dbError(JDBCConnectionException exception,
HttpHeaders headers,
HttpStatus status,
WebRequest request) throws IOException
{
Map<String,Object> body = new HashMap<>();
body.put("errorId",Long.valueOf(201));
body.put("state",HttpStatus.SERVICE_UNAVAILABLE.value());
body.put("message", "internal failure");
body.put("time", new Date().toString());
return new ResponseEntity<>(body, headers, status);
}
Hope you can help me.
I've found the failure...spring can not resolve these two parameters, for that kind of exception.
HttpHeaders headers,
HttpStatus status
It's obviouse the exception mentioned paramter [1]
java.lang.IllegalStateException: Could not resolve parameter [1] in public org.springframework.http.ResponseEntity<java.lang.Object> ...
throws java.io.IOException: No suitable resolver
I removed these two parameters and the exception handler handles the exception.
This code works now
#ExceptionHandler(JDBCConnectionException.class)
public ResponseEntity<Object> dbError(Exception ex,
WebRequest request)
{
Map<String,Object> body = new HashMap<>();
body.put("errorId",Long.valueOf(201));
body.put("state",HttpStatus.SERVICE_UNAVAILABLE.value());
body.put("message", "internal failure");
body.put("time", new Date().toString());
return new ResponseEntity<Object>(body, HttpStatus.INTERNAL_SERVER_ERROR);
}
As the annotation implies #ControllerAdvice is used as an extension on your REST endpoints, these exception handlers will process the exception for the REST API and does not influence how it is logged in the console. It will instead determine how exceptions are reported to your end users and allow you to write concise error messages without leaking information about your program.
If you want to completely catch an exception and not only for the REST API take a look at this blog.
However I would not recommend doing this since this will greatly reduce the information available to you as a developer, this information cannot be seen by end users and therefore the REST API custom exception should provide enough abstraction.
I hope this helps you.

How Runtime Exceptions are handled by Spring ExceptionHandler

I am using spring's #ControllerAdvice and #ExceptionHandler for exception handling.
Any method throws custom exception from Controller and corresponding #ExceptionHandler handle it. If Runtime exception occurs(eg any HibernateException) then it will throw Runtime Exception and I dont have any #ExceptionHandler for RuntimeExceptions.
My question is how to handle any runtime exception? do I need to add #ExceptionHandler for every Exception that is thrown by controller?
I dont want create an Generic ExceptionHandler for Exception.class because I have to send different error code according to exception occured.
one way to do it add try catch block in Controller and then throw the custom exception from catch block?
or is there any another better way?
All #ExceptionHandlers are inside #ControllerAdvice class.
the alternative is don't catch Exception in Controller. catch all Exception in service layer and throw a custom Exception eg. if you persisting a record failed, throw DatabaseException with message. see below method:
Student persist(Student object){
try{
studentDao.insert(object);
}catch(HibernateException e){
throw new DatabaseException("database operation failed!");
}
return student;
}
from you exception handler method you can get the message. this way you can set different message on different Exception.

spring transaction at service layer

In our application we are applying spring declarative transactions using annotations at service layer.
Here i am not getting any idea on how to handle exceptions properly.
What exactly my requirement is when dao layer throws any hibernate exception we are rolling back the transaction, but in one case i am getting InvalidDataAccessResourceUsageException because there is a unique index violation happening. So what i would like to do here is i want to catch InvalidDataAccessResourceUsageException exception at service class and have to rethrow the application specific exception to controller.
But whats happening here is as we have transaction demarcation at service layer class the session is flushing at service layer(ie when tx commits) after executing the method, as a result i cant catch it into the same method and it is directly propagating to the controller.
Please suggest me work around on this.
also seeking one more clarification, suppose i have a method like below
#Transactional(value="transactionManager",readOnly = false, propagation = Propagation.REQUIRED,rollbackFor = HibernateException.class)
public SomeDTO editObject(SomeDTO someDto, String user) throws EditException {
try{
/*
call to dao.edit();
another call to anotherDao.addEditsTOAnotherTable();
some business logic*/
} catch(HibernateException e){
} catch(InvalidDataAccessResourceUsageException ie){}
}
Can i catch exceptions as above. Note: I am not handling or throwing any exceptions from dao. Also there is no session cache mechanisms like FlushMode.ALWAYS etc at dao layer as it will flush during tx.commit().
By default #Transactional will rollback for any RuntimeException, and since HibernateException is a RuntimeException , roll back will be done automaticaly and you don't have to add rollbackFor = HibernateException.class
You can handle Exception this way:
try{
}catch(InvalidDataAccessResourceUsageException e){
throw new YourApplicationExceptionNotUniqueIndex();
}
and :
YourApplicationExceptionNotUniqueIndex shoud extends RuntimeException that way you wil have a rollback at your sevice layer and you can catch the exception at your Controller .
Better to handle check all the database constraints before editing into database

Resources