Should Service layer throw an exception? - java

I don't like throwing exceptions for some reason, maybe because of the performance hit I don't know, wondering if I should re-think this issue.
Should my service layer (uses Dao's + business logic etc.) be throwing exceptions?
public ModelAndView createProduct(#Valid ProductForm productForm, ..) {
ModelAndView mav = new ModelAndView(...);
if(bindingResult.hasErrors()) {
return mav;
}
// throw exception if user doesn't have permissions??
productService.create(product, userPermissions);
}
So my options in the create method of the ProductService:
if the user doesn't have permissions, throw an exception
return some sort of a Response object that will have the new product Id if it was a success, along with a success/failure flag and a error collection.
Things to keep in mind:
I may re-use this service layer in a non-web app, also in a restful web service.
What is considered best practice?

Depends of what you mean by service and exception, but in the context you've got I'll assume a java exception from a HTTP endpoint.
The answer is no. Services should expose errors in a general way. In the case of Restful service, errors should be propagated as HTTP status with error codes. The service shouldn't leak implementation details to consumers. It's a natural boundary.
The Consumer should handle those error situations and decide the most appropriate what to communicate that. It may well choose to generate an exception. But these exceptions are disjoint from the original issue/eception that caused the service to return an error code.
Going further I would say #yahir is right in what he says also. HTTP service would expose HTTP errors, and it may well just be using another service underneath that returns another kind of errors, but it's job will be to handle or map them appropriately.

Ask yourself what other options do you have, sometimes exceptions are necessary. The only other thing you could do is return a status of failure or success and handle appropriately.

I'd say the service layer should behave just like any other method exposed to client code. After all, that's exactly what it is.
Clients that will use it through RPC, will expect exactly this behavior.
Other cilents, such as REST, should anyway access the services layer through some other wrapping layer (e.g. Controller layer). One of this wrapping layer duties is transforming the response to be client-consumable.

Related

Throwing the status exception

I have a core module that has such relationships
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-mail')
in service in method I would like to throw an exception (or otherwise) from the status code (for example, NOT FOUND 404) in case the user is not found.
getById(Long id) {
//if the user with specified id does not exist
//for example, cast an exception throw new UserNotFoundException(new List<FieldError>); with a list of error fields
}
the problem is that this module has no dependency
compile('org.springframework.boot:spring-boot-starter-web')
and cannot use objects such as ResponseEntity or HttpStatus.
I want to achieve a result such as that here https://github.com/JonkiPro/REST-Web-Services/blob/master/src/main/java/com/service/app/rest/controller/advice/ErrorFieldsExceptionHandler.java, but without org.springframework.web.
I could be advised on how I can throw an exception with the status and error list object as response?
Let's exercise the good old Single Responsibility Principle.
The Service layer is not concerned about HTTP STATUS. Throwing some sort of HttpStatus404Exception from the Service layer is not a good choice. How about if someone wants to use the Service layer in a batch processor which connects directly to the database? In this case the HttpStatus404Exception is totally out of place.
Throw a UserNotFoundException (which could extend a NotFoundException) and let the Controller layer (in your case a WebController layer) handle the exceptions gracefully.

How do I implement site-wide exception handling in a spring MVC architecture?

Note: Skip to the two updates at the bottom to find the answer.
I have a Spring (3) MVC web application running on Tomcat. This web application serves as a UI for a remote WSDL service layer. I have written a custom AuthenticationProvider to authenticate to this remote service. That works fine. My issue is this:
Each controller method, more or less, results in a remote call to this remote WSDL. My plan was to not have Tomcat or Spring expire sessions, but wait until the remote server tells me that the session has expired on that end and then re-route the user to the login page, telling them that their session has expired.
BaseController, from which all other Controllers extend, has this method:
protected void addBindingErrors(HttpSession session, MTAResponse response, BindingResult binding, boolean allowDefault) {
switch (response.getResponseCode()) {
case SESSION_EXPIRED:
UserInfo nfo = (UserInfo)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
SecurityContext context = SecurityContextHolder.getContext();
System.out.println("token in handle session expired: " + nfo.getMtaCoreSessionId());
if(session != null){
System.out.println("invalidating session");
session.invalidate();
//1. throw new SessionAuthenticationException("session expiredd");
ModelAndView mav = new ModelAndView("error");
throw new ModelAndViewDefiningException(mav);
//3. something else?
}
context.setAuthentication(null);
break;
case INVALID_PARAMETER_VALUE:
binding.addError(...);
break;
case ACCESS_DENIED:
binding.addError(...);
break;
default:
if(allowDefault){
binding.addError(...);
break;
}
}
}
I have found a couple solutions, but I'm new to Spring so I don't know if they're the "right" ones or if there are issues lurking in them.
(a bit of a cheat) In the BaseController.addBindingError() method, if a remote session expired code is received, throw a SessionAuthenticationException
Pros: this works, automagically re-routes the user to login page (I think because I have authentication-failure-url set?)
Cons: I’d have to change the signature of addBindingError to throw this kind of exception.
Con: I’d also have to change the signature of every controller method to throw this kind of exception, since they all make remote service calls to WSDL.
Con: the user doesn’t know why they’re back at the login page and I’m not sure there is a way to let them know
In the BaseController.addBindingError() method, if a remote session expired code is received, throw a ModelAndViewDefiningException
Pros: this works, automagically re-routes the user to appropriate error page, which can contain a link to the login page
Pro: we can explain to the user on this page how they got here.
Cons: I’d have to change the signature of addBindingError to throw this kind of exception.
Con: I’d also have to change the signature of every controller method to throw this kind of exception, since they all make remote service calls to remote WSDL
In the BaseController.addBindingError() method, if a remote session expired code is received, throw a MyCustomRemoteSessionExpiredException and then catch it in a SimpleMappingExceptionResolver
Pros: this works, automagically re-routes the user to appropriate error page, which can contain a link to the login page
Pro: we can explain to the user on this page how they got here.
Cons: I’d have to change the signature of addBindingError to throw this kind of exception.
Con: I’d also have to change the signature of every controller method to throw this kind of exception, since they all make remote service calls to remote WSDL
Numbers 2 and #3 have the same pros/cons. #3 seems like it might be a more "correct" solution. Does anyone have any feedback, suggestions, or alternatives?
Update 5/30/2013:
I think I may have found what I'm looking for and I think it will require me to upgrade to the latest spring 3.2. #ControllerAdvice a la this article here:
http://www.javacodegeeks.com/2013/03/exception-handling-with-the-spring-3-2-controlleradvice-annotation.html
From BaseController.addBindingError, I'll throw MyCustomException (which extends RuntimeException so that the method signatures will not need to declare a throws statement) and handle that in a new #ControllerAdvice class (which will contain an #ExceptionHandler method).
Can anyone confirm or deny this approach?
Any better suggestions?
Thanks!
Update 12/3/2013 **
This question would have been much better titled like so: "How do I implement site-wide exception handling in a spring MVC architecture?". So, I'm changing the title (the former title was based on my misunderstanding that the interaction with the remote SOAP server had anything to do with my real question). I implemented the solution discussed in May and it has been working very well. I have even extended the #ControllerAdvice class to handle other RuntimeExceptions.

The best way of exception handling in an app with web services

I have an application which consists of SOAP and REST web services and a simple HTTP access. All of them convert incoming requests and send them to a handler. The most painful thing is exception handling. In order to return the right response, I have to wrap every method with try-catch block and create a response there.
I thought that I could create a filter which could do it. But how can the filter recognise the source of it (soap, rest frontend) so I knew that I should return a SOAP or other response?
It depends on the WS framework you use. All I know have some sort of interceptors/aspects that you can inject and handle exceptions in one place. For instance in apache-cxf there is even a special outbound error chain where you can plug your own interceptors.
Obviously try-catch in every method is a bad idea.
In layer of below Web-Service Layer, you have to create your custom Exception and in Web-Service layer you have to use try-catch approach for achieve occurred exception and in catch block log and convert it to your custom web service layer exception. I show this approach in following:
#WebService
public class EmployeeWS
{
#WebMethod
public void add(Employee em) throws CustomWebServiceException
{
try
{
// call facade layer method
}
catch(Exception e)
{
logger.error(e.getMessage());
throw new CustomWebServiceException(e);
}
}
}
Alternative using try catch in any Web-Method,you can use AOP approch(for sample Spring AOP) or interceptor approach in Web-Service frameworks(for sample SOAPHandler<T> in JAX-WS).
Note: In JAX-WS standard, you can't throw a RuntimeException because Exception must specify in final WSDL and if you throw a RuntimeException your web service client don't achieve your CustomException, in another your Web-Methodneed to throws in itself signature.
You can see selected Web-Service faramework documents for more information.
It sounds that you are not using any framework because that was typical frameworks provide. For example Spring allows you to decouple the code from exception handling and define your custom exception handlers.
In your case you generally have 2 solutions.
(1) You can use Decorator pattern: wrap each service with decorator where each method is implemented as
try {
call real method
} catch() {
send error to client
}
Since it is very verbose you can save time using Dynamic proxy (feature that was introduced in java 5). So, you can dynamically wrap each service (if your services have defined interface).
(2) You can solve it using servlet API's error page:
javax.servlet.ServletException
/servlet/ErrorDisplay
for more details see http://java.sun.com/developer/technicalArticles/Servlets/servletapi2.3/
You can customize your class!! Do it!
Take easy on diagnostic errors, like insert a protocol number, message Log, message client, etc...
http://java.globinch.com/enterprise-java/web-services/jax-ws/jax-ws-exceptions-faults-annotation-exception-and-fault-handling-examples/#Pre-Requisites

What's an appropriate way of appending metadata to objects before returning via a RESTful WS?

I have a RESTful web service that responds to /user/{userId} with a marshalled XML representation of a User domain object (using JAXB). What's an appropriate way of communicating back to the client additional details about their request, particularly if it doesn't return the information they're expecting? In a non-distributed Java application, you might have a catch block that deals with data access, or security exceptions. In the event that /user/{userId} doesn't return anything (e.g. the web services persistence mechanism isn't working, there is a security restriction, etc...) how do I include meaningful information in the response to the client?
I don't think DTOs are what I need because I'm not looking for different representations of a domain object. Rather, I'm looking for information about what happened during the request that may have prevented it from returning the information the client expected. Would it be appropriate to enclose the domain object within some kind of ResponseObject that holds the relevant metadata? The downside to this approach is that I'd rather not have my service layer interfaces all have ResponseObject as their return type because I may very well provide a non-RESTful implementation that doesn't have the same metadata requirements.
What's an appropriate way of communicating back to the client additional details about their request, particularly if it doesn't return the information they're expecting.
In the event that /user/{userId} doesn't return anything (e.g. the web services persistence mechanism isn't working, there is a security restriction, etc...) how do I include meaningful information in the response to the client?
This is what the HTTP Status Code is used for in a RESTful service.
To indicate that a requested userId doesn't correspond to an actual user, you can return a 404 Not Found.
To indicate an internal error within your application (such as not being able to connect to the database), you can return 500 Internal Server Error.
The option you are describing - wrapping your returns in a ResponseObject which then includes the true "response status" - sounds an awful lot like SOAP.
The beauty of REST, or at least what people claim, is that you can use the already-existing HTTP response status code to model almost all statuses of your actual response.
If it's really error situation (security problems, no DB connection or even user with provided ID not found), then just throw an Exception. Client receives fault and can behave according to information contained in it.
Which implementation do you use? In Apache CXF, for example, you can define exception handler and render XML for exception yourself, and there you are free to include any meta-info you like.
I would capture the information using exceptions, then map those exceptions to an HTTP response with the appropriate status code. You can achieve this by creating an implementation of ExceptionMapper if you're using JAX-RS, or you can subclass StatusService if you're using Restlet.
http://wikis.sun.com/display/Jersey/Overview+of+JAX-RS+1.0+Features
http://wiki.restlet.org/docs_2.0/13-restlet/27-restlet/331-restlet/202-restlet.html

Passing errors back to the view from the service layer

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.

Categories

Resources