I'm using tomcat 6, jersey 1.8 with jersey guice and guice 3. I'm having problem using JSP with my setup. I have a "Status" servlet served as a simple servlet configured by web.xml, a jersey servlet configured by GuiceFilter which returns a jsp view response (jsp is /diff/index.jsp) to render the result as in:
Viewable view = new Viewable("/diff/index.jsp", null);
Response response = Response.ok().entity(view).build();
return response;
It all works perfectly with simple Jersey, once I'm trying to have it with Guice integration the JSP fails and I'm getting a 404 response with "The requested resource (/diff/index.jsp) is not available."
Using the debugger I can see that the JSPTemplateProcessor as called and got a RequestDispatcher with a StandardWrapper that has "isJspServlet = true" and "jspFile = null".
<servlet>
<display-name>Status Page</display-name>
<servlet-name>Status</servlet-name>
<servlet-class>my.BaseStatusPage</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Status</servlet-name>
<url-pattern>/Status/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/REST/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>my.GuiceServletConfig</listener-class>
</listener>
=====================
GuiceServletConfig:
public class GuiceServletConfig extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
return Guice.createInjector(new JerseyServletModule() {
@Override
protected void configureServlets() {
bind(DiffPage.class);// the jersey servlet
Map<String, String> params = new HashMap<String, String>();
params.put(PROPERTY_PACKAGES, "my");
params.put(PROPERTY_WEB_PAGE_CONTENT_REGEX, ".*\\.jsp");
params.put(FEATURE_REDIRECT, "true");
params.put(FEATURE_IMPLICIT_VIEWABLES, "true");
params.put(RESOURCE_CONFIG_CLASS, "com.sun.jersey.api.core.PackagesResourceConfig");
serve("/REST/*").with(GuiceContainer.class, params);
}
});
}
=====================
Having GuiceContainer as a filter made the servlets served from the web.xml fail. Adding a jsp servlet in web.xml didn't do much good.
Btw, I've read the thread from Jul 25, 2010 at the jersey mailing list but it didn't work for me.
Help appreciated Thanks, Eishay
-- Appendix -- I find myself calling JSP from the business logic code. Ugly but works:
protected Response renderJsp(HttpServletRequest request,
HttpServletResponse response, ServletConfig servletConfig) {
request.setAttribute("org.apache.catalina.jsp_file", "/diff/index.jsp");
Class jspServletClazz;
try {
jspServletClazz = forName("org.apache.jasper.servlet.JspServlet");
Object jspServlet = jspServletClazz.getConstructor().newInstance();
jspServletClazz.getMethod("init", ServletConfig.class).invoke(jspServlet,
servletConfig);
jspServletClazz.getMethod("service", HttpServletRequest.class,
HttpServletResponse.class).invoke(jspServlet, request, response);
} catch (Exception e) {
throw new RuntimeException(e);
}
return Response.ok().build();
}
The problem is due to configuring Guice to "serve" requests "with" a Servlet: The Servlet blocks the request chain and prevents requests such as static content and jsp calls from being passed onwards to the default handlers.
The solution is to configure Guice to "filter" requests "through" a Filter instead:
web.xml
<listener>
<listener-class>my.guice.config.package.GuiceServletConfig</listener-class>
</listener>
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Note this is a filter
configuration as opposed to a servlet
configuration.
GuiceServletConfig
public class GuiceServletConfig extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
return Guice.createInjector(new JerseyServletModule() {
@Override
protected void configureServlets() {
/* Bindings */
bind(JerseyResource.class);
/* Parameters*/
Map<String, String> params = new HashMap<String, String>();
params.put(JSP_TEMPLATES_BASE_PATH, "/WEB-INF/jsp");
params.put(FEATURE_FILTER_FORWARD_ON_404, "true");
filter("/*").through(GuiceContainer.class, params);
}
});
}
}
Note the use of filter().through();
instead of serve().with();
.
This allows static and jsp requests (and includes!) to be passed onto the next link in the filter chain, and eventually to the default content handlers.
Also note the use above of the more recent ServletContainer.FEATURE_FILTER_FORWARD_ON_404
option as an alternative to the more complex ServletContainer.PROPERTY_WEB_PAGE_CONTENT_REGEX
option for when you're happy with the default locations for your static content.
You can still use the other options listed in the original question.
For the next step, you can also refer to this question specifically involving a problem I had with adding Guice AOP into this configuration to work alongside Guice Dependency Injection, Jersey REST Services, Static Content (JavaScript, CSS, Images) and returning JSP Viewables.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With