Difference between AccessDeniedHandler and ResponseEntityExceptionHandler - spring-boot

I am trying to implement CommonExceptionHandler class in my project. I searched on google there are multiple methods to achieve it. The two most common I found are above one. Please help me , When I should use AccessDeniedHandler (Interface) and ResponseEntityExceptionHandler (Class).
Do they make any difference when I enabled Security configuration in the project.?

To make things clear there isn't any relation between ResponseEntityExceptionHandler and AccessDeniedHandler. The 1st one is used to centralized the handling of most common exceptions raised by Spring MVC. It provides about 17 protected methods that you can override to customize the response after the exception. You can find more details here
And example of usage:
#ControllerAdvice // or #RestControllerAdvice
public class CommonExceptionHandler extends ResponseEntityExceptionHandler {
}
Regarding the 2nd one AccessDeniedHandler as indicated on the doc:Handles an access denied failure. An access denied exception is raised when someone try to access a resource which she/he/it is not allowed to access to it.
Now if your question is: Can your CommonExceptionHandler also handle AccessDeniedHandler exception? Yes by doing this:
#ControllerAdvice // or #RestControllerAdvice
public class CommonExceptionHandler extends ResponseEntityExceptionHandler implements AccessDeniedHandler {
}
But I'll suggest you to handle security exception in another class like:
public class CommonSecurityExceptionHandler implements AccessDeniedHandler {
}

I am trying to implement CommonExceptionHandler class in my project.
ResponseEntityExceptionHandler is more preferred because it can handle any sql, javax validation ,http method and any custom exception. It gives you capability to customize error message with status code. Here is an example how you can configure you custom error handler.
As per documenttation, AccessDeniedHandler can handle only exception of type AccessDeniedException. Based on above mentioned link, you can handle AccessDeniedException by just following new method.
#ExceptionHandler(AccessDeniedHandler.class)
#ResponseStatus(value = HttpStatus.CONFLICT)
public Map<String, String> handleAccessDeninedException(AccessDeniedHandler ex) {
// write your own logic to return user friendly response
}

Related

spring boot application exception handler which don't have controller

My Spring boot app is standalone application which don't have controller. I am calling service layer from main method of spring boot application.
I have tried to use #ExceptionHandler #ControllerAdvice annotations in my class as below. but control never comes to My Exception Handler method
package com.test.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
#ControllerAdvice
public class MyExceptionHandler {
#ExceptionHandler(NullPointerException.class)
public void handleNullpointerExcetion() {
System.out.println("Handling Null pointer exception");
}
}
Tried with package name as well which i need to scan in #ControllerAdvice but it is not working
#ControllerAdvice("com.test.utility")
public class MyExceptionHandler {
#ExceptionHandler(NullPointerException.class)
public void handleNullpointerExcetion() {
System.out.println("Handling Null pointer exception");
}
}
Are we not able to handle exception at centralized place if i we don't have controller class which we annotate with #RestContoller or #Controller
I don't think so.
ControllerAdvice is only used whenever a controller would return an exception,
It is a layer that exists after your endpoint in the controller returns and before actually returning the response, to interject and globally handle the exception and is meant to be global only for controllers.
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html
since you don't have a controller, I'd imagine the ControllerAdvice will not help you there.
If you want a centralized error handling mechanism, you'd have to implement something similar to the controller advice yourself around your "Main" function, to which you can have unified exception handling responses.

Spring AOP Advice for ResponseEntityExceptionHandler.handleException

I am new at Spring AOP. I try to write advice for ResponseEntityExceptionHandler.handleException method to logging exception info. After hours of searching for solutions, I'm stuck.
This is my Apect component
#Log4j2
#Aspect
#Component
public class LogginAspect {
#Pointcut(value = "execution(* org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler.handleException(..)) && args(ex, request)")
public void callSpringExceptionHandler() {}
#Before("callSpringExceptionHandler()")
public void logBeforeError(JoinPoint joinPoint, Exception ex, WebRequest request) {
log.error(ex.getMessage(), ex);
}
}
I have tried different patterns of pointcut but with no luck.
My advice logBeforeError does not ever called at all. Please help me with my problem
From the Spring documentation :5.8. Proxying Mechanisms
If the target object to be proxied implements at least one interface,
a JDK dynamic proxy is used. All of the interfaces implemented by the
target type are proxied. If the target object does not implement any
interfaces, a CGLIB proxy is created.
and
With CGLIB, final methods cannot be advised, as they cannot be
overridden in runtime-generated subclasses.
ResponseEntityExceptionHandler is an abstract class which does not implement any interface and ResponseEntityExceptionHandler.handleException() is a final method. In short Spring AOP will not be able to advice that method execution.
You will be able to achieve advicing a final method using AspectJ though. Please go through the detailed answer from #kriegaex

