I'm trying to inject the constructor of resource class using Guice. Meanwhile i have used GrizzlyWebServer as a server to handle the reqquest from the resource class. Below i've given some of the codes and errors I'm having.
GoogleModule class:
public class GoogleModule extends AbstractModule {
#Override
protected void configure() {
bind(Interface.class).to(Implementation.class);
}
}
Resource class
#Path("/path")
public class ResourceClass {
Logger log = LoggerFactory.getLogger(ResourceClass.class);
private final Interface interface;
GConnection con = new GConnection();
#Inject
public ResourceClass(Interface interface) {
this.interface = interface;
}
#GET
#Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public List<Object> getObjects() {
return interface.list();
}
}
and before starting the grizzly server I've call this statement.
Injector injector = Guice.createInjector(new GoogleModule());
webserver.startServer();
after this set up i've i found the following error.
SEVERE: Missing dependency for constructor public com.motilink.services.ResourceClass(Interface ) at parameter index 0
Jul 3, 2013 9:52:36 AM com.sun.grizzly.http.servlet.ServletAdapter doService
SEVERE: service exception:
com.sun.jersey.spi.inject.Errors$ErrorMessagesException
at com.sun.jersey.spi.inject.Errors.processErrorMessages(Errors.java:170)
at com.sun.jersey.spi.inject.Errors.postProcess(Errors.java:136)
at com.sun.jersey.spi.inject.Errors.processWithErrors(Errors.java:199)
at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:770)
at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:765)
at com.sun.jersey.spi.container.servlet.ServletContainer.initiate(ServletContainer.java:489)
at com.sun.jersey.spi.container.servlet.ServletContainer$InternalWebComponent.initiate(ServletContainer.java:319)
at com.sun.jersey.spi.container.servlet.WebComponent.load(WebComponent.java:605)
at com.sun.jersey.spi.container.servlet.WebComponent.init(WebComponent.java:210)
at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:374)
at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:557)
at javax.servlet.GenericServlet.init(GenericServlet.java:212)
at com.sun.grizzly.http.servlet.ServletAdapter.loadServlet(ServletAdapter.java:451)
at com.sun.grizzly.http.servlet.ServletAdapter.doService(ServletAdapter.java:390)
at com.sun.grizzly.http.servlet.ServletAdapter.service(ServletAdapter.java:347)
at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:166)
at com.sun.grizzly.tcp.http11.GrizzlyAdapterChain.service(GrizzlyAdapterChain.java:186)
at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:166)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:824)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:721)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1014)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:220)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:530)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:511)
at java.lang.Thread.run(Thread.java:680)
Given that you're running through a servlet you need to make sure that Guice is hooked in correctly so that resources are created with injection rather than instantiated directly. The way you have your code now the injector is not used to create the new instance of the resource and hence your error.
There are details on how to set this up on the Guice Wiki.
Related
I'm attempting to implement OpenId Connect sign-on in a Spring Boot 1.3.0 application with Spring Security 3.2.5 on Spring Framework 4.2.3. The implementation is very similar to this question: Protecting REST API with OAuth2: Error creating bean with name 'scopedTarget.oauth2ClientContext': Scope 'session' is not active, except that I've implemented the suggested bean for the RequestContextFilter.
#Configuration
#EnableOAuth2Client
public class OpenIdConnectConfig {
#Value("${oidc.clientId}")
private String clientId;
#Value("${oidc.clientSecret}")
private String clientSecret;
#Value("${oidc.accessTokenUrl}")
private String accessTokenUri;
#Value("${oidc.userAuthorizationUri}")
private String userAuthorizationUri;
#Value("${oidc.redirectUri}")
private String redirectUri;
#Value("#{'${oidc.scopes}'.split(',')}")
private List<String> oidcScopes;
#Bean
public OAuth2ProtectedResourceDetails openIdResourceDetails() {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
details.setClientId(clientId);
details.setClientSecret(clientSecret);
details.setAccessTokenUri(accessTokenUri);
details.setUserAuthorizationUri(userAuthorizationUri);
details.setClientAuthenticationScheme(AuthenticationScheme.form);
details.setScope(oidcScopes);
details.setPreEstablishedRedirectUri(redirectUri);
details.setUseCurrentUri(false);
return details;
}
#Bean(name = "my.company.ui.security.OpenIdRestTemplate")
// ToDo: fix org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.oauth2ClientContext': Scope 'session' is not active for the current thread
public OAuth2RestTemplate OpenIdRestTemplate(OAuth2ClientContext clientContext) {
return new OAuth2RestTemplate(openIdResourceDetails(), clientContext);
}
#Bean
public RequestContextListener requestContextListener() {
return new RequestContextListener();
}
}
The exception stack trace is likewise similar
Caused by:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'scopedTarget.oauth2ClientContext':
Scope 'session' is not active for the current thread; consider
defining a scoped proxy for this bean if you intend to refer to it
from a singleton;
nested exception is java.lang.IllegalStateException: No thread-bound
request found: Are you referring to request attributes outside of an
actual web request, or processing a request outside of the originally
receiving thread? If you are actually operating within a web request
and still receive this message, your code is probably running outside
of DispatcherServlet/DispatcherPortlet: In this case, use
RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:355)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:187)
at com.sun.proxy.$Proxy78.getAccessToken(Unknown Source)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:169)
at my.company.ui.security.OpenIdConnectFilter.attemptAuthentication(OpenIdConnectFilter.java:118)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211)
at my.company.ui.security.OpenIdConnectFilter.doFilter(OpenIdConnectFilter.java:93)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at my.company.ui.security.UserCookieFilter.doFilter(UserCookieFilter.java:29)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at my.company.server.filter.UncaughtExceptionRequestFilter.doFilter(UncaughtExceptionRequestFilter.java:45)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at com.rmn.commons.web.metrics.AbstractInstrumentedFilter.doFilter(AbstractInstrumentedFilter.java:143)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:167)
at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:80)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:499)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
at org.springframework.web.context.request.SessionScope.get(SessionScope.java:91)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340)
... 48 more
Caused by:
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
at org.springframework.web.context.request.SessionScope.get(SessionScope.java:91)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:187)
at com.sun.proxy.$Proxy78.getAccessToken(Unknown Source)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:169)
at my.company.ui.security.OpenIdConnectFilter.attemptAuthentication(OpenIdConnectFilter.java:118)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211)
at my.company.ui.security.OpenIdConnectFilter.doFilter(OpenIdConnectFilter.java:93)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at my.company.ui.security.UserCookieFilter.doFilter(UserCookieFilter.java:29)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at my.company.server.filter.UncaughtExceptionRequestFilter.doFilter(UncaughtExceptionRequestFilter.java:45)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at com.rmn.commons.web.metrics.AbstractInstrumentedFilter.doFilter(AbstractInstrumentedFilter.java:143)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:167)
at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:80)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:499)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:748)
Powered by Jetty://
You can clearly see that the filter call is part of the Spring Security FilterChainProxy, so I don't know what to make of the error message's suggestion that "your code is probably running outside of DispatcherServlet/DispatcherPortlet". Also, I have tried adding a bean for the suggested alternative RequestContextFilter and the same exception is thrown.
The filter that performs the authentication (some exception handling and user processing code removed):
public class OpenIdConnectFilter extends AbstractAuthenticationProcessingFilter {
public OpenIdConnectFilter(
RequestMatcher requiresAuthenticationRequestMatcher,
AuthenticationService authenticationService
) {
super(requiresAuthenticationRequestMatcher);
setAuthenticationManager(new NoopAuthenticationManager());
}
#SuppressWarnings("RedundantThrows") // Matching overridden method
#Override
public Authentication attemptAuthentication(
HttpServletRequest request,
HttpServletResponse response
) throws AuthenticationException, IOException, ServletException {
// Required parameters (one-time access code, state) are retrieved from the context
OAuth2AccessToken oAuth2AccessToken = restTemplate.getAccessToken();
// Process the token, get the user details, return an Authentication object.
}
public void setRestTemplate(OAuth2RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
private static class NoopAuthenticationManager implements AuthenticationManager {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
throw new UnsupportedOperationException("No authentication should be done with this AuthenticationManager");
}
}
private static final Logger LOGGER = LoggerFactory.getLogger(OpenIdConnectFilter.class);
#Value("${oidc.clientId}")
private String clientId;
#Value("${oidc.issuer}")
private String issuer;
#Value("${oidc.jwt.jwk.url}")
private String jwkUrl;
private final AuthenticationService authenticationService;
private OAuth2RestTemplate restTemplate;
}
And the Security Config that sets up the Spring Security FilterProxyChain:
#Configuration
#EnableWebSecurity
#EnableOAuth2Client
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Override
#SuppressWarnings("unchecked")
protected void configure(HttpSecurity http)
throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.csrf()
.disable()
.authorizeRequests()
.expressionHandler(securityExpressionHandler)
.antMatchers("/asset/**").access("permitAll")
.antMatchers("/ws/ssoEnabled").access("permitAll")
.antMatchers("/**").access("hasRole('ROLE_USER') or hasRole('ROLE_TOKEN_ACCESS')")
.and()
.httpBasic()
.authenticationEntryPoint(ajaxAwareLoginUrlAuthenticationEntryPoint)
.and()
// Handles unauthenticated requests, catching UserRedirectRequiredExceptions and redirecting to OAuth provider
.addFilterAfter(new OAuth2ClientContextFilter(), SecurityContextPersistenceFilter.class)
// Handles the oauth callback, exchanging the one-time code for a durable token
.addFilterAfter(openIdConnectFilter, OAuth2ClientContextFilter.class)
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/logincheck")
.usernameParameter("username")
.passwordParameter("password")
.successHandler(ajaxAwareAuthenticationSuccessHandler)
.failureHandler(ajaxAwareAuthenticationFailureHandler)
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
.and()
.rememberMe()
.rememberMeServices(rememberMeServices)
// Even though this key has been added directly to the rememberMeServices instance, the RememberMeConfigurer
// can instantiate a new RememberMeServices with a made-up key if the same key is not provided.
.key("the key value")
;
// We do not configure a bean for the SessionAuthenticationStrategy. We want to use the Spring default strategy,
// which is configured by the above builder chain. In order to share the correct, configured instance with our
// custom OpenIdConnectFilter, we first tell the builder to perform the configuration (normally this would be
// done long after this method returns)...
http.getConfigurer(SessionManagementConfigurer.class).init(http);
// ... then we get the shared object by interface (SessionAuthenticationStrategy) class name...
final SessionAuthenticationStrategy sessionAuthenticationStrategy = http.getSharedObject(SessionAuthenticationStrategy.class);
// ... then set it in our custom filter.
openIdConnectFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
}
}
One final wrinkle: I was getting this error while running on my machine. Then, adding the RequestContextListener resolved it. When deploying it to our test environment, the exception message resurfaces. However, after a few hours or days, sometimes after the CI/CD pipeline re-deploys the same version, the problem resolves itself and the OpenID integration works as expected until we make the next change, bugfix or improvement, then it usually reoccurs for a similar short interval.
Questions:
Is DispatcherServlet/DispatcherPortlet a factor at all when running in Spring Boot?
How do you determine if you should use a RequestContextFilter or RequestContextListener? Is there an actual difference? The (linked) documentation isn't much help here, in my opinion.
Servlet listener that exposes the request to the current thread, through both LocaleContextHolder and RequestContextHolder. To be registered as listener in web.xml.
Alternatively, Spring's RequestContextFilter and Spring's DispatcherServlet also expose the same request context to the current thread. In contrast to this listener, advanced options are available there (e.g. "threadContextInheritable").
This listener is mainly for use with third-party servlets, e.g. the JSF FacesServlet. Within Spring's own web support, DispatcherServlet's processing is perfectly sufficient.
Where should the Beans for the RequestContextFilter/Listener be defined in a Spring Boot app? We don't have a web.xml. (My understanding is that web.xml is only for Spring MVC - please correct me if that is wrong.)
What could possibly be causing the context to be found sometimes? Why is it that our app can work after enduring failure for a little while?
Investigating this further, I found that the RequestContextFilter was definitely being executed before the Oauth2ClientContextFilter and OpenIdConnectFilter when running locally. I decide to take a chance on M. Prokhorov's suggestion from the comments and register the RequestContextFilter into Spring Security's filters anyways; it extends the OncePerRequestFilter preventing it from executing more than once anyways.
All said and done, I went with the following modifications:
Removed the declaration of the RequestContextLister bean from the OpenIdConnectConfig. This was registered elsewhere in the application, in a parent module that I verified was getting configuration-scanned.
#Bean
public ServletListenerRegistrationBean<RequestContextListener> requestContextListener() {
return new ServletListenerRegistrationBean<>(new RequestContextListener());
}
Moved the Oauth2ClientContextFilter into a bean declaration. It doesn't seem like there's anything in this filter that relies on being populated as a Spring bean – in testing, the client configuration was attached to the UserRedirectRequiredException that this filter processes before the OAuth2RestTemplate (which does have the client configuration OAuth2ProtectedResourceDetails injected into it by Spring) throws it. However, it felt like defensive programming in case a future version of Spring changes the interplay between this filter, the exceptions it handles, and the OAuth client details.
Adding the filter to the HttpSecurity object in the WebSecurityConfigurerAdapter.configure() call in SecurityConfig.java. The final code for that class looked like this:
#Configuration
#EnableWebSecurity
#EnableOAuth2Client
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Override
#SuppressWarnings("unchecked")
protected void configure(HttpSecurity http)
throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.csrf()
.disable()
.authorizeRequests()
.expressionHandler(securityExpressionHandler)
.antMatchers("/asset/**").access("permitAll")
.antMatchers("/ws/ssoEnabled").access("permitAll")
.antMatchers("/**").access("hasRole('ROLE_USER') or hasRole('ROLE_TOKEN_ACCESS')")
.and()
.httpBasic()
.authenticationEntryPoint(ajaxAwareLoginUrlAuthenticationEntryPoint)
.and()
// OAuth filters
// Explicitly add a RequestContextFilter ahead of the Oauth filters to facilitate retrieval of a session-scoped oauth2ClientContext object
.addFilterAfter(requestContextFilter, SecurityContextPersistenceFilter.class)
// Handles unauthenticated requests, catching UserRedirectRequiredExceptions and redirecting to OAuth provider
.addFilterAfter(oAuth2ClientContextFilter, RequestContextFilter.class)
// Handles the oauth callback, exchanging the one-time code for a durable token
.addFilterAfter(openIdConnectFilter, OAuth2ClientContextFilter.class)
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/logincheck")
.usernameParameter("username")
.passwordParameter("password")
.successHandler(ajaxAwareAuthenticationSuccessHandler)
.failureHandler(ajaxAwareAuthenticationFailureHandler)
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
.and()
.rememberMe()
.rememberMeServices(rememberMeServices)
// Even though this key has been added directly to the rememberMeServices instance, the RememberMeConfigurer
// can instantiate a new RememberMeServices with a made-up key if the same key is not provided.
.key("the key value")
;
// We do not configure a bean for the SessionAuthenticationStrategy. We want to use the Spring default strategy,
// which is configured by the above builder chain. In order to share the correct, configured instance with our
// custom OpenIdConnectFilter, we first tell the builder to perform the configuration (normally this would be
// done long after this method returns)...
http.getConfigurer(SessionManagementConfigurer.class).init(http);
// ... then we get the shared object by interface (SessionAuthenticationStrategy) class name...
final SessionAuthenticationStrategy sessionAuthenticationStrategy = http.getSharedObject(SessionAuthenticationStrategy.class);
// ... then set it in our custom filter.
openIdConnectFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
}
}
public class ContextAwareCallable<T> implements Callable<T> {
private Callable<T> task;
private RequestAttributes context;
public ContextAwareCallable(Callable<T> task, RequestAttributes context) {
this.task = task;
this.context = cloneRequestAttributes(context);
}
#Override
public T call() throws Exception {
if (context != null) {
RequestContextHolder.setRequestAttributes(context);
}
try {
return task.call();
} finally {
RequestContextHolder.resetRequestAttributes();
}
}
private RequestAttributes cloneRequestAttributes(RequestAttributes requestAttributes) {
RequestAttributes clonedRequestAttribute = null;
try {
clonedRequestAttribute =
new ServletRequestAttributes(((ServletRequestAttributes) requestAttributes).getRequest(),
((ServletRequestAttributes) requestAttributes).getResponse());
if (requestAttributes.getAttributeNames(RequestAttributes.SCOPE_REQUEST).length > 0) {
for (String name : requestAttributes.getAttributeNames(RequestAttributes.SCOPE_REQUEST)) {
clonedRequestAttribute.setAttribute(name,
requestAttributes.getAttribute(name, RequestAttributes.SCOPE_REQUEST),
RequestAttributes.SCOPE_REQUEST);
}
}
return clonedRequestAttribute;
} catch (Exception e) {
return requestAttributes;
}
}
}
Then Create Executor
public class ContextAwarePoolExecutor extends ThreadPoolTaskExecutor {
#Override
public <T> Future<T> submit(Callable<T> task) {
return super.submit(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
}
#Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
return super.submitListenable(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
}
I have created a rest service in Jersey which is internally using Jackson for mapping JSON to Java Object. The whole Service works on Apache tomcat but however when i deploy it on weblogic 10.2.3 it is giving the below error
java.lang.NoSuchMethodError: org.domain.pojo.CreateOutput.pcsetErrorText(Ljava/lang/String;)V
at org.domain.pojo.CreateOutput.setErrorText(CreateEVCOutput.java)
at org.domain.serviceinterface.ExceptionMapper.toResponse(ExceptionMapper.java:14)
at com.sun.jersey.spi.container.ContainerResponse.mapException(ContainerResponse.java:480)
at com.sun.jersey.spi.container.ContainerResponse.mapMappableContainerException(ContainerResponse.java:417)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1477)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1419)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1409)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:409)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:558)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:733)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:301)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:184)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3732)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3696)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2273)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2179)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1490)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:256)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:221)
I am using Jersey 1.19 and weblogic 10.2.3 version.
Below is my service class POST method
#POST
#Path("/post")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public CreateOutput RequestCall(Wrapper createServiceInput) {
/*
* handling all the business logic
*/
CreateOutput serviceOutput = new CreateOutput();
serviceOutput.setErrorCode("200");
logger.info("Messafe Successfully Consumed without any exception");
serviceOutput.setErrorText("Xml passed successfully");
serviceOutput.setStatus("SUCCESS");
// return HTTP response 200 in case of success
return serviceOutput;
}
and below is my exception mapper custom class to handle exception
#Provider
public class MapperException implements ExceptionMapper<Throwable> {
CreateOutput createOutput = new CreateOutput();
public Response toResponse(Throwable e) {
createOutput.setErrorText(e.getMessage());
createOutput.setErrorCode(Status.PRECONDITION_FAILED.toString());
createOutput.setStatus("failure");
return Response.status(Status.PRECONDITION_FAILED).entity(createOutput).type("application/json").build();
}
}
Thanks in advance for your help !
I am reading through Beginning J2EE 7 - Antonio Gonclaves and going through the source code, I have encountered an exception "org.glassfish.hk2.api.UnsatisfiedDependencyException" which I'm finding hard to solve. Without any qualifiers the application works fine. I'm using Netbeans 7.3.1 and Glassfish 4.0. Below is my source code and exception log
These are my service classes which I'm using #Qualifiers to differentiate
#Stateless
#ISBNAlt
public class ISBNGenerator implements INumberGenerator{
#Override
public String generateNumberr() {
return "ISBN generated";
}
}
Second service class
#Stateless
#ISBNDef
public class ISSNGenerator implements INumberGenerator{
#Override
public String generateNumberr() {
return "Working version 2";
}
}
The resource class
#ManagedBean
#RequestScoped
#Path("/test")
public class TestClass {
#Inject #ISBNAlt
private INumberGenerator ng;
#Produces(MediaType.TEXT_PLAIN)
#GET
public String getValue()
{
return ng.generateNumberr();
}
}
and i use this class for adding resource classes
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
/**
*
* #author naphlin
*/
#ApplicationPath("webresource")
public class ApplicationConfig extends Application{
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<Class<?>>();
// following code can be used to customize Jersey 2.0 JSON provider:
try {
Class jsonProvider = Class.forName("org.glassfish.jersey.jackson.JacksonFeature");
// Class jsonProvider = Class.forName("org.glassfish.jersey.moxy.json.MoxyJsonFeature");
// Class jsonProvider = Class.forName("org.glassfish.jersey.jettison.JettisonFeature");
resources.add(jsonProvider);
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(getClass().getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
addRestResourceClasses(resources);
return resources;
}
/**
* Do not modify addRestResourceClasses() method.
* It is automatically re-generated by NetBeans REST support to populate
* given list with all resources defined in the project.
*/
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(helpers.TestClass.class);
}
}
After deploying my application and invoking the REST endpoint, i get this exception
Info: Initiating Jersey application, version Jersey: 2.0 2013-05-03 14:50:15...
Warning: StandardWrapperValve[config.ApplicationConfig]: Servlet.service() for servlet config.ApplicationConfig threw exception
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=INumberGenerator,parent=TestClass,qualifiers={#annotations.ISBNAlt()}),position=-1,optional=false,self=false,unqualified=null,1495563497)
at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)
at org.jvnet.hk2.internal.ClazzCreator.resolve(ClazzCreator.java:191)
at org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:214)
at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:311)
at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:448)
at org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:157)
at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2204)
at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:579)
at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:566)
at org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:172)
at org.glassfish.jersey.server.model.MethodHandler$ClassBasedMethodHandler.getInstance(MethodHandler.java:185)
at org.glassfish.jersey.server.internal.routing.PushMethodHandlerRouter.apply(PushMethodHandlerRouter.java:105)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:118)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:121)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:121)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:121)
at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:102)
at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:62)
at org.glassfish.jersey.process.internal.Stages.process(Stages.java:197)
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:215)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:198)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:946)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:323)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:372)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:218)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
at java.lang.Thread.run(Thread.java:745)
Any
Works on my machine ;o) No, actually I reproduced your code quickly with JBoss Forge. You can run the following JBoss Forge script if you want :
$ project-new --named testrest
$ rest-setup
$ cdi-setup
$ cdi-new-qualifier --named ISBNAlt --targetPackage org.testrest.util
$ cdi-new-qualifier --named ISBNDef --targetPackage org.testrest.util
$ java-new-interface --named INumberGenerator2 --targetPackage org.testrest.service
$ ejb-new-bean --named ISBNGenerator
$ ejb-new-bean --named ISSNGenerator
$ faces-setup
I deployed it on WildFly, and it's working fine. BTW, as simplification, you don't need #ManagedBean and #RequestScoped on your REST endpoint. Try to get rid of it and re-deploy on GlassFish. You can also give it a try on WildFly first.
I'm currently trying to develop a simple proof of concept for a REST application using CXF 2.6.4. I'm taking the non-spring approach. I'm using JBoss AS 7.1.1 Final as my web server.
The following is my web service class:
package restful.webservice;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import restful.entity.ControllerVersion;
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class WebServiceRest implements WebServiceInterface
{
#Override
#POST
#GET
#Path("/getVersion")
public ControllerVersion getVersion(String deviceID, String[] macAddresses)
{
return new ControllerVersion();
}
}
ControllerVersion class:
package restful.entity;
#XmlRootElement(name = "ControllerVersion")
public class ControllerVersion {
private String version="R1.1.0.0";
public String getVersion() {
return version;
}
}
Now, when I try to make a REST call to my web service, I get the following exception on the server side:
18:51:52,913 WARNING [org.apache.cxf.jaxrs.utils.JAXRSUtils] (http--0.0.0.0-8080-1) No message body reader has been found for request class String[], ContentType : application/json.
18:51:52,927 WARNING [org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper] (http--0.0.0.0-8080-1) javax.ws.rs.WebApplicationException
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:1054)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:614)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:578)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:238)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:89)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:262)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:236)
at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:209)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:154)
at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:130)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:225)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:145)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:201)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930)
at java.lang.Thread.run(Thread.java:662)
The libraries that I have under WEB-INF/lib are:
cxf-api-2.6.4.jar
cxf-bundle-2.6.4.jar
cxf-rt-frontend-jaxrs-2.6.4.jar
cxf-rt-frontend-jaxrs.jar
cxf-rt-transports-http-2.6.4.jar
geronimo-servlet.jar
jaxb-api-2.2.5.jar
jaxb-impl-2.2.5.1.jar
jaxb-xjc-2.2.5.1.jar
jettison-1.3.4.jar
log4j-1.2.16.jar
neethi-3.0.2.jar
xmlschema-core-2.0.3.jar
The interesting thing is that I tried to do another project, but this time in the signature of my web service method, I included a custom class. I had no problem reading the contents of the custom class' instance, nor a problem while returning it to my client.
Am I missing something?
UPDATE:
I tried to add the following to my web.xml:
<init-param>
<param-name>jaxrs.providers</param-name>
<param-value>
org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider
(writeXsiType=false)
</param-value>
</init-param>
And added the following dependencies as well:
jackson-jaxrs-1.9.2.jar
jackson-mapper-asl-1.9.2.jar
jackson-xc-1.9.2.jar
Now I'm getting the following exception:
19:22:29,762 WARNING [org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper] (http--0.0.0.0-8080-1) javax.ws.rs.WebApplicationException: java.io.IOException: Stream closed
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:243)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:89)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:262)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:236)
at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:209)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:154)
at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:130)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:225)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:145)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:201)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.io.IOException: Stream closed
at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:377)
at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:193)
at java.io.FilterInputStream.read(FilterInputStream.java:116)
at org.codehaus.jackson.impl.ByteSourceBootstrapper.ensureLoaded(ByteSourceBootstrapper.java:507)
at org.codehaus.jackson.impl.ByteSourceBootstrapper.detectEncoding(ByteSourceBootstrapper.java:129)
at org.codehaus.jackson.impl.ByteSourceBootstrapper.constructParser(ByteSourceBootstrapper.java:224)
at org.codehaus.jackson.JsonFactory._createJsonParser(JsonFactory.java:785)
at org.codehaus.jackson.JsonFactory.createJsonParser(JsonFactory.java:561)
at org.codehaus.jackson.jaxrs.JacksonJsonProvider.readFrom(JacksonJsonProvider.java:414)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:1038)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:614)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:578)
Update 2:
I tried to implement a method with a different signature, and this time, I have omitted the String array from the method:
public ControllerVersion getVersion(String deviceID)
Everything is working perfectly without the String array. What do you think I should do?
I apparently misunderstood how REST works. What I did to finally solve the problem was the following:
1- Changed my web service signature:
#POST
#Path("/getVersion")
#Produces(MediaType.APPLICATION_JSON)
#Consumes({"application/xml", "application/json", "application/x-www-form-urlencoded"})
public ControllerVersion getVersion(#FormParam("deviceID") String deviceID,#FormParam("macAddresses") String macAddresses)
2- Now, make sure that the client is sending a request with content-type (application/x-www-form-urlencoded) and that the client correctly adds form parameters same as those you defined in the #FormParam annotations.
3- Now, you can use a library such as FlexJson, to deserialize your parameters from a JSon String. For instance, I'm now sending the macAddresses as a JSon String: ["mac1","mac2"] from the client. On the server side, I convert this JSon string to a String[] using the following method:
public static String[] parseStringArrayFromJSONArray(String jsonArray)
{
String[] stringArray = null;
try
{
JSONArray array = new JSONArray(jsonArray);
if (array != null)
{
stringArray = new String[array.length()];
for (int i = 0; i < array.length(); i++)
{
stringArray[i] = array.getString(i);
}
}
} catch (Exception e)
{
stringArray = null;
}
return stringArray;
}
I hope this will help someone out there.
You're using #Consumes(MediaType.APPLICATION_JSON). You need to add jackson-core (and maybe some more jackson dependencies) for the conversion to work.
cxf uses jettison by default. Why do you have #GET and #POST annotations?
But it say's
java.io.IOException: Stream closed
So there is most likely an inputstream that isn't being shut down.
I want to have a configuration parameter injected this way:
public class MyManagedBean {
#Inject
public MyManagedBean(#Named("user") String user){
....
}
}
So I tried to implement a producer method this way:
#ApplicationScoped
public class MyConfiguration {
private Properties loadProperties() {
Properties properties = new Properties();
try {
properties.load(getClass().getResourceAsStream(
"user.properties"));
} catch (IOException e) {
throw new RuntimeException();
}
return properties;
}
#Produces
#Named("user")
String getUser() {
return loadProperties().getProperty("user");
}
}
I have other bean defined this way:
public class OtherManagedBean {
#Inject
public OtherManagedBean(MyManagedBean myManagedBean){
....
}
}
However, I'm having this exception when I try to deploy it:
INFO: WEB0671: Loading application [example-ear#example-war.war] at [example]
SEVERE: Exception while loading the app
SEVERE: Exception while loading the app : WELD-001410 The injection point [parameter 1] of [constructor] #Inject public com.example.OtherManagedBean(MyManagedBean) has non-proxyable dependencies
org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001410 The injection point [parameter 1] of [constructor] #Inject public com.example.OtherManagedBean(MyManagedBean) has non-proxyable dependencies
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:317)
at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:139)
at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:162)
at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:385)
at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:371)
at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:390)
at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:190)
at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:128)
at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:298)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:461)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:240)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:370)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:355)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:370)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1067)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1200(CommandRunnerImpl.java:96)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1247)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1235)
at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:465)
at com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:222)
at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:168)
at com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:117)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:234)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:822)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:719)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1013)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:662)
Any idea?
Thanks.
It looks like you need a default (no-arg) constructor for your MyManagedBean to make it proxyable. I am not really sure about why it is needed, since MyManagedBean is a #Dependent bean and so is not proxied AFAIK; I do not know even why a proxyable bean needs a default constructor, to be honest This seems to be an implementation detail or a little point from CDI specification that was ignored. Anyway, I bet it can make a good new question :)
EDIT: I discovered why a proxyable bean needs a default construction. It is no mistery, actually: since the proxy of a bean is a subclass of the same bean, the proxy needs to call a super() constructor in its own construction. If it has no non-private default constructor, it does not know which constructor to call. One can even imagine a scenario where the injected constructor is called to create the proxy, but I do not know which kind of complexity it can add to a CDI implementation; it may not be so easy to do...