Announcement Announcement Module
Collapse
No announcement yet.
Request scoped bean can't get injected HttpServletResponse, but HttpServletRequest ok Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Request scoped bean can't get injected HttpServletResponse, but HttpServletRequest ok

    I must be doing something wrong. Can someone please point me in the right direction?

    I have a bean that is request scoped.

    It has two collaborators I want injected:
    HttpServletRequest (which works)
    HttpServletResponse (which fails)

    Here is my bean:
    <bean id="sessionFactory" class="com.example.web.SessionRequiring$SessionFac tory" scope="request">
    <aop:scoped-proxy/>
    </bean>

    Here are the autowired fields:
    @Autowired HttpServletRequest request;
    @Autowired HttpServletResponse response;

    Can I inject the response object in this bean?

    This is the error.
    [INFO] Caused by: org.springframework.beans.factory.BeanCreationExce ption: Error creating bean with name 'scopedTarget.sessionFactory': Autowiring of fields failed; nested exception is org.springframework.beans.factory.BeanCreationExce ption: Could not autowire field: javax.servlet.http.HttpServletResponse com.example.web.SessionRequiring$SessionFactory.re sponse; nested exception is org.springframework.beans.factory.NoSuchBeanDefini tionException: No unique bean of type [javax.servlet.http.HttpServletResponse] is defined: Unsatisfied dependency of type [interface javax.servlet.http.HttpServletResponse]: expected at least 1 matching bean
    [INFO] at org.springframework.beans.factory.annotation.Autow iredAnnotationBeanPostProcessor.postProcessAfterIn stantiation(AutowiredAnnotationBeanPostProcessor.j ava:243)


    Thanks in advance!

  • #2
    I wrote a simpler example of a request scoped bean (with request and response as autowired properties) and tried injecting it into a request scoped controrller. I got the same exception.

    So, now I'm looking at all the registered beans and trying to find if there is a spring wrapper like WebRequest that I can inject.

    Comment


    • #3
      I'm reasonably certain I cannot out of the box inject an HttpServletResponse object into a request-scoped collaborator.

      I navigated to GenericWebApplicationContext, which delegates to WebApplicationContextUtils.registerWebApplicationS copes(beanFactory), which then registers ServletRequest.class and HttpSession.class as injectable.

      I'm going to forgo using the spring out of the box capabilities, and instead look at building my own filter or interceptor to stash request and response into a threadlocal, which is referenced in my own BeanFactory, and use that to allow injection throughout other request-scoped beans.

      Comment


      • #4
        So here's what I did, which works for me:

        In web.xml add a filter that will store every ServletResponse in a threadlocal, which will be accessible only from your FactoryBean.
        Code:
          <filter>
                <filter-name>responseInScopeFilter</filter-name>
                <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
                <init-param>
                    <param-name>targetBeanName</param-name>
                    <param-value>responseInScopeFilter</param-value>
                </init-param>
            </filter>
          <filter-mapping>
                <filter-name>responseInScopeFilter</filter-name>
                <url-pattern>/*</url-pattern>
            </filter-mapping>
        Create the filter:
        Code:
            /**
             * We need a filter to capture the HttpServletResponse object such that it can be injectable elsewhere in request scope.
             */
           public static class ResponseInScopeFilter implements Filter {
                private ThreadLocal<HttpServletResponse> responses = new ThreadLocal<HttpServletResponse>();
                public void init(FilterConfig filterConfig) throws ServletException { }
        
                public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
                    HttpServletResponse response = (HttpServletResponse) servletResponse;
                    responses.set(response);
                    chain.doFilter(servletRequest, servletResponse);
                    responses.remove();
                }
        
                /** Only to be used by the BeanFactory */
                private HttpServletResponse getHttpServletResponse() {
                    return responses.get();
                }
        
                public void destroy() { }
            }
        And also create the FactoryBean:
        Code:
         /** We need our own FactoryBean because Spring does not offer a way to
             * inject request scoped HttpServletResponse objects.
             * See http://forum.springsource.org/showthread.php?p=298179#post298179 */
            public static class HttpServletResponseFactoryBean implements FactoryBean {
                @Autowired ResponseInScopeFilter responseInScopeFilter;
        
                public Object getObject() throws Exception {
                    return responseInScopeFilter.getHttpServletResponse();
                }
        
                public Class getObjectType() {
                    return HttpServletResponse.class;
                }
        
                public boolean isSingleton() {
                    return false;
                }
            }
        Wire it all together in applicationContext.xml
        Code:
        <bean id="httpServletResponse" class="com.example.web.SessionRequiring$HttpServletResponseFactoryBean" scope="request"/>
            <bean id="responseInScopeFilter" class="com.example.web.SessionRequiring$ResponseInScopeFilter"/>
        Elsewhere I can now inject an HttpServletResponse object and it will be request scoped appropriately for this request.

        Comment


        • #5
          Well I am not so good with Spring things but still I think there is one more practical solution to this problem.
          1. Create a Class which will have this Response Object
          public class MyHttpResponse {

          *** private HttpResponse response;

          ** private static ThreadLocal<MyHttpResponse > tLocal = new ThreadLocal<MyHttpResponse >();

          *** public static void set(MyHttpResponse myHttpResponse ) {
          *** *** tLocal.set(myHttpResponse );
          *** }

          *** public static RunTime get() {
          *** *** return tLocal.get();
          *** }
          public void setHttpResponse( HttpResponse response) {
          *** *** this.response= response;
          *** }

          *** public HttpResponse gettHttpResponse() {
          *** *** return response;
          *** }
          }
          ***
          2. Now in the class where you have got hold of Response Object say in any Filter class do some thing like this
          MyHttpResponse myHttpResponse = new MyHttpResponse ();
          *** myHttpResponse.setHttpResponse(response);

          3. And now finally where you need this Response object you can fetch it like below
          MyHttpResponse myHttpResponse = MyHttpResponse.get();
          ***** HTTResponse response = myHttpResponse.gettHttpResponse();

          // use response as you like here

          Comment


          • #6
            Some tips of improvement

            Hey.

            I had a similar problem. I had a few aspects that needed to set some HTTP headers.
            I needed therefor access to the response object.

            One problem with you solution is that you say:
            HttpServletResponse response = (HttpServletResponse) servletResponse;

            This is not a true statement.


            Spring supplies you with an interface called HandlerInterceptor. You can easily create a service that implements
            it and then load that bean into your DefaultAnnotationHandlerMapping

            (I believe that you are interested in the preHandle method)

            Code:
            	<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
            		<property name="interceptors">
            			<list>
            				<ref bean="myInterceptor"/>
            			</list>
            		</property>
            	</bean>

            Comment

            Working...
            X