Exception is not thrown for page doesn't exist

I have defined ExceptionHandler with #ControllerAdvice and catches the following
Exception.class, Throwable.class, SQLException.class
When a user enters a page which doesn't exist or not available in the server. circular view page error is being displayed in the log and ExceptionHandler is not getting called.
What are the usual checkpoints to make the API error to get caught in CustomExceptionHandler. Not sure whether any tomcat hooks to be defined.
Using Spring Boot 2.0 and Spring version 5.0
Thanks.
In case : user enters a page/resource which does not exist, no exception is thrown. So your code does not work (I believe your code is similar to following code)
#ControllerAdvice
public class ErrorHandler {
#ExceptionHandler(Exception.class)
public String handle() {
....
return "error"
}
}
In order to make it work you need to extend yourhandler class from ResponseEntityExceptionHandler as
#ControllerAdvice
public class ErrorHandler extends ResponseEntityExceptionHandler {
...
}
And You need to override the following method
handleHttpMediaTypeNotSupported
handleHttpMediaTypeNotSupported
Detailed guide can be found from
- https://blog.jayway.com/2013/02/03/improve-your-spring-rest-api-part-iii/
- http://www.baeldung.com/global-error-handler-in-a-spring-rest-api
Another way, You can override /error if there is fixed message in all general cases.

#RestControllerAdvice vs #ControllerAdvice

What are the major difference between #RestControllerAdvice and #ControllerAdvice ??
Is it we should always use #RestControllerAdvice for rest services and #ControllerAdvice MVC ?
#RestControllerAdvice is just a syntactic sugar for #ControllerAdvice + #ResponseBody, you can look here.
Is it we should always use #RestControllerAdvice for rest services and
#ControllerAdvice MVC?
Again, as mentioned above, #ControllerAdvice can be used even for REST web services as well, but you need to additionally use #ResponseBody.
In addition, we can just understand it as:
#RestControler = #Controller + #ResponseBody
#RestControllerAdvice = #ControllerAdvice + #ResponseBody.
Keeping in mind that #RestControllerAdvice is more convenient annotation for handling Exception with RestfulApi.
Example os usage:
#RestControllerAdvice
public class WebRestControllerAdvice {
#ExceptionHandler(CustomNotFoundException.class)
public ResponseMsg handleNotFoundException(CustomNotFoundException ex) {
ResponseMsg responseMsg = new ResponseMsg(ex.getMessage());
return responseMsg;
}
}
In that case any exception instanceOf CustomNotFoundException will be thrown in body of response.
Example extracted here:
https://grokonez.com/spring-framework/spring-mvc/use-restcontrolleradvice-new-features-spring-framework-4-3
Exception: A good REST API should handle the exception properly and send the proper response to the user. The user should not be rendered with any unhandled exception.
A REST API developer will have two requirements related to error handling.
Common place for Error handling
Similar Error Response body with a proper HTTP status code across APIs
#RestControllerAdvice is the combination of both #ControllerAdvice and #ResponseBody
The #ControllerAdvice annotation was first introduced in Spring 3.2.
We can use the #ControllerAdvice annotation for handling exceptions in the RESTful Services but we need to add #ResponseBody separately.
Note:
GlobalExceptionHandler was annotated with #ControllerAdvice, thus it is going to intercept exceptions from controllers accross the application.
The differences between #RestControllerAdvice and #ControllerAdvice is :
#RestControllerAdvice = #ControllerAdvice + #ResponseBody. - we can
use in REST web services.
#ControllerAdvice - We can use in both MVC and Rest web services, need to
provide the ResponseBody if we use this in Rest web services.
For Example :
Exception Class:
#ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends Exception{
private static final long serialVersionUID = 1L;
public ResourceNotFoundException(String message){
super(message);
}
}
usage of the above exception in Rest Web Service.
#RestControllerAdvice
public class MyRestControllerAdviceHandler {
#ExceptionHandler(ResourceNotFoundException.class)
public ResponseMsg resourceNotFoundException(ResourceNotFoundException ex) {
ResponseMsg resMsg = new ResponseMsg(ex.getMessage());
return resMsg;
}
}
usage of the above exception in MVC.
#ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<?> resourceNotFoundException(ResourceNotFoundException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
}
If you use #ControllerAdvice and return your error object from a method then it will look for a view with the name of your error object so instead of returning the expected response it will return 404 for not founding a view page with that name
#ControllerAdvice
public class CustomizedExceptionHandler {
#ExceptionHandler({ UserNotFoundException.class })
#ResponseStatus(code = HttpStatus.BAD_REQUEST)
public ExceptionResponce handleUserNotException(Exception ex, WebRequest request) throws Exception {
ExceptionResponce exceptionResponce = new ExceptionResponce(new Date(), ex.getMessage(),
request.getDescription(false));
return exceptionResponce;
}
}
As in the above code, I want to return 400 (BAD_REQUEST) but
instead of 400, it is returning 404(NOT_FOUND)
You can solve this issue by using any of the below ways
add #ResponseBody to your method or class.
Use #RestControllerAdvice.
Or you can wrap your error object in ResponseEntity.
After using either of the above ways it returns the correct response

