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 ......
Related
I'm developing a jar library and trying to inject an interceptor from external jar library to Application.
For example:
External Lib
MyExternalInterceptor.java
public class MyExternalInterceptor implements HandlerInterceptor {
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// Do something
}
}
I tried to using AOP in external libs but it's not working.
InterceptorAspect.java
#Around("execution(* org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.addInterceptors(..))")
public Object aspect(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
// Tried to inject MyExternalInterceptor here
Object result = proceedingJoinPoint.proceed();
return result;
}
In Application using that lib:
Application
MyConfiguration.java
#Configuration
public MyConfiguration extends WebMvcConfigurationSupport {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SpringTestInterceptor()); // client's own interceptor
/* Add MyExternalInterceptor not explicitly but implicitly using AOP or other things */
}
}
Is there any way to inject an interceptor from external lib to App?
I know the question is very obscure (sorry for that), but could you give me any advice or hint to make it work?
Thank you for anyone who read my question :)
(I updated few more details for clarification)
Summary
Use WebMvcConfigurer in both Client and library side instead of WebMvcConfigurationSupport
AoP is not needed
I use WebMvcConfigurer instead of WebMvcConfigurationSupport and change some codes like below:
External Lib
MyExternalInterceptor.java
Same as before
InterfaceAspect.java
Don't needed it anymore
MyExternalLibConfiguration.java
#Configuration
public class MyExternalLibConfiguration implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyExternalInterceptor());
}
}
Application (client)
MyConfiguration.java
#Configuration
public MyConfiguration implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SpringTestInterceptor()); // client's own interceptor
/* No need to add MyExternalInterceptor in here */
}
}
That's all! Everything is working well as M. Deinum said in comment.
Thank you again Deinum!
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");
}
}
My Spring web app is configured via Java annotations (see the configuration class at the bottom).
Is it possible to add a request filter in front of one controller (or possibly many via some sort of configuration) that supports the same (or at least a subset of the) annotations available inside #RestController methods, such as #PathVariable, #RequestParam, etc.?
So far I found the documentation about the HandlerInterceptor interface within the DispatcherServlet Interception docs and I configured one following what's in Interceptors configuration:
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(ctx.getBean(CustomInterceptor.class));
}
But the interceptor implements the HandlerInterceptor interface thus the preHandle() method has a given signature:
preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
I can of course read parameters, header values, etc from the arguments, but I was wondering whether some other way was already supported.
That the filter shows up in some sort of documentation (I'm using Swagger and SpringFox) would be a plus.
Main config class
#EnableWebMvc
#Configuration
#EnableSwagger2
#ComponentScan(basePackages= { /* ... */ })
#PropertySource("classpath:config.properties")
public class WebappConfig implements WebMvcConfigurer {
#Autowired
private ApplicationContext ctx;
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
// extra Jackson configuration
}
// see below for this method
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(ctx.getBean(CustomInterceptor.class));
}
}
I already looked at a lot of posts and nothing seems to work quite as i liked it to.
I want to inject an object into ContainerRequestContext properties from a filter and retrieve it later in other classes.
here is my filter:
#Priority(Priorities.AUTHENTICATION)
public class AuthorizationFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
containerRequestContext.setProperty("myObject", new Object());
}
}
here is the class I want access to ContainerRequestContext:
#Provider
public class SessionContextProvider implements ISessionContextProvider {
#Context
private ContainerRequestContext request;
#Override
public Object getSessionContext() {
return request.getProperty("mySessionContext");
}
}
and my spring config:
#Bean(name="sessionContextProvider")
#Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
public ISessionContextProvider sessionContextProvider() {
return new SessionContextProvider();
}
Everything works as expected if I inject ContainerRequestContext into my web resource. However if call my provider class ContainerRequestContext is always null.
I don't seem why this would not work.
Reagrds
Jonas
The problem is that with the Jersey/Spring integration, it allows us to successfully inject Spring beans into Jersey components, but this is not always true the other way around.
Jersey has it's own DI framework, HK21, and it is responsible for handle the injections with Jersey components. With the Jersey Spring integration, Jersey will lookup the Spring Bean, and take it as is, it won't inject it with any dependencies, I guess assuming Spring should take care of it's own injections.
That being said, if you don't require the ISessionContextProvider to be a Spring bean, then you can just make it an HK2 service. It's pretty simple. If you don't require any special initialization, you can just let HK2 create it. Here a simple configuration
public JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(new AbstractBinder() {
bind(SessionContextProvider.class)
.to(ISessionContextProvider.class)
.in(RequestScoped.class);
});
}
}
And that's it. You have an injectable ISessionContextProvider2.
If you require the ISessionContextProvider provider to be a Spring bean, then another option is to grab the bean from the Spring ApplicatinContext, and explicitly inject it yourself, using HK2's analogue of the ApplicationContext, its ServiceLocator. To do that we would need to use a Factory to do all the work transparently, so you can still inject the bean without doing any extra work on the outside
import javax.inject.Inject;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.ServiceLocator;
import org.springframework.context.ApplicationContext;
public class SessionContextProviderFactory
implements Factory<SessionContextProvider> {
private final ISessionContextProvider provider;
#Inject
public SessionContextProviderFactory(ApplicationContext ctx,
ServiceLocator locator) {
provider = ctx.getBean(ISessionContextProvider.class);
locator.inject(provider);
}
#Override
public ISessionContextProvider provide() {
return provider;
}
#Override
public void dispost(ISessionContextProvider provider) { /* noop */ }
}
Then just register the factory
public JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(new AbstractBinder() {
bindFactory(SessionContextProviderFactory.class)
.to(ISessionContextProvider.class)
.in(RequestScoped.class);
});
}
}
1 - hk2
2 - See also Dependency injection with Jersey 2.0
I found a workaround. I could inject the Spring HttpServletRequest into my AuthorizationFilter and set the SessionContext on this one.
#Autowired
private HttpServletRequest request;
....
request.setAttribute("mySessionContext", sessionContext);
And then because HttpServletRequest is known to spring and besically represents the same thing in my SessionContextProvider I do the same:
#Autowired
private HttpServletRequest request;
#Override
public SessionContext getSessionContext() {
return (SessionContext) request.getAttribute("mySessionContext");
}
I dont think this is the best solution possible. But it works. Ill wait for peeskillet for any other input if there is a better solution.
Regards
Jonas
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.