Java interceptor not getting called - java

I have a Spring boot application and I am implementing and interceptor in order to log some data.
The problem is that is not getting called, I have tried:
#Interceptor
public class LoggerInterceptor{
#AroundInvoke
public Object collectBasicLoggingInformation(InvocationContext context) throws Exception {
Logger logger = LoggerFactory.getLogger(context.getClass());
logger.info("Method Called: " + context.getMethod()
.getName());
logger.info("Parameters: " + Arrays.toString(context.getParameters()));
return context.proceed();
}
}
And then I've applied to methods or classes and in both of them doesn't work:
#GetMapping
#Interceptors(LoggerInterceptor.class)
public List getAllFilingNumber(){
logger.info("This is a test");
return filingNumberService.findAll();
}
Or
#RestController
#RequestMapping(FilingNumberController.BASE_URL)
#Interceptors(LoggerInterceptor.class)
public class FilingNumberController{
#GetMapping
public List getAllFilingNumber(){
logger.info("This is a test");
return filingNumberService.findAll();
}
}
Does someone knows what I am doing wrong?
Thanks

If you are having a springboot application in order to intercept the request to a controller , you have to take a different approach altogethor.
Interceptors are used in conjunction with Java EE managed classes to
allow developers to invoke interceptor methods on an associated target
class, in conjunction with method invocations or lifecycle events.
Common uses of interceptors are logging, auditing, and profiling.
Reference Doc
You are trying to use Java EE annotation with spring , which won't work.In spring-boot you will have to register the interceptors like :
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleChangeInterceptor());
registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
}
}
The interceptor itself have to be a class which extends the HandlerInterceptorAdapter and implements the methods as follows.
From Spring DOCS :
All HandlerMapping implementations support handler interceptors that
are useful when you want to apply specific functionality to certain
requests — for example, checking for a principal. Interceptors must
implement HandlerInterceptor from the org.springframework.web.servlet
package with three methods that should provide enough flexibility to
do all kinds of pre-processing and post-processing:
preHandle(..): Before the actual handler is executed
postHandle(..): After the handler is executed
afterCompletion(..): After the complete request has finished
#Component
public class RequestInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object object) throws Exception {
System.out.println("we are Intercepting the Request");
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object object, ModelAndView model)
throws Exception {
System.out.println("request processing "
+ "completed by #RestController");
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object object, Exception arg3)
throws Exception {
System.out.println("afterCompletion Request Completed");
}
}

Related

How to apply custom interceptor to external library as well

I developed 3 things.
a interceptor-library with my custom interceptor.
Application
another library. A-library
This interceptor in interceptor-library intercepts a request to the controller and reads the header value.
ex)Interceptor-library code
public class MyInterceptorConfig implements WebMvcConfigurer {
private final MyInterceptor interceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor);
}
public class MyInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// get request.getHeader....
My application has dependency in this interceptor-library and A-library in build.gradle.
ex)Application's build.gradle (Actual working Application)
dependencies {
implementation myLibrary('interceptor-library')
implementation myLibrary('A-library')
The problem is that the other libraries that this application uses are also using the Controller.
ex) A-library
#RestController
public class ALibraryController{
#GetMapping("/api/library-works")
public ResponseEntity<?> test() {
During application operation, the interceptor works well for the controller declared "inside" the application.
However, the interceptor does not work on the controller in the A-library that the application uses.
(Interceptor can't intercept /api/library-works)
I thought the interceptor would intercept all the controllers in the "Application" and the controllers in "all the libraries" that the application has. ....
Is there a way to solve it?
Plz help me ......

Invoke Same Method for Multiple Services in Application

My application consists of multiple services.We had a requirement now that for every request coming in to our application we need to validate the token.
Current architecture of my application is such that every microservice has its own ServiceInterceptor class and in that class I am writing the logic in prehandle method to validate token recieved in request.
Service Interceptor Class.
#Component
public class ServiceInterceptor implements HandlerInterceptor {
private static final ApplicationLogger logger = ApplicationLogger.getInstance();
#Autowired
TokenInfoServiceImpl tokenInfoServiceImpl;
#Override
#CrossOrigin(origins = "*", maxAge = 3600)
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String requestPath = request.getRequestURL().toString();
String authToken = request.getHeader("authToken");
String bearerToken = request.getHeader("Authorization");
String userId = request.getHeader("userId");
if (deviceId.equals("web")) {
if (bearerToken.startsWith("Bearer ")){
bearerToken = bearerToken.substring(7, bearerToken.length());
} else {
response.sendError(400, "Expected bearer prefix to Authorization header value.");
}
boolean isTokenValid = tokenInfoServiceImpl.validateToken(bearerToken);
return isTokenValid;
}
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("Post Handle method is Calling");
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception exception) throws Exception {
System.out.println("Request and Response is completed");
}
}
My concern is since we have different services,every service has its interceptor class , so in every service will I have to create method validateToken(to validate the token when a request comes to that service) which is obviously not at all an ideal approach.
Is there a way that I could write validateToken method in one place and that could be accessed by all the services(like UserService,PaymentService,etc..) or rather one Interceptor could be used to intercept request for all the individual microservices instead of having separate interceptor for each service .
I know this can be done using API Gateway but right now our team want a quick solution to this .API Gateway will implement later.
If I understand your question & comments you can try below :
Create Configuration bean which implements WebMvcConfigurer
Use your ServiceInterceptor inside addInteceptor & mention endpoints or root context if all endpoints needed this config :
#Configuration
public class ConfigClass implements WebMvcConfigurer{
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ServiceInterceptor ()).addPathPatterns("/contextroot/**");
}
}
Also you may directly use your ServiceInterceptor without annotating it with Component.

