Last Updated
Viewed 12 Times
           

According to guice servlet doc, I should be able to use Guice servlets in a webapp as long as I setup guice filters and configure GuiceServletContextListener. The thing is that I want to use full programmatic approach (e.g. using tomcat.addContext instead of tomcat.addWebapp) with embeddable tomcat without web.xml, and I am having trouble setting it up.

My Main.java looks like below.

public class Main {
    private static String CONTEXT_PATH = "";
    public static void main(String[] args) throws LifecycleException {
        Tomcat tomcat = new Tomcat();
        String docBase = new File(".").getAbsolutePath();

        Context context = tomcat.addContext(CONTEXT_PATH, docBase);

        context.addApplicationListener(CustomGuiceServletContextListener.class.getName());

        context.addFilterDef(getGuiceFilterDef());
        context.addFilterMap(getGuiceFilterMap());

        tomcat.setPort(8080);
        tomcat.start();
        tomcat.getServer().await();
    }

    private static FilterMap getGuiceFilterMap() {
        FilterMap guiceFilterMap = new FilterMap();
        guiceFilterMap.setFilterName("guice");
        guiceFilterMap.addURLPattern("/*");
        return guiceFilterMap;
    }

    private static FilterDef getGuiceFilterDef() {
        FilterDef guiceFilterDef = new FilterDef();
        guiceFilterDef.setFilterName("guice");
        guiceFilterDef.setFilterClass("com.google.inject.servlet.GuiceFilter");
        guiceFilterDef.setFilter(new GuiceFilter());
        return guiceFilterDef;
    }
}

CustomGuiceServletContextListener.java

public class CustomGuiceServletContextListener extends GuiceServletContextListener {

    @Override
    protected Injector getInjector() {
        return Guice.createInjector(new ServletModule() {
            @Override
            protected void configureServlets() {
                serve("/*").with(PingServlet.class);
            }
        });
    }
}

PingServlet.java

@Singleton
public class PingServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("ping!");
        resp.getWriter().flush();
    }
}

If I run the program, the tomcat server successfully starts, but my browser only gets 'HTTP Status 404 – Not Found' error when I connect to the server. Is there something that I am missing that I have to add to either context or tomcat to make it work? I am new to tomcat so I might be unaware of certain setup that I have to do.

Below are logs generated by Tomcat when browser connects to it. As you can see, it seems that tomcat receives the request, but it cannot pass the request to my custom guice servlet context listener.

00:18:00.670 [http-nio-8080-exec-1] DEBUG - org.apache.juli.logging.DirectJDKLog - Received [GET / HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng;q=0.8,application/signed-exchange;v=b3
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9;q=0.8,es;q=0.7
Cookie: G_AUTHUSER_H=0

]
00:18:00.681 [http-nio-8080-exec-1] DEBUG - org.apache.juli.logging.DirectJDKLog - Set query string encoding to UTF-8
00:18:00.686 [http-nio-8080-exec-1] DEBUG - org.apache.juli.logging.DirectJDKLog - Cookies: Parsing b[]: G_AUTHUSER_H=0
00:18:00.688 [http-nio-8080-exec-1] DEBUG - org.apache.juli.logging.DirectJDKLog - Security checking request GET /
00:18:00.689 [http-nio-8080-exec-1] DEBUG - org.apache.juli.logging.DirectJDKLog -   No applicable constraints defined
00:18:00.700 [http-nio-8080-exec-1] DEBUG - org.apache.juli.logging.DirectJDKLog - Loading persistent provider registrations from [C:\Users\user\workspace\service\tomcat.8080\conf\jaspic-providers.xml]
00:18:00.701 [http-nio-8080-exec-1] DEBUG - org.apache.juli.logging.DirectJDKLog -  Not subject to any constraint
00:18:00.708 [http-nio-8080-exec-1] DEBUG - org.apache.juli.logging.DirectJDKLog - Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@7997a754:org.apache.tomcat.util.net.NioChannel@4d4fdca9:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:4790]], Read from buffer: [0]
00:18:00.713 [http-nio-8080-exec-1] DEBUG - org.apache.juli.logging.DirectJDKLog - Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@7997a754:org.apache.tomcat.util.net.NioChannel@4d4fdca9:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:4790]], Read direct from socket: [0]
00:18:00.714 [http-nio-8080-exec-1] DEBUG - org.apache.juli.logging.DirectJDKLog - Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@7997a754:org.apache.tomcat.util.net.NioChannel@4d4fdca9:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:4790]], Status in: [OPEN_READ], State out: [OPEN]
00:18:00.714 [http-nio-8080-exec-1] DEBUG - org.apache.juli.logging.DirectJDKLog - Pushed Processor [org.apache.coyote.http11.Http11Processor@5a8cf651]
00:18:00.715 [http-nio-8080-exec-1] DEBUG - org.apache.juli.logging.DirectJDKLog - Registered read interest for [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@7997a754:org.apache.tomcat.util.net.NioChannel@4d4fdca9:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:4790]]

