I am using Spring Boot(1.5.3) to develop a REST Web Service. In order to take some action on incoming request I have added an interceptor shown below.
#Component
public class RequestInterceptor extends HandlerInterceptorAdapter {
#Autowired
RequestParser requestParser;
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//HandlerMethod handlerMethod = (HandlerMethod) handler;
requestParser.parse(request);
return true;
}
}
RequestInterceptor has an autowired Spring Bean RequestParser responsible for parsing the request.
#Component
public class RequestParserDefault implements RequestParser {
#Override
public void parse(HttpServletRequest request) {
System.out.println("Parsing incomeing request");
}
}
Interceptor registration
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new RequestInterceptor()).addPathPatterns("/usermanagement/v1/**");
}
}
And my Spring Boot Application
#SpringBootApplication
public class SpringBootApp {
public static void main(String[] args) {
SpringApplication.run(SpringBootApp.class, args);
}
}
Now when a request comes in, it lands in preHandle method of RequestInterceptor but RequestParser is NULL. If I remove the #Component annotation from RequestParser I get an error during Spring context initialization No bean found of type RequestParser. That means RequestParser is registered as Spring bean in Spring context but why it is NULL at the time of injection? Any suggestions?
Your problem lies in this new RequestInterceptor().
Rewrite your WebMvcConfig to inject it, e.g. like this:
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Autowired
private RequestInterceptor requestInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestInterceptor)
.addPathPatterns("/usermanagement/v1/**");
}
}
Related
I'm writing a RESTful web service where I'm trying to inject a request scoped service class into a filter.
I have gone through Paul Samsotha's blog on how to inject request scoped services using proxies.
Here's my implementation:
The supplier for this:
public class FileServiceSupplier implements Supplier<FileService> {
#Inject
ContainerRequestContext context;
public FileService get() {
String something = context.get("something");
new FileService(something);
}
}
and I'm binding the supplier here
import org.glassfish.jersey.internal.inject.AbstractBinder;
...
public class CustomDependencyBinder extends AbstractBinder {
#Override
protected void configure() {
bindFactory(FileServiceSupplier.class)
.proxy(true)
.proxyForSameScope(false)
.to(FileService.class)
.in(RequestScoped.class);
}
}
public class MyWebService extends ResourceConfig {
public MyWebService() {
register(new CustomDependencyBinder());
}
}
But now when I'm injecting this into a filter:
public class FileScanningFilter implements ContainerRequestFilter {
#Inject
private FileService fileService;
#Inject
private ResourceInfo resourceInfo;
#Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
boolean status = fileService.assertStatus();
}
}
#Provider
public class FileScanningFeature implements DynamicFeature {
#Override
public void configure(ResourceInfo resourceInfo, FeatureContext featureContext) {
featureContext.register(FileScanningFilter.class);
}
}
But now when I send a request I get the following error:
"There is more than one active context for org.glassfish.jersey.process.internal.RequestScoped" "java.lang.IllegalStateException: There is more than one active context for org.glassfish.jersey.process.internal.RequestScoped
at org.jvnet.hk2.internal.ServiceLocatorImpl._resolveContext(ServiceLocatorImpl.java:2193)
at org.jvnet.hk2.internal.ServiceLocatorImpl.access$000(ServiceLocatorImpl.java:105)
at org.jvnet.hk2.internal.ServiceLocatorImpl$3.compute(ServiceLocatorImpl.java:165)
at org.jvnet.hk2.internal.ServiceLocatorImpl$3.compute(ServiceLocatorImpl.java:161)
at org.glassfish.hk2.utilities.cache.Cache$OriginThreadAwareFuture$1.call(Cache.java:74)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at org.glassfish.hk2.utilities.cache.Cache$OriginThreadAwareFuture.run(Cache.java:131)
at org.glassfish.hk2.utilities.cache.Cache.compute(Cache.java:176)
at org.jvnet.hk2.internal.ServiceLocatorImpl.resolveContext(ServiceLocatorImpl.java:2207)
at org.jvnet.hk2.internal.MethodInterceptorImpl.internalInvoke(MethodInterceptorImpl.java:64)
at org.jvnet.hk2.internal.MethodInterceptorImpl.invoke(MethodInterceptorImpl.java:101)
at org.jvnet.hk2.internal.MethodInterceptorInvocationHandler.invoke(MethodInterceptorInvocationHandler.java:39)
at com.sun.proxy.$Proxy88.getResourceMethod(Unknown Source)
at com.test.FileScanningFilter.filter(AuthFilter.java:56)
Even though I inserted it once in the filter, it is saying there are multiple contexts.
I'm using Jersey 2.28
P.S: For the AbstractBinder , I followed this answer
While implementing the interceptors in my spring boot application I came across a weird problem which is as follows:
My Application class code:
#Import(CommonConfig.class)
#EnableAsync
#SpringBootApplication
#EnableSwagger2
#EnableScheduling
#EnableSpringDataWebSupport
#ImportResource({ "classpath:META-INF/applicationContext.xml" })
#AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class Application extends SpringBootServletInitializer {
private static final Logger LOG = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
.......
................
}
#Bean
public TokenInterceptor intializeTokenInterceptor() {
System.out.println("Adding interceptors");
return new TokenInterceptor();
}
#Bean
public WebMvcConfigurerAdapter adapter() {
return new WebMvcConfigurerAdapter() {
#Override
public void addInterceptors(InterceptorRegistry registry) {
System.out.println("Adding interceptors");
registry.addInterceptor(intializeTokenInterceptor()).addPathPatterns("/**");
super.addInterceptors(registry);
}
};
}
}
Inside my application-context I have mentioned tag (mvc:annotation-driven) as I need this for initializing my bean classes.
Now, if I test my application by removing the annotation-driven tag, my interceptors are getting called. However, if I keep this tag, my interceptors are not getting called, (which I believe is overriding the implementation of WebMvcConfigurerAdapter bean from WebMvcAutoConfiguration.class somehow).
I know that this have been asked a lot of times, but none of them could make my code work. I might be doing something wrong but I can't find out what.
I'm using Spring Boot with AngularJS, what I'm trying to do is to preHandle all the requests.
This is my code:
Controller:
#RestController
#RequestMapping(value = { "/user" })
public class UserController {
#RequestMapping(value = "/get", method = RequestMethod.GET)
public String getLanguage() {
return "user";
}
}
Interceptor:
#Component
public class RequestHandler extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException {
System.out.println("intercepted");
return false;
}
}
WebConfig:
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired
HandlerInterceptor requestHandler;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestHandler);
}
}
And I added this to the applicationContext.xml:
<mvc:interceptors>
<bean class="server.RequestHandler" />
</mvc:interceptors>
I've been all the weekend trying to make this work and I couldn't, any help will be really appreciated!
Thank you!
You could try defining the Bean manually without declaring your Interceptor as a #Component like this:
RequestHandler.java
public class RequestHandler extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) throws ServletException {
System.out.println("intercepted");
return true;
}
}
WebConfig.java
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public RequestHandler requestHandler() {
return new RequestHandler();
}
#Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(requestHandler());
}
}
And by the way: If the class is declared as an interceptor why no renaming it to something which contains the term Interceptor in it such as RequestInterceptor?
It should work straightforward. Please let me know if that did the trick for you!
Update: I've implemented this in a prototype. See this minimal, complete, and verifiable example. Hope it helps!
https://github.com/dbubenheim/stackoverflow-41794738.git
I have a problem I'm not able to solve. I have searched on the internet and on Stackoverflow but could not find how to solve the problem.
I want to test a Spring MVC Handler interceptor. This interceptor has a "session" scope bean as a dependency.
I tried to reduce the code as much as possible. Here is the code:
The src part :
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = { "..." })
public class SpringMvcConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry interceptorRegistry) {
interceptorRegistry.addInterceptor(initializeUserLanguageHandler());
}
#Bean
public InitializeUserLanguageHandler initializeUserLanguageHandler() {
return new InitializeUserLanguageHandler();
}
#Bean
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public SessionBean sessionBean() {
return new SessionBean();
}
}
#Component
public class InitializeUserLanguageHandler extends AbstractHandlerInterceptor {
#Autowired
private SessionBean sessionBean;
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (sessionBean.getLanguage() == null) {
sessionBean.setLanguage(getUserLanguage());
}
return true;
}
}
The test part:
#WebAppConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SpringMvcConfiguration.class)
public class BaseSpringMvcIntegrationTest {
#Resource
protected WebApplicationContext webApplicationContext;
protected MockMvc mockMvc;
#Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
}
public class InitializeUserLanguageHandlerTest extends BaseSpringMvcIntegrationTest {
#Autowired
private SessionBean sessionBean;
#Autowired
private MockHttpSession mockHttpSession;
#Test
public void testLanguageIsInitializedOnlyOnce() throws Exception {
MockHttpSession mocksession = new MockHttpSession();
// It is null, this is because the interceptor has not been called yet
assertEquals(null, sessionBean.getLanguage());
// This line will call the interceptor and set language to "nl"
mockMvc.perform(get("/").session(mocksession).principal(getUser("nl")));
// It is null, but I expect it to be "nl"
assertEquals(null, sessionBean.getLanguage());
// Let's try again
mockMvc.perform(get("/").session(mocksession).principal(getUser("fr")));
// It is null, but I expect it to be "nl"
assertEquals(null, sessionBean.getLanguage());
}
}
You can see in the test class "InitializeUserLanguageHandlerTest" that I have some assertions.
The first time I call:
mockMvc.perform(get("/").session(mocksession).principal(getUser()));
The code in the interceptor is executed and language is set to "nl". Therefore, in my test, I would have expected that sessionBean.getLanguage() would return me "nl", but it is not. I don't understand why.
So I'm calling the perform again, the interceptor code is executed again, and calling sessionBean.getLanguage() returns "nl".
It seems I've two SessionBean instances, one in my test and the other in the source. But when I look at the SessionBean variable in Eclipse in Debug mode, they have the same ID.
If I change the "session" scope to "application" scope, it is working properly.
Can somebody help me ?
Thank you.
Here is one way to solve the problem, not sure it is the best though.
#ContextConfiguration(classes = {SpringMvcConfiguration.class, InitializeUserLanguageHandlerTest.BeanConfig.class})
public class InitializeUserLanguageHandlerTest extends BaseSpringMvcIntegrationTest {
#Configuration
public static class BeanConfig {
#Bean(name = "sessionBean")
public SessionBean sessionBean() {
return new SessionBean();
}
}
...
}
I want to add spring mvc interceptor as part of Java config. I already have a xml based config for this but I am trying to move to a Java config. For interceptors, I know that it can be done like this from the spring documentation-
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleInterceptor());
}
}
But my interceptor is using a spring bean autowired into it like follows-
public class LocaleInterceptor extends HandlerInterceptorAdaptor {
#Autowired
ISomeService someService;
...
}
The SomeService class looks like follows-
#Service
public class SomeService implements ISomeService {
...
}
I am using annotations like #Service for scanning the beans and have not specified them in the configuration class as #Bean
As my understanding, since java config uses new for creating the object, spring will not automatically inject the dependencies into it.
How can I add the interceptors like this as part of the java config?
Just do the following:
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
LocaleInterceptor localInterceptor() {
return new LocalInterceptor();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeInterceptor());
}
}
Of course LocaleInterceptor needs to be configured as a Spring bean somewhere (XML, Java Config or using annotations) in order for the relevant field of WebConfig to get injected.
The documentation for general customization of Spring's MVC configuration can be found here, and specifically for Interceptors see this section
When you handle the object creation for yourself like in:
registry.addInterceptor(new LocaleInterceptor());
there is no way the Spring container can manage that object for you and therefore make the necessary injection into your LocaleInterceptor.
Another way that could be more convenient for your situation, is to declare the managed #Bean in the #Configuration and use the method directly, like so:
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public LocaleInterceptor localeInterceptor() {
return new LocaleInterceptor();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor( localeInterceptor() );
}
}
Try to inject your service as a constructor parameter. It is simple.
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired
ISomeService someService;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleInterceptor(someService));
}
}
Then reconfigure your interceptor,
public class LocaleInterceptor extends HandlerInterceptorAdaptor {
private final ISomeService someService;
public LocaleInterceptor(ISomeService someService) {
this.someService = someService;
}
}
Cheers !