Is it good practice to throw exception from DAO layer to controller? - java

I am writing one REST api. There might be two exceptions in my DAO layer namely Exception_X and Exception_Y. If I encountered a exception Exception_X in DAO layer, my controller should return status code 200, if Exception_Y then 401 and if all goes well controller should return 201.
Now what was I thinking that I will throw encountered exception as it is from DAO layer to controller via service layer and in catch block of controller I will return response.
Is it acceptable or there is some other standard way?

Yes that is quite an acceptable way. However, rather than using try-catch, I would suggest to implement Exception Handlers for your REST Controllers. That way, you won't have to clutter your REST methods.
Also, it would be better to create a model object in REST layer for Error messages - ErrorResponse, with appropriate information:
class ErrorResponse {
int statusCode;
String errorMessage;
}
And return it's object from the exception handlers. BTW, you can also map your exception class directly to a response using #ResponseStatus annotation:
#ResponseStatus(value=401, reason="message")
class Exception_Y extends RuntimeException {
}
Then you don't have to write exception handler for that exception.

My suggestion would be wrap any unchecked exceptions with a service layer for loose coupling, and clean abstraction. Keep your controller free from conditions and let Service layer take care of this pain.
Keeping security concern in mind if you exposing it externally wrap your exception with service oriented exception it also helps to achieve generic layer specific exceptions say PersistentException, ServiceException etc. keeping good degree of decoupling in mind.
For handling exception globally you can use spring inbuild ControllerAdvice annotation with JsonExceptionModel for formatted error response.
#ControllerAdvice
public class GlobalExceptionHandler {
#ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler(SQLException.class)
public Map<String, Object> handleSQLException(HttpServletRequest request, Exception ex) {
//json response here
}
}
public class JsonExceptionModel {
private int code;
private String type;
private String url;
private String message;
private String moreInfo;
// getters/setters here
}

I suggest you to go with Exception Resolver which is providing by spring.
Spring Framework provides HandlerExceptionResolver interface that we can implement to create global exception handler. We can also override it to create our own global handler with our application specific changes, such as logging of exception messages.
Here is the sample implementation of HandlerExceptionResolver,which will fullfill your need
public class RestResponseStatusExceptionResolver extends HandlerExceptionResolver {
#Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
if (ex instanceof InvalidInputException) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return handleException(ex);
} else if (ex instanceof ResourceNotFoundException) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return handleException(ex);
}
//Adding error details to modelView object
modelAndView.addObject("errors", ErrorDetails);
// Custom error message details
public class ErrorDetails {
private String code;
private List<String> data;
}

Related

Spring Boot intercept all exception handlers

I am trying to perform some common logic that applies to all my #ExceptionHandlers in code. I know I can write a HandlerInterceptor to intercept happy paths. But I would like to hook into the exception handling lifecycle so that I can execute some common logic such as logging, before the error response is rendered.
Is there anyway to do this in Spring Boot / Spring MVC? I would like to avoid having to write a servlet filter for this purpose if possible.
I have a solution. It's about using HandlerInterceptor.afterCompletion method. However, there is a line in the documentation of this method that states that:
Note: Will only be called if this interceptor's preHandle method has successfully completed and returned true!
So the trick is to also implement the preHandle and make it return true.
Now my interceptor looks like this:
#Component
public class MyInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// perform common logic here
}
}
One thing to be aware of though is that if you have a chain of interceptors and an interceptor before this one throws an exception, this interceptor won't get a chance to execute. So if we reorder the interceptor chain so that MyInterceptor is right at the top, it will intercept all requests.
There is a way with #RestControllerAdvice and #ExceptionHandler, an example:
#RestControllerAdvice
public class GlobalControllerExceptionHandler {
#ExceptionHandler(value = {DeniedPermissionException.class})
#ResponseStatus(HttpStatus.FORBIDDEN)
public String deniedPermissionException(DeniedPermissionException ex) {
return "Denied permission";
}
#ExceptionHandler(value = {ConstraintViolationException.class})
#ResponseStatus(HttpStatus.BAD_REQUEST)
public String constraintViolationException(ConstraintViolationException ex) {
return "Bad request";
}
#ExceptionHandler(value = {Exception.class})
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String internalServerError(Exception ex) {
return "Internal error";
}
}
*DeniedPermissionException is a custom exception.
This is not really a Spring Boot concern. This is really a Spring MVC concern. One good approach is to implement the HandlerExceptionResolver or extend from something like ExceptionHandlerExceptionResolver. The implementation needs to be given a higher precedence than the default exception resolvers (which all run with the lowest precedence). And if you want to retain the existing behavior of the default resolvers but only trap the exception for something cross-cutting like logging or tracking, then just return null for the ModelAndView and Spring will ensure other default resolvers are invoked as before.