I am using tomcat-embed-core 8.5.49 if that matters.

Edit

If I add the following two lines in the main method during Tomcat/context initialization, everything suddenly works. While the below mapping points the given default servlet (btw, it works with any stub servlet) to /, that config gets ignored, and what I configured in my GuiceServletContextListener seems to be prioritized first.

        // Default servlet
        Tomcat.addServlet(context, "default", "org.apache.catalina.servlets.DefaultServlet"); //any servlet works as a dummy placeholder
        context.addServletMappingDecoded("/", "default");

Does embeddable Tomcat require at least 1 mapping to be added before it can start serving request? It seems abnormal that presence of above two lines makes the difference. Is there a way that I can solve the problem without having to add above irrelevant two lines?

I have just started using Google Guice with my Tomcat webapp, and have noticed the following in the catalina.out file whenever the WAR file is undeployed:

May 16, 2011 5:37:24 PM org.apache.catalina.startup.HostConfig checkResources INFO: Undeploying context [/app]

May 16, 2011 5:37:24 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads SEVERE: A web application appears to have started a thread named [com.google.inject.internal.util.$Finalizer] but has failed to stop it. This is very likely to create a memory leak.

May 16, 2011 5:37:24 PM org.apache.catalina.loader.WebappClassLoader clearThreadLocalMap SEVERE: A web application created a ThreadLocal with key of type [null] (value [com.google.inject.internal.InjectorImpl$1@10ace8d]) and a value of type [java.lang.Object[]] (value [[Ljava.lang.Object;@7e9bed]) but failed to remove it when the web application was stopped. To prevent a memory leak, the ThreadLocal has been forcibly removed.

Does anyone know what causes this, or how I can stop it from happening?

I have only followed the instructions from here http://code.google.com/docreader/#p=google-guice&s=google-guice&t=ServletModule

... and haven't done anything fancy with it yet. I just have 2 servlets and a filter.

Thanks!

I am developing a simple application using Jersey 1.x, Guice and trying to run on Tomcat.

I used Guice filter and Guice Listener along with Resources and Application.

Below is my web.xml :

<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>
    <display-name>Guice Listener</display-name>
    <listener-class>com.simple.application.GuiceListener</listener-class>
</listener>

And using GuiceListener I injected all my dependencies,

public class GuiceListener extends GuiceServletContextListener {
    private Injector injector;

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        try {
            super.contextDestroyed(servletContextEvent);
        } finally {
            injector = null;
        }
    }

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        injector = Guice.createInjector(new SimpleServlet());
        super.contextInitialized(servletContextEvent);
        injector.injectMembers(this);
    }

    @Override
    protected Injector getInjector() {
        return injector;
    }
}

And This is how my Servlet looks

public class SimpleServlet extends JerseyServletModule {
    @Override
    protected void configureServlets() {
        configureGuiceServlet();
    }

    private void configureGuiceServlet() {
        bind(SimpleResource.class).in(Scopes.SINGLETON);
        serve("/service/*").with(GuiceContainer.class);
        bind(Manager.class).to(ManagerImpl.class);
    }
}

And I created a resource with a GET method,

@Path("/stuff")
public class SimpleResource {
    private final ManagerImpl manager;

    @Inject
    public SimpleResource(final ManagerImpl manager) {
        this.manager = manager;
    }

