Trying to catch exception in order to see request (HttpRequestMethodNotSupportedException) - spring

I am trying to catch an exception in order to evaluate and see which request from the front-end caused it. However, my breakpoint is never triggered:
try{
filterChain.doFilter(request, response);
}catch(Exception e){
if(e instanceof org.springframework.web.HttpRequestMethodNotSupportedException)
throw new HttpRequestMethodNotSupportedException(e.getMessage());
throw new RuntimeException(e);
}
Any reason why my breakpoint inside the catch statement is never executed? The stacktrace denotes this specific method as the source of the exception.

The answer was provided by #M. Deinum :
Because the DispatcherServlet itself is handling the exception. From
the perspective of the filter there is no exception.

Related

is there a way to log exception for all #ExceptionHandler in one place

I have #ControllerAdvice with numerous #ExceptionHandler methods with their own logic. However, I do need a log an original Exception.
Is there a way to do it without adding explicit logging message to each #ExceptionHandler method?
No. You should define other Exception class and do not define it in #ControllerAdvice .
then you can use this Exception and put in log
catch (DefinedException ex) {
log.info("your log here");
throw ex;
}

Get Stack trace from HttpServletRequest in spring boot

I'm currently running a spring boot application.
I am putting this webpage live for multiple people to use. However, this is the first time launching it and I'm unsure if I've worked out all the bugs so I'm trying to find a way to alert myself when something happens.
I have created a custom error controller in Spring. I want this to display a custom error page that just simply tells the user that something is wrong and that we've been made aware of it. This part is working already.
Also with that, I want it to send me an email with the stack trace information. I would love the same page that the default error controller shows, to be sent to me via email. I'm using AWS SES.
Here's my code sample.
#GetMapping("/error")
public String handleError(HttpServletRequest request) {
Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
if (status != null) {
int statusCode = Integer.parseInt(status.toString());
if(statusCode == HttpStatus.NOT_FOUND.value()) {
return "404";
}
}
sesSender.sendErrorEmail("strack trace error");
return "error";
}
I found the following question provided 5 years ago Spring Boot Custom Error Page Stack Trace
I'm hoping that since then, they've allowed this functionality.
If you are using Spring Boot you can use this bean and this method ExceptionUtils.getStackTrace(). You will need to import the commons.lang dependency. The method from ExceptionUtils will get you the stack trace you are looking for to send to your email. But this will only work for Serverside Errors. If you want emails sent with a stack trace for front end errors you will need to create your own Dispatcher Servlet and handle it in the DoService Filter
#Bean
HandlerExceptionResolver errorHandler() {
return (request, response, handler, ex) -> {
Logger logger = LoggerFactory.getLogger(DispatcherServlet.class);
ModelAndView model = new ModelAndView("error/error");
model.addObject("exceptionType", ex);
model.addObject("handlerMethod", handler);
logger.error(ExceptionUtils.getMessage(ex));
System.out.println("" +
"\n" + ExceptionUtils.getStackTrace(ex));
try {
Utility.sendStackTraceToDeveloper(ex, request, javaMailSender);
} catch (MessagingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return model;
};
}

java.lang.IllegalStateException: getWriter() has already been called for this response, Even thought its called only once

I am using spring-boot. I want to send a CSV as the attachment of response for which I am using opencsv to write bean to response. Even though response.getWriter() is called only once, I am getting this exception.
While searching for solution, I came to know that we cannot use response.getWriter() and response.getOutputStream() together. But this is not the case here.
I am only calling getWriter and exactly once.
I also checked if it was due to opencsv library by writing a plain string to it e.g. "name, test". But still the same error. So it's not due to opencsv either.
private Pair<Boolean, String> writeCSVToResponse(List<QuestionDownloadResponse> qdrList, HttpServletResponse response) {
String fileName = new SimpleDateFormat("'CSV'yyyyMMddHHmmss'.csv'").format(new Date());
response.reset();
response.setContentType("application/csv");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + fileName + "\"");
response.setCharacterEncoding("UTF-8");
//Find answer, for now we will return any if exists
try {
Writer writer = response.getWriter();
// Create Mapping Strategy to arrange the
// column name in order
final CustomCSVMappingStrategy<QuestionDownloadResponse> mappingStrategy = new CustomCSVMappingStrategy<>();
mappingStrategy.setType(QuestionDownloadResponse.class);
StatefulBeanToCsv<QuestionDownloadResponse> sbc = new StatefulBeanToCsvBuilder<QuestionDownloadResponse>(writer)
.withSeparator(CSVWriter.DEFAULT_SEPARATOR)
.withMappingStrategy(mappingStrategy)
.build();
sbc.write(qdrList);
} catch (IOException e) {
CMSQuestionServiceImpl.logger.error("Error in CSV IO operations", e);
return Pair.of(false, "Failed to Open file");
} catch (CsvDataTypeMismatchException | CsvRequiredFieldEmptyException e) {
CMSQuestionServiceImpl.logger.error("Error in CSV Write operation", e);
return Pair.of(false,"Failed to write in csv");
}
}
Why is this exception coming, even when response.getWriter is called exactly once. How to solve this issue.
I found the issue. The problem was that I was sending a String (a message) in response in the controller, but in service, I am sending an attachment. So getWriter() was being called first time in service by me, and the second time by spring to write the response message of type String. Solution: I set the return type of method in the controller to void ex::
#GetMapping(value = "/downloadCSV")
public void downloadCSV(#RequestBody(required = false) List<Integer> items, HttpServletResponse response){
The only problem is if something goes wrong in service, you cannot send an error message and there are other alternatives to overcome it.
I had the same error: in spring-boot
This error occures when we use a RestExceptionHandler which tries to modify the response by using response.getOutputStream(), remember, the response.getWriter() is already called (even once in our code).
So when we call response.getWriter() , and we have some exception, the RestExceptionHandler executes the response.getOutputStream() which causes java.lang.IllegalStateException: getWriter() has already been called for this response.
What I suggest to do is to add try-catch to the response.getWriter() and when you catch any exception we have to reset the response by using response.reset() like that:
try {
writer.write(beans);
} catch (Exception e) {
response.reset();
throw e;
}
After throwing the exception the RestExceptionHandler will do it's job.

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.

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