I am working on a legacy project, converting it to annotation based MVC. I am noticing alot of times in the onsubmit method where the following pattern is followed:
public ModelAndView onSubmit(Command command) {
try {
service.doSomeBusinessLogic(command);
}
catch (ServiceException) {
//return one type of model and view here
}
//return another type of model and view here
}
Intuitively to me, this exception handling placed here is wrong, but I am unsure as to what alternative solutions spring gives me? Any ideas or is this not an anti-pattern like I am thinking?
The best practice for unrecoverable exceptions is to show an error page. Configure that in web.xml. Spring's default exception handler will take care of setting the response status to 500, so a 500 error page will be displayed.
If the exception is recoverable, then the above approach is fine - there is a specific action to take, and it goes in the catch clause.
But you should decide which exceptions are recoverable and which should just lead to an error page.
Related
Is it fine to throw an exception on the server side when the requested resource was not found?
the client receives a 404 not found. My concern is whether it is fine/wrong to throw an exception on the server side when this happens.
It's hard to assume what your are trying to do with the level of details you added to your question.
However, if you handle the exceptions properly, there may be nothing wrong with that approach. Have a look at the approaches used by some frameworks:
JAX-RS
You can throw a WebApplicationException, that will be mapped a response. You can define your own subclasses of WebApplicationException or use the existing ones. The NotFoundException, for example, will be mapped to a response with the 404 status code. For more details on the existing exceptions, refer to this answer.
You also can create your own ExceptionMapper to map any exception to a desired response.
Spring MVC
You can map exceptions to responses by annotating an exception class with #ResponseStatus.
It also gives you the possibility to implement a HandlerExceptionResolver or extend one of the existing implementations, such as the AbstractHandlerExceptionResolver.
Another approach would be using a ResponseEntityExceptionHandler annotated with #ControllerAdvice and define the handled exceptions by annotating the implemented method with #ExceptionHandler
Basically it is not ideal to throw reserved status codes of exception. You should handle this exceptions internally and prepare your own code with meaning full message that client should know the actual problem.
I would say add a filter to capture 404 and add custom information about the 404 details.
In case of pure REST implementation, any resource-id missing and malformed URL will return 404.
As far as REST contract, both cases are correct to have 404 response. But more details on what type of resource is missing will help the client side consuming it to take appropriate actions.
Related discussion:
return-404-when-a-rest-resource-is-not-found
From perspective of semantics: Exception should be thrown if condition is such that condition is unrecoverable and devs must be notified about it.
Server cannot resolve auth request in the beginning of a session - this is serious enough situation and exception is appropriate.
User didn't fill out obligatory field and tried sending a form. This problem can be fixed and an exception would be a bad design.
I am using Play!Framework 1.2.5. I want to handle all errors in play framework in a customized way. For example if there is route error I would like to display an appropriate error message instead of showing the whole route file. Likewise for other errors, I would like to display my own error page. How to do this?
We needed a bit more control than what #iwawiwi mentioned to figure out what database constraint message was thrown by the database. That was solved by using a method with a #Catch annotation like this in a Controller class:
#Catch(value=PersistenceException.class)
public static void handleException(PersistenceException exception) {
..
}
I hadn't heard of that annotation before and this has worked pretty good in my situation.
For missing routes we've added a bit in this Controller as well:
#Catch(value=ActionNotFoundException.class)
public static void catchRouteNotFound(ActionNotFoundException exception) {
String referer = session.get("referer");
Logger.error("ActionNotFoundException, referer: %s", referer);
Logger.error("Exception: %s", exception);
}
This way we can find out about missing routes / wrong links in the application.
You can define your own error page by creating new sub-package named errors on views package. In this sub-package, you can create template file for your customized error page using the error code name such as:
404.html for Not Found Error page
403.html for Forbidden Error page
500.html for Internal Server Error page
etc...
Don't worry for the default route not found error page, it's only shown on development mode for helping development phase. While in production mode, this error page (the default framework error page) will not be displayed.
-- UPDATE
This #Catch annotation maybe useful for handling other type of exception. It act as interceptor for action in your controller, and will handle exception if exception occur while doing some action. Note that this annotation only works in Controller class.
Please check the documentation here for further read.
I am writing a web application using Spring 3 framework. Consider a situation where I have N number of controllers. Each controller delegates the request to exposed services and gets the response and return to users.
I would like to know if there is a better to way catch unexpected runtime exceptions thrown out of the controller code. I do not want to write something like the following for each of my controller methods. Or is it the only way?
try {
//call the service
} catch(ServiceException serviceEx) {
//do process for know exception
} catch(Exception ex) {
//return generic error message.
}
I know that we can use Spring Exception resolver. But I do not want to show different error page when unexpected error happens. I want to show some generic error message on UI as part of my widget?
Edit:
I also don't want my users to see the exception stacktrace when trying to perform some operations.
Sundar
I think catching RuntimeExceptions is bad practice. Originally RuntimeExceptions where thought as inicators to programming errors (e.g. NullPointerException to indicate that a null check is missing). Whereas checked exceptions where meant to indicate errors that the program can recover from (e.g. FileNotFoundException).
The problem today is that many frameworks use RuntimeExceptions where checked exceptions should be used. Therefore it is difficult to differentiate between cases where a program can handle the exception and where a programming error (bug) is encountered.
This is my personal view of this things for enterprise development. I know that most people mandate for dropping checked exceptions and handle everything as unchecked exception (as in Scala).
In my opinion you should only catch exceptions in your code from which you can recover. All other exceptions (checked or unchecked) should be caught by one über exceptionhandler which will log the exception and show the user some generic error page (possibly with an id that you can use to find what the exception was).
For example, in struts2 you would that this like so:
<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="unrecoverableException"/>
</global-exception-mappings>
I never use spring mvc but this article seems to give you the options for an über exceptionhandler:
http://doanduyhai.wordpress.com/2012/05/06/spring-mvc-part-v-exception-handling/
You can catch runtime unexpected exceptions using this approach.
try {
...
} catch ( Exception e ) {
throw new RuntimeException("msg",e);
}
I think RuntimeException is designed for situations like breach of contract or some unrecoverable fault. Most of the time, you should just let the container or some outer infrastructure to handle it for you. Or you have to write a lot of redundant code to deal with them and it's kind of against the design philosophy of Spring.
In your case, may be you can leverage some filter or interceptor to catch those unexpected RuntimeException if you really need to transfer them to some other generic messages.
My Spring MVC app is full of methods that look like this:
#RequestMapping(value = "/foo", method = RequestMethod.GET)
public final void foo(HttpServletRequest request, ModelMap modelMap){
try{
this.fooService.foo();
}
catch (Exception e){
log.warn(e.getMessage(), e);
}
}
Exceptions are caught and logged but not handled otherwise.
The fooService called above does the same thing, never throwing exceptions up to the controller but catching and logging them. So, actually this controller exception code will never get invoked.
What's the best and simplest approach to implement proper exception handling in my app?
Get rid of all catch statements if all they do is logging carelessly. catch is meant to handle the error, not hide it.
Once all these catches are removed, install one global exception resolver in Spring MVC (1, 2, 3, ...) Simply implement this trivial interface:
public interface HandlerExceptionResolver {
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}
In your exception resolver you might simply log the exception once and let it go as unprocessed (return null), so that error mappings in web.xml will forward request to proper error page. Or you can handle exception yourself and render some error page. AFAIK in simplest case there is no need for register exception resolver, just define it as a Spring bean/annotate with #Service.
Remember, catch the exception only when you know what to do with. Logging is only for troubleshooting, it doesn't handle anything.
BTW this:
log.warn(e.getMessage(), e);
is not only a very poor exception handling, but it is also slightly incorrect. If your exception does not have a message, you will see mysterious null just before the stack trace. If it does, the message will appear twice (tested with Logback):
22:51:23.985 WARN [main][Foo] OMG! - this is the exception message
java.lang.IllegalStateException: OMG! - this is the exception message
at Foo.bar(Foo.java:20) ~[test-classes/:na]
...sometimes undesirable, especially when exception message is very long.
UPDATE: When writing your own exception logger consider implementing both org.springframework.web.servlet.HandlerExceptionResolver and org.springframework.core.Ordered. The getOrder() should return something small (like 0) so that your handler takes precedence over built-in handlers.
It just happened to me that org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver running prior to my handler returned HTTP 500 without logging the exception.
Edit: I have looked into Spring 3's #ExceptionHandler annotation and combining this with Option 1 below looks to be a pretty clean solution.
See http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-exceptionhandlers
I also found this to be a good read: http://blog.decaresystems.ie/index.php/2006/04/07/difficult-choices-in-handling-exceptions-in-enterprise-java-applications/
I have been developing using the Spring MVC framework for some time now however I am struggling to come up with a 'nice' way to pass errors that are raised in the service layer back to the JSP.
Basically, I don't believe that business logic (beyond "this field is mandatory") should be in the Validators, especially any logic that requires access to the DB. So, what I have been doing is placing further, more complicated validation and business logic in the service layer.
For example, lets say I have a page that allows a user to buy a Book. They click "Purchase" on the JSP and the controller calls the service to make it all happen... Now, what happens if the service sees that they have insufficient funds - how do I get this message back to the JSP so a nice little "Insufficient funds" message can be displayed to the user? I have considered two ways and I'm not sure which is correct...
Option 1: Exceptions
The first way I thought was to raise an exception in the service layer, trap it in the controller and add a message to the BindingResult.
Service:
public void pay(Book book) throws InsufficientFundsException {
// Some logic goes here, which ends up throwing the above exception
}
Controller:
public ModelAndView(#ModelAttribute("book") Book book, BindingResult errors) {
try {
pay(book);
} catch (InsufficientFundsException ex) {
errors.reject("insufficient.funds");
}
return new ModelAndView(blahblahblah);
}
Option 2: Pass BindingResult to Service layer
The second way was to pass the BindingResult object to the service layer and raise further errors against it.
Service:
public void pay(Book book, BindingResult errors) {
// User has insufficient funds, so...
errors.reject("insufficient.funds);
}
I can see problems with both of these ways. Option 1 feels awkward because not only do I have to catch the exception, I then have to add the error to the binding result so it feels like I'm doing the same thing twice. And Option 2 seems to bind the service layer too tightly to the controller.
Finally, I realise there is the SimpleMappingExceptionResolver that could be used in conjunction with Option 1, but I'm not sure how appropriate it is (perhaps I have not seen a proper example?). In the above example, lets just say for argument's sake that I'd like the user returned to the original form with a red error above the form, not redirected to an entirely different page. The SimpleMappingExceptionResolver seems to me to be useful when you want to redirect a user to a standard error page when a certain exception is raised (which is not quite what I want to know how to do).
Java uses exceptions to naturally handle this kind of thing. In the end it generally simplifies your logic and reduces the chance of making a mistake by forgetting to check that something had an error. You are also able to move error logic out of the main flow of the code.
I don't see why the case you present is different from any other case where I would use exception handling to deal with errors.