tags:

views:

233

answers:

1

I've configured my GWT app with Guice as documented here. With this setup the app works fine.

However what I'd like to do now is get a GWTTestCase to call a service using GWT RPC. To this end I've done this,

  • Updated my <app>JUnit.gwt.rpc so that the service URL maps to GuiceRemoteServiceServlet
  • Added an init() method to GuiceRemoteServiceServlet to initialise the Injector as per this comment

Unfortunately I'm still getting an error,

com.google.inject.ProvisionException: Guice provision errors:

Caused by: com.google.inject.OutOfScopeException: Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.
    at com.google.inject.servlet.GuiceFilter.getContext(GuiceFilter.java:132)
    at com.google.inject.servlet.GuiceFilter.getRequest(GuiceFilter.java:118)
    at com.google.inject.servlet.InternalServletModule$1.get(InternalServletModule.java:35)
.....

The object it's trying to provision is ServletContext. The cause of the error is due to the fact the GuiceFilter hasn't been called so the ServletContext hasn't been bound to ThreadLocal.

Is there any way of getting past this?

A: 

In the Junit environment you aren't getting two things that you normally get from the servlet container: the setup/destroy help from the GuiceServletContextListener and the filtering of the GuiceFilter, so you need to do these bits yourself.

You basically need to create another servlet that wraps your servlet and does all the setup/filtering that you'd normally see done by the servlet container; what I recommend is something like this:

Suppose your servlet is called AdriansGuicedGwtServiceServlet. Then create this in your testing directory:

public class TestAdriansGuicedGwtServiceServlet extends AdriansGuicedGwtServiceServlet {
  private GuiceFilter filter;

  @Override
  public void init() {
    super.init();

    // move your injector-creating code here if you want to
    // (I think it's cleaner if you do move it here, instead of leaving
    //  it in your main servlet)

    filter = new GuiceFilter();
    filter.init(new FilterConfig() {
      public String getFilterName() {
        return "GuiceFilter";
      }

      public ServletContext getServletContext() {
        return TestAdriansGuicedGwtServiceServlet.this.getServletContext();
      }

      public String getInitParameter(String s) {
        return null;
      }

      public Enumeration getInitParameterNames() {
        return new Vector(0).elements();
      }
    });
  }

  @Override
  public void destroy() {
    super.destroy();
    filter.destroy();
  }

  private void superService(ServletRequest req, ServletResponse res)
      throws ServletException, IOException {
    super.service(req, res);
  }

  @Override
  public void service(ServletRequest req, ServletResponse res) 
      throws ServletException, IOException {
    filter.doFilter(new FilterChain() {
      public void doFilter (ServletRequest request, ServletResponse response)
          throws IOException, ServletException {
        superService(request, response);
      }
    });
  }
}

And then in your <app>Junit.gwt.rpc have it map in TestAdriansGuicedGwtServiceServlet instead of your real servlet.

Daniel Martin
Great answer Daniel. Thanks very much. Worked perfectly.
Adrian