Custom default headers for REST API only using Spring Data REST

I have a use case where my application hosts REST API and web application and we need to add custom header to REST APIs only. REST APIs are enabled through Spring Data REST. Typically we could use Servlet Filter to achieve this but we need code the logic of isolating requests to our REST API and add the custom headers. It would be nice if Spring Data REST API allows to add a default header to all the responses it generates. What are your thoughts? Don't say I am lazy :)
For folks looking for actual implementation details..
Interceptor
public class CustomInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("adding CORS headers.....");
response.addHeader("HEADER-NAME", "HEADER-VALUE");
return true;
}
}
Java Configuration
#Configuration
public class RepositoryConfig extends
RepositoryRestMvcConfiguration {
#Override
public RequestMappingHandlerMapping repositoryExporterHandlerMapping() {
RequestMappingHandlerMapping mapping = super
.repositoryExporterHandlerMapping();
mapping.setInterceptors(new Object[] { new CustomInterceptor() });
return mapping;
}
}
As Spring Data REST is built on top of Spring MVC, the easiest way is to configure a custom HandlerInterceptor as described in the reference documentation.
With Spring Data REST the easiest way is to extend RepositoryRestMvcConfiguration and override repositoryExporterHandlerMapping, call the parent method and then invoke ….setInterceptors(…) on it.
Finally I managed to make the setup of custom interceptor working also on spring-data-rest 2.4.1.RELEASE.
#Configuration
public class RestMvcConfig extends RepositoryRestMvcConfiguration {
#Autowired UserInterceptor userInterceptor;
#Autowired ApplicationContext applicationContext;
#Override
public DelegatingHandlerMapping restHandlerMapping() {
RepositoryRestHandlerMapping repositoryMapping = new RepositoryRestHandlerMapping(resourceMappings(), config());
repositoryMapping.setInterceptors(new Object[] { userInterceptor }); // FIXME: not nice way of defining interceptors
repositoryMapping.setJpaHelper(jpaHelper());
repositoryMapping.setApplicationContext(applicationContext);
repositoryMapping.afterPropertiesSet();
BasePathAwareHandlerMapping basePathMapping = new BasePathAwareHandlerMapping(config());
basePathMapping.setApplicationContext(applicationContext);
basePathMapping.afterPropertiesSet();
List<HandlerMapping> mappings = new ArrayList<HandlerMapping>();
mappings.add(basePathMapping);
mappings.add(repositoryMapping);
return new DelegatingHandlerMapping(mappings);
}
}
I had to override the restHandlerMapping method, copy-paste it's content and add a line repositoryMapping.setInterceptors for adding custom interceptor, in my case the UserInterceptor.
Is there any better way?

Resources