Search code examples
javajettyembedded-jettyguice-servletcode-separation

Runnable war with jetty+guice


This is a question about better separating the code for embedding jetty from the code for wiring up servlets.

I am trying to adapt this sample code such that I will be getting a runnable war, i.e. a war file that I can drop into an existing Jetty container, or run standalone using a command like java -jar webapp-runnable.war. The sample code belongs to these two blog posts: No.1, No.2.

I followed the GuiceServlet manual and created a web.xml and GuiceServletContextListener (see below), but they don't seem to get me very far with mvn jetty:run; When I try to run mvn jetty:run, I get the following error:

[main] DEBUG org.eclipse.jetty.util.log - Logging to Logger[org.eclipse.jetty.util.log] via org.eclipse.jetty.util.log.Slf4jLog
WARN:oejw.WebAppContext:main: Failed startup of context o.e.j.m.p.JettyWebAppContext@3cceafcb{/,file:/[...]/src/main/webapp/,STARTING}{file:/[...]/src/main/webapp/}
com.google.inject.ConfigurationException: Guice configuration errors:||1) Explicit bindings are required and com.google.inject.servlet.InternalServletModule$BackwardsCompatibleServletContextProvider is not explicitly bound.|  while locating com.google.inject.servlet.InternalServletModule$BackwardsCompatibleServletContextProvider||1 error
    at [stack strace clipped]

Here's my code. As mentioned before, I started with this repo on github.

1) I extracted the anonymous inner class of type AbstractModule from com.teamlazerbeez.http.HttpServerMain and put it into a new class com.teamlazerbeez.http.HttpServerModule. This class is now instantiated when creating the Guice Injector in HttpServerMain (l36).

2) My web.xml:

<?xml version="1.0" ?>
<web-app
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    metadata-complete="false"
    version="3.0">

    <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>
    <listener>
        <listener-class>com.teamlazerbeez.http.GuiceServletConfig</listener-class>
    </listener>
</web-app>

3) My com.teamlazerbeez.http.GuiceServletConfig:

public class GuiceServletConfig extends GuiceServletContextListener {

    @Override
    protected Injector getInjector() {
        //I know this code not come close to doing what I want, but I just don't know where to start
        return Guice.createInjector(new HttpServerModule());
    }

}

My question: How can I refactor the HttpServerMain main method and HttpServerModule in such a way that the setup process described by them becomes usable to my GuiceServletConfig? And what must GuiceServletConfig look like for this to work?


Solution

  • I never got a war working as jar, so I always go for one of the two solutions. However, when using a war, its not hard to setup a embedded Jetty server that works in your IDE. To do that you can use a WebAppContext to set it up using a web.xml. See this documentation for an example. From there, everything should work as advocated on the Guice site.

    However, this will not create a runnable war (like java -jar yourapp.war) because jars have a different internal layout. However, if you want to you can use the jetty-runner to fix this using java -jar jetty-runner.jar yourapp.war.