Handling Exception in Spring boot Application with Hibernate

I am building a REST API with Spring boot and DAO layer is implemented in Hibernate.I need to understand the correct way of throwing and handling Exception in the Application.Currently I am doing it in this way
#Repository
public class UserDaoImpl
{
public getAllUsers() throws Exception
{
//get All Users from DB
}
}
#Service
public class UserServiceImpl
{
public getAllUsers throws MyCustomException
{ try{
userDaoImpl.getAllUsers();
}
catch(Exception e)
{
throw MyCustomException();
}
}
}
and In Exception Mapper
#ControllerAdvice
public class ApplicationExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler({MyCustomException.class})
#ResponseBody
public ResponseEntity<?> handleCustomException(Exception e) {
log.error("", e);
Map<String, String> error = new HashMap<String, String>();
error.put("message", e.getMessage());
return new ResponseEntity<>(error, HttpStatus.NOT_ACCEPTABLE, MessageResource.getLogMessage("BAD_REQUEST_EXCEPTION"));
}
}
public class MyCustomException extends RuntimeException
{
///// ....
}
So I have added throws clause (throws Exception) in DAO layer and catch at service layer and wrap it in Custom Exception(unchecked exception) and do not propogate the exception at controller layer.
Is this correct ? or there is some better way?
I'd recommend you to have general #ExceptionHandler({Exception.class}) for all cases that you don't want to handle specifically.
Also it's okay to create separate exception classes for situations that require custom handling.
It depends on what do you want to achieve.
About your case. Exception in DAO layer does not necessary mean that request was wrong or did not provide correct parameters. It could be mapping problems, DB access problems and etc. So I would not wrap it to my custom exception, or at lest wrap in to general DataAccessException, make good logging around that and return some general error code to the client.

is it possible to handle exception from a single place

I have dao, service and action classes in my spring mvc application.
I am throwing Exception in Dao and Service classes. Now in Action, normally I have to write try catch block and in case exception occurs in dao and service, it will be thrown from there and it will go in catch block in action.
I have a error jsp which will be displayed.
Problem is I need to write same catch block in all action methods.
Is it possible to throw it again in action methods too and handle it from a single point rather than writing same code everywhere.
Please suggest.
You can also have a look at Spring Integration. It provides the use of gateways, filters and channels. Each can have a Request, Response and Error channel assigned. Or there is even a default error handler. In case all data flows through a specific channel, having a custom error handler is as simple as follows:
#MessageEndpoint
public class MyErrorHandler {
#ServiceActivator(inputChannel = "errorChannel")
public String handle(String messsage) {
// do whatever you like
}
}
The Integration framework offers lots of usefull stuff for general handling.
I think you are looking for cross-cutting exception handling and good news, you are working with Spring MVC yes you can use this feature.
All you need to do, is throw your CustomExcptions or whatever other Exceptions that are from your services to your action methods.
Let's say here is your service:
#Service
public class MyService {
public void someMethod throws RuntimeException {
...
}
}
In your controller method:
#Controller
public class MyController {
#Autowired
MyService service;
#RequestMapping("/someuri"){
try {
service.someMethod();
} catch {
throw new RuntimeException();
}
}
#ExceptionHandler(RuntimeException.class)
public ModelAndView handleException(RuntimeException ex) {
ModelAndView model = new ModelAndView("errorpage");
return model;
}
}
The handleException method annotated with ExceptionHandler is your advice method for exception handling and it will be called anytime a RuntimeException is throw inside your controller and you can keep up like this for all other exceptions.

