I have implemented controlleradvice in my spring mvc project. Am able to see proper response but unable to find my stack trace.
Here is my code, can any one tell me what should i do to get stack trace.....
#ExceptionHandler(Exception.class)
public ResponseEntity<?> handleException(final Exception exception) {
err.setErrorMessage("server_error");
return new ResponseEntity<ErrResp>(err,
HttpStatus.OK);
}
Try:
exception.getStackTrace();
You can assign this to a variable if needed or use the below to see stacktrace in console:
exception.printStackTrace();
Related
I am refactoring an ASP.NET WEB API solution that uses Odata.
When dealing with errors I would like to provide a custom error payload which is defined in my CustomException class.
The issue is that when I make a bad request the generated response is the ODataException error payload which contains some confidential information that I don't want exposed and also the stack trace.
I need to modify this Odata payload and replace it with my own.
So far what I've tried is to use Exception Filters applied on Controller level and also tried to register an Exception Handler on global level. None of these worked.
Any help would be greatly appreciated.
I was able to resolve it with Exception Filter, I was using the wrong method before:
public class CustomExceptionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
ErrorContentResponse error = new ErrorContentResponse();
var response = new HttpResponseMessage(actionExecutedContext.Response.StatusCode)
{
Content = new ObjectContent<ErrorContentResponse>(error, new JsonMediaTypeFormatter())
};
actionExecutedContext.Response = response;
}
}
When I use #ExceptionHandler within Controller, it's not working as expected.
Here is my code:
#Controller
public class PageController {
#RequestMapping("/page")
public ModelAndView index(ModelAndView modelAndView){
String mess = null;
mess.split(",");
modelAndView.setViewName("index");
return modelAndView;
}
#ExceptionHandler({Exception.class})
#ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "Bad Request")
public ModelAndView handleException(Exception ex, HttpServletRequest request, HttpServletResponse response){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("message", ex.getMessage());
modelAndView.addObject("url", request.getRequestURL());
modelAndView.addObject("code", response.getStatus());
modelAndView.setViewName("exception");
return modelAndView;
}
}
After the application starts with debug mode, I visit http://localhost:8080/page, and handleException is running, but the view is below other than the expected excepction view. Why?
The problem is with the #ResponseStatus annotation. Have a look at the following article: http://blog.sizovs.net/spring-rest-exception-handler/. In the mid of this article the author says following:
Warning: when using this annotation on an exception class, or when setting the reason attribute of this annotation, the HttpServletResponse.sendError method will be used.
With HttpServletResponse.sendError, the response is considered complete and should not be written to any further. Furthermore, the Servlet container will typically write an HTML error page therefore making the use of a reason unsuitable for REST APIs. For such cases it is preferable to use a org.springframework.http.ResponseEntity as a return type and avoid the use of #ResponseStatus altogether.
According to a Spring article: https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc, Spring MVC chains the following three resolvers in the order below:
ExceptionHandlerExceptionResolver matches uncaught exceptions against for suitable #ExceptionHandler methods on both the handler (controller) and on any controller-advices.
ResponseStatusExceptionResolver looks for uncaught exceptions annotated by #ResponseStatus (as described in Section 1)
DefaultHandlerExceptionResolver converts standard Spring exceptions and converts them
to HTTP Status Codes (I have not mentioned this above as it is internal to Spring MVC).
So the ResponseStatusExceptionResolver is triggered after the ExceptionHanlderExceptionResolver and uses the default and will display Spring's error page.
For a quick fix try to remove #ResponseStatus and you should see your custom error page in your browser.
I am using spring MVC 3.2.4. I have a business exception thrown from business tier and want to display an error message in the same view instead of forwarding to an error page once it is caught. I know I could put try-catch in each handler method and then return to the same view. But I really want a common place to achieve this in Spring MVC. I tried #ExceptionHandler and #ControllerAdvice, It seems not working.
Here is what I want to do,
#SomeExceptionHandlerAnnation(BusinessException.class)??
public String handleBusinessException(Model model,
BusinessException ex)
{
//convertExceptionToMessage();
//add message to model
return userView;//stay in the same view
}
The problem is how to get model of the same view. It seems Spring MVC exception handler doesn't support it. Any idea? Thanks in advance.
Try this:
#ControllerAdvice
public class ExceptionController {
#ExceptionHandler(Exception.class)
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ModelAndView handleAllExceptions(Exception e) {
--do something here
return new ModelAndView();
}
}
I want to display a simple graph in my webapplication so I've decided to integrate JFreeChart into Spring MVC.
I've found the following solutions:
#RequestMapping("/seeGraph")
public String drawChart(HttpServletResponse response) {
response.setContentType("image/png");
XYDataset pds = createDataset();
JFreeChart chart = createChart(pds);
try {
ChartUtilities.writeChartAsPNG(response.getOutputStream(), chart, 600, 400);
response.getOutputStream().close();
} catch (Exception e) {
}
return "graph";
}
I guess this is not good. Although it does display the graph it also throws an exception:
getOutputStream() has already been called for this response] with root cause
java.lang.IllegalStateException: getOutputStream() has already been called for this response.
I did some research and found that an application can either call getOutputStream or getWriter on any given response, it's not allowed to do both.
But because of ChartUtilities.writeChartAsPNG() I have to call getOutputstream, and Spring will call getWriter().
Is there any clever solution to avoid this exception?
Currently you ask Spring to render a view called graph after execution of your controller method (by returning a view name from the method). However, if you write data to the output inside a controller you should not proceed to view rendering phase.
So, you need to use a void method instead:
#RequestMapping("/seeGraph")
public void drawChart(HttpServletResponse response) { ... }
I'm migrating some servlets over to the Spring framework, using Spring MVC. Currently in each servlet we authenticate the user and if the authentication fails we do this:
if (authfailed)
{
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
"You are not authorized.");
return;
}
On the front end is a YUI-based application, and when an error status is returned the "failure" callback displays a dialog with the error message given above.
I know in my controller I can get the response object and call sendError, but is that the best way to handle this? sendError also throws an IOException so I'd have to catch that - a bit of annoying code to insert in every method of every controller.
I have the same problem handling exceptions - the servlets have try-catch blocks that call sendError in the catch method. I know I can mark my exception handlers with
#ExceptionHandler
#ResponseStatus(value = HttpStatus.NOT_FOUND)
but doesn't the exception handling class need to be in each controller class?
Finally, if the exception happens in a service called from a controller, does the exception bubble up to the controller or should I handle the exception in the service (thus pushing these exception handling issues into the service layer)?
This seems more difficult than it should be, but as with many things in Spring it's likely I don't understand what's going on. All I want to do is to send an error status and message back in the response!
Thanks,
Paul
It looks like you have the most of the answers in your question itself :)
To reiterate,
Have the controller like this
#RequestMapping("/test")
public String verifyAuth(HttpServletRequest request) throws NotFoundException {
String id = request.getParameter("id");
if (id == null)
throw new NotFoundException("Id not found in the request");
return "success";
}
Declare the exception class in NotFoundException.java,
#ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Id Not Found")
public class NotFoundException extends Exception {
public NotFoundException(String msg) {
super(msg);
}
}
This exception class need not be every controller class. Declare it as public class and import it in every required controller.
This is one way of doing it. If you like the non-spring style, declare HttpServletResponse in every controller arguments and do
#RequestMapping("/test")
public String verifyAuth(HttpServletRequest request, HttpServletResponse response) {
...
try {
response.sendError(..)
catch(..) {}
}
Or you can use views to show error message,
#RequestMapping("/test")
public String verifyAuth(HttpServletRequest request, Map<String, Object> map){
String id = request.getParameter("id");
if (id == null) {
map.put("status", HttpStatus.NOTFOUND);
map.put("reason", "Id Not Found");
return "error"
}
return "success";
}
Make sure your viewResolver is configured correctly and in the error.jsp to get the error string, you could say.
<body>
${status} ${reason}
</body>
Define error.jsp with nice css for all kind of errors you would expect.
These are not the only ways. With spring you have freedom to do anything. I have seen few ppl rendering json object for error message.
To answer your another question of if the error happens in the service called by the controller is depend on your scenario. For example you are trying to read the user store, if the user store not available error happens, I would handle there itself to read from another replica user store if one available and If I found user does not exist I would leave the exception to the controller to throw.