    @GET
    @Path("{id}")
    @Produces(MediaType.TEXT_HTML)
    public String submitData(@PathParam("id") final String id) {
        String welcomeScreen = manager.getWelcomeScreen();
        return "This is" + welcomeScreen + id;
    }
}

I used Constructor Injection for injecting classes.

And this is how my application looks

public class SimpleApplication extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        return ImmutableSet.<Class<?>>builder()
            .add(SimpleResource.class)
            .build();
    }
}

I am deploying this on Tomcat 7 and when I try to hit the application endpoint, I am getting 404,

http://localhost:9999/simple-0.0.1-SNAPSHOT/service/stuff/id

I can see in the logs that all the classes are instantiated successfully.

These are the dependencies in my pom.

    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-server</artifactId>
        <version>1.18.6</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>com.sun.jersey.contribs</groupId>
        <artifactId>jersey-guice</artifactId>
        <scope>compile</scope>
        <version>1.18.6</version>
    </dependency>
    <dependency>
        <groupId>com.google.inject.extensions</groupId>
        <artifactId>guice-servlet</artifactId>
        <scope>compile</scope>
        <version>3.0</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <scope>provided</scope>
        <version>2.5</version>
    </dependency>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <scope>compile</scope>
        <version>14.0</version>
    </dependency>
</dependencies>

Is there anything that I am missing as far as Tomcat with guice?

I'm trying to configure Guice and I'm getting this problem when I deploy the war file into Tomcat :

17-Jul-2016 15:11:55.238 SEVERE [RMI TCP Connection(2)-127.0.0.1] org.apache.catalina.core.StandardContext.listenerStart Exception lors de l'envoi de l'évènement contexte initialisé (context initialized) à l'instance de classe d'écoute (listener) ca.products.services.InjectorListener
 java.lang.NoClassDefFoundError: com/google/inject/internal/guava/base/$Preconditions
    at com.google.inject.servlet.ServletModule.configure(ServletModule.java:46)
    at com.google.inject.AbstractModule.configure(AbstractModule.java:59)
    at com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:223)
    at com.google.inject.spi.Elements.getElements(Elements.java:101)
    at com.google.inject.internal.InjectorShell$Builder.build(InjectorShell.java:133)
    at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:103)
    at com.google.inject.Guice.createInjector(Guice.java:95)
    at com.google.inject.Guice.createInjector(Guice.java:72)
    at com.google.inject.Guice.createInjector(Guice.java:62)
    at ca.products.services.InjectorListener.getInjector(InjectorListener.java:13)
    at com.google.inject.servlet.GuiceServletContextListener.contextInitialized(GuiceServletContextListener.java:47)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4738)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5181)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:725)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:701)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717)
    at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1678)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:463)
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:413)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
    at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1471)
    at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76)
    at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1312)
    at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1404)
    at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:832)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:323)
    at sun.rmi.transport.Transport$1.run(Transport.java:200)
    at sun.rmi.transport.Transport$1.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$256(TCPTransport.java:683)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ClassNotFoundException: com.google.inject.internal.guava.base.$Preconditions
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1333)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1167)
    ... 56 more

Here is the content of my web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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_2_5.xsd">
  <display-name>Restful Web Application</display-name>


  <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>ca.products.services.InjectorListener</listener-class>
  </listener>
</web-app>

Here is my InjectorListener :

public class InjectorListener extends GuiceServletContextListener {
    @Override
    protected Injector getInjector() {
        return Guice.createInjector(new RestModule());
    }
}

And here the RestModule Class :

public class RestModule extends JerseyServletModule {

    @Override
    protected void configureServlets() {

        HashMap<String, String> params = new HashMap<>();
        params.put(PackagesResourceConfig.PROPERTY_PACKAGES, "ca.products.services");
        params.put(JSONConfiguration.FEATURE_POJO_MAPPING, "true");
        params.put(ResourceConfig.FEATURE_DISABLE_WADL, "true");

        serve("/*").with(GuiceContainer.class, params);
    }
}

Any idea ?

Similar Question 6 (1 solutions) : Google Guice MethodInterceptor under Tomcat 8.5

Similar Question 7 (1 solutions) : How to get Google Guice working with JaxRS (Jersey)

Similar Question 8 (2 solutions) : How to serve JSPs using Guice 3.0?

cc