How can I handle exceptions with Spring Data Rest and the PagingAndSortingRepository?

Let's say I have a repository like:
public interface MyRepository extends PagingAndSortingRepository<MyEntity, String> {
#Query("....")
Page<MyEntity> findByCustomField(#Param("customField") String customField, Pageable pageable);
}
This works great. However, if the client sends a formed request (say, searching on a field that does not exist), then Spring returns the exception as JSON. Revealing the #Query, etc.
// This is OK
http://example.com/data-rest/search/findByCustomField?customField=ABC
// This is also OK because "secondField" is a valid column and is mapped via the Query
http://example.com/data-rest/search/findByCustomField?customField=ABC&sort=secondField
// This throws an exception and sends the exception to the client
http://example.com/data-rest/search/findByCustomField?customField=ABC&sort=blahblah
An example of the exception thrown and sent to client:
{
message:null,
cause: {
message: 'org.hibernate.QueryException: could not resolve property: blahblah...'
}
}
How can I handle those exceptions? Normally, I use the #ExceptionHandler for my MVC controllers but I'm not using a layer between the Data Rest API and the client. Should I?
Thanks.
You could use a global #ExceptionHandler with the #ControllerAdvice annotation. Basically, you define which Exception to handle with #ExceptionHandler within the class with #ControllerAdvice annotation, and then you implement what you want to do when that exception is thrown.
Like this:
#ControllerAdvice(basePackageClasses = RepositoryRestExceptionHandler.class)
public class GlobalExceptionHandler {
#ExceptionHandler({QueryException.class})
public ResponseEntity<Map<String, String>> yourExceptionHandler(QueryException e) {
Map<String, String> response = new HashMap<String, String>();
response.put("message", "Bad Request");
return new ResponseEntity<Map<String, String>>(response, HttpStatus.BAD_REQUEST); //Bad Request example
}
}
See also: https://web.archive.org/web/20170715202138/http://www.ekiras.com/2016/02/how-to-do-exception-handling-in-springboot-rest-application.html
You could use #ControllerAdvice and render the content your way. Here is tutorial if you need know how to work on ControllerAdvice, just remember to return HttpEntity

#ExceptionHandler not getting called once exception is thrown from REST layer

I'm developing a REST service using Spring MVC. I'm trying to implement exception handling using #ExceptionHandler . When exception is thrown from REST layer, it's not been intercepted by #ExceptionHandler. Am i missing anything ?
#Service
#Path("/customer")
public class CustomerResource extends BaseResource{
#Autowired
private CustomerDao customerDao;
........
#GET
#Path("/customer/{accountNumber}")
public Response findCustomerByAccountNumber(String accountNumber) throw Exception{
Customer customer=null;
customer=customerDao.find(....);
if(customer==null)
throw new ResourceNotFoundException();
else
..........
}
}
Base class which has Exception handler method
public abstract class BaseResource {
.......
#ExceptionHandler({ResourceNotFoundException.class })
public Response handleException(Exception ex) {
ErrorResource errResource = new ErrorResource();
.....
return Response.status(Response.Status.NOT_FOUND).entity(errResource).build();
}
}
You are throwing ResourceNotFound but have specified ResourceNotFoundException in the exception handler - these seem to be different exceptions. Either throw ResourceNotFoundException instead of ResourceNotFound or add ResourceNotFound to the exception handler.
EDIT:
Don't know how I missed it at first: just noticed you don't actually use Spring MVC controller. Spring MVC exception handlers only work for requests handled by Spring MVC controllers. They handle exceptions that happen in the body of controller handler methods. You seem to use something else to handle REST requests.

Categories