How to trigger a callback post fetching an entity in spring boot

#Service
#GetMapping
public Foo findByFooId(#RequestParam(name = "fid") String fooId) {
return fooService.findByFooId(fooId);
}
I would like to trigger and save who viewed Foo, using a different method in FooService.
Its like a PostConstruct callback for a successful response of findByFooId. How can this be achieved
One way is going to a custom HandlerInterceptor implementation.
Definition of the interceptor
public class FooViewerInterceptor extends HandlerInterceptorAdapter {
#Autowired
FooService fooService;
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
// if response succeeded ? http response code = 200 ?
// extract the "who" logic
// extract the fooId from request path
fooService.viewedBy(fooId, userId); // example...
}
}
Register the interceptor. Note the path pattern specified with the custom interceptor instance.. just an example.
#Configuration
public class AppConfig implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new FooViewerInterceptor()).addPathPatterns("/foo/**");
}
}

Persistent counter for every REST call

Is there any better way in spring boot that I can maintain a persistent counter in a DB(say, Redis or ES) for every kind of REST call with their corresponding timestamp? (WHAT I am not looking for is calling a function from within every REST call). Probably something like if I can do it before the control is passed to the function corresponding to the REST call, a common portion.
you can implement a custom interceptor.
public class MyInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// persist your counter here
return true;
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
super.afterCompletion(request, response, handler, ex);
// do what you need in the end of the call
}
to make spring-boot invoke your interceptor you should add a configuration class:
#Service
#EnableWebMvc
public class MyConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/*");
}
}

Spring mvc filter for some controllers

I need to process all request coming to some Spring controllers to get some requester informartion or to throw exceptions like a security filter.
I would like if is there something buildin in Spring like a filter for controllers (I need it not for all controller, but only for someone).
I don't want to apply this filter by url request but with a class/method extension or annotation.
This is my actual solution:
#Controller
public class MyFilteredController extends FilterController {
#RequestMapping("/filtered")
public void test1(HttpServletRequest req){
InfoBean infobean=filter(req);
//... controller job
}
}
A controller that extends a class with a filter method.
public abstract FilterController{
protected InfoBean filter(HttpServletRequest req){
//... filter job
return infobean;
}
}
I don't want to apply this filter by url request but with a
class/method extension or annotation
You can register a HandlerInterceptor for this purpose. For example, you can apply a filter to all handler methods that annotated with SomeAnnotation with following code:
public class CustomHandlerIntercepter extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
SomeAnnotation annotation = handlerMethod.getMethodAnnotation(SomeAnnotation.class);
if (annotation != null) {
// do stuff
}
}
return true;
}
}
Also, you should register your interceptor in WebConfig:
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CustomHandlerIntercepter());
}
}
You can read more about interceptors in spring reference documentation.
Take a look at SpringSandwich http://springsandwich.com/
It lets you set filters (Spring Interceptors, actually) directly as controller annotations. Unlike normal servlet filters, you'll also have full access to your Spring context.
Disclosure: I'm the author of this framework :)
You can use mvc intercepters here .
see :
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-handlermapping-interceptor
and if you want to intercept particular url you can do it as specified here
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-config-interceptors
Everything in using the SpringDispatcherServlet is URL based, I don't think you can do it by controller.
You will need to use a Filter, looks at the API here https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/filter/package-summary.html you will probable want to use a OncePerRequestFilter.
public class MyFilter extends OncePerRequestFilter{
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// TODO Auto-generated method stub
}
}
you will then need to add the filter in the web.xml
<filter>
<filter-name>requestFilter</filter-name>
<filter-class>com.greg.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>errorHandlerFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Now the hacky bit, if you want to get Spring beans in here you can create a Bridge class with statics in it.
public class Bridge {
private static PaymentService paymentService;
public PaymentService getPaymentService() {
return paymentService;
}
public void setPaymentService(PaymentService paymentService) {
Bridge.paymentService = paymentService;
}
}
If you want to inject some spring beans into this class
<bean id="paymentService" class="net.isban.example.service.PaymentService" />
<bean class="net.isban.example.util.Bridge">
<property name="paymentService" ref="paymentService" />
</bean>
Then in your filter (not spring class).
PaymentService paymentService = new Bridge().getPaymentService();
Happy for someone to show me a less hacky way of doing this.

Categories

Resources