GWT + Guice servlet Example

This downloadable maven project integrates GWT with Guice while you can define web scoped components by annotations. Guice Servlet provides a complete story for use in web applications and servlet containers. Guice’s servlet extensions allow you to completely eliminate web.xml from your servlet application and take advantage of type-safe, idiomatic Java configuration of your servlet and filter components.

This example has:

  • GWT (Google Web Toolkit),
  • Guice DI (@Inject),
  • Web scoped components (@Singleton, @SessionScoped, @RequestScoped )

The project structure:

struct

NOTE: This tutorial does not list all the files, but you can download working example at the bottom of the page.

Maven config

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>hu.daniel.hari.test</groupId>
    <artifactId>Tutorial-GuiceGWT</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <java.version>1.7</java.version>
        <gwt.version>2.6.1</gwt.version>
    </properties>

    <build>

        <plugins>
            <!-- maven compiler -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>

            <!-- maven surefire tests -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <skipTests>${surefire.skip}</skipTests>
                    <includes>
                        <include>**/*Test.java</include>
                    </includes>
                </configuration>
            </plugin>

            <!-- GWT plugin -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>gwt-maven-plugin</artifactId>
                <version>2.2.0</version>
                <dependencies>
                    <dependency>
                        <groupId>com.google.gwt</groupId>
                        <artifactId>gwt-user</artifactId>
                        <version>${gwt.version}</version>
                    </dependency>
                    <dependency>
                        <groupId>com.google.gwt</groupId>
                        <artifactId>gwt-dev</artifactId>
                        <version>${gwt.version}</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <webappDirectory>${project.build.directory}/gwt-webapp</webappDirectory>
                    <draftCompile>true</draftCompile>
                    <optimizationLevel>1</optimizationLevel>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <!-- WAR plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1.1</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                        </manifest>
                    </archive>
                    <webResources>
                        <resources>
                            <directory>${project.build.directory}/gwt-webapp</directory>
                        </resources>
                    </webResources>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>

        <!-- GWT -->
        <dependency>
            <groupId>com.google.gwt</groupId>
            <artifactId>gwt-user</artifactId>
            <version>${gwt.version}</version>
        </dependency>
        <dependency>
            <groupId>com.google.gwt</groupId>
            <artifactId>gwt-servlet</artifactId>
            <version>${gwt.version}</version>
        </dependency>

        <!-- GUICE servlet -->
        <dependency>
            <groupId>com.google.inject.extensions</groupId>
            <artifactId>guice-servlet</artifactId>
            <version>3.0</version>
        </dependency>

        <!-- Logger -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.3</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

    </dependencies>

</project>

We use guice-servlet to use guice in a web app, and to use web scopes.

Scoped components

Let’s define some scoped components.

AddressManager: @Singleton
ContentExporter: @RequestScoped
RequestCounter: @SessionScoped

AddressManager.java

@Singleton
public class AddressManager {

    .....

    public List<Address> getAddressList() {
        return new ArrayList<>(addressList);
    }

    public void addAddress(Address address) {
        addressList.add(address);
    }

    ......
}

ContentExporter.java

@RequestScoped
public class ContentExporter {
    private final AddressManager addressManager;

    @Inject
    public ContentExporter(
            AddressManager addressManager
            ) {
        this.addressManager = addressManager;
    }

    public void exportAddressList() {
        List<Address> addressList = addressManager.getAddressList();
        for (Address address : addressList) {
            log.info(address.addressString);
        }
    }

}

RequestCounter.java

@SessionScoped
public class RequestCounter {
    private int requestCount = 0;

    public void increase() {
        requestCount++;
    }
    public int getRequestCountWithinSession() {
        return requestCount;
    }
}

Service interface

Let’s define a service interface.

AppService.java

package hu.daniel.hari.learn.gwttest.ui.gwt.rpc;

import hu.daniel.hari.learn.gwttest.model.Address;

import java.util.List;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

@RemoteServiceRelativePath("appservice")
public interface AppService extends RemoteService {
    List<Address> getAddressList();
    void addAddress(Address address);
    void exportAddressList();
    void increaseRequestCountWithinSession();
    int getRequestCountWithinSession();
}

Service implementation

Let’s define the service implementation.

AppServiceImpl.java

package hu.daniel.hari.learn.gwttest.servlet;

import hu.daniel.hari.learn.gwttest.controller.requestscoped.ContentExporter;
import hu.daniel.hari.learn.gwttest.controller.sessionscoped.RequestCounter;
import hu.daniel.hari.learn.gwttest.controller.singleton.AddressManager;
import hu.daniel.hari.learn.gwttest.model.Address;
import hu.daniel.hari.learn.gwttest.ui.gwt.rpc.AppService;

import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;

@Singleton
public class AppServiceImpl extends RemoteServiceServlet implements AppService {

    @Inject
    /** SINGLETON **/
    private AddressManager addressManager;

    @Inject
    /** SESSION SCOPED **/
    private Provider<RequestCounter> requestCounterProvider;

    @Inject
    /** REQUEST SCOPED **/
    private Provider<ContentExporter> contentExporterProvider;

    @Override
    public List<Address> getAddressList() {
        return addressManager.getAddressList();
    }

    @Override
    public void addAddress(Address address) {
        addressManager.addAddress(address);
    }

    @Override
    public void exportAddressList() {
        contentExporterProvider.get().exportAddressList();
    }

    @Override
    public void increaseRequestCountWithinSession() {
        requestCounterProvider.get().increase();
    }

    @Override
    public int getRequestCountWithinSession() {
        return requestCounterProvider.get().getRequestCountWithinSession();
    }

}

Guice Config

AppModule.java

public class AppModule extends ServletModule {
    static final String CONTEXT_PATH_APPMODULE_APPSERVICE = "/appmodule/appservice";

    @Override
    protected void configureServlets() {
        //BIND LOGGER
        bind(Log.class).to(Log4JLogger.class);

        //CONFIGURE SERVLETS
        serve(CONTEXT_PATH_APPMODULE_APPSERVICE).with(AppServiceImpl.class);
    }
}

GWT Config

AppModule.gwt.xml

<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='appmodule'>

    <inherits name='com.google.gwt.user.User' />
    <inherits name='com.google.gwt.user.theme.clean.Clean' />

    <entry-point class='hu.daniel.hari.learn.gwttest.ui.gwt.AppEntryPoint' />

    <!-- Specify the paths for translatable code -->
    <source path='ui/gwt' />
    <source path='model' />

</module>

ServletContextlistener

AppGuiceServletContextListener.java

public class AppGuiceServletContextListener extends GuiceServletContextListener {

    @Override
    protected Injector getInjector() {
        return Guice.createInjector(
                new AppModule()
                );
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
    }
}

web.xml

web.xml

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">

    <!-- GUICE CONTEXT LISTENER -->
    <listener>
        <listener-class>hu.daniel.hari.learn.gwttest.boot.AppGuiceServletContextListener</listener-class>
    </listener>

    <!-- GUICE FILTER -->
    <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>

    <session-config>
        <session-timeout>5</session-timeout>
    </session-config>

</web-app>

Test the Page

testpage

2015/11/19 22:30:37 [INFO  ] AppServiceImpl - new
2015/11/19 22:30:37 [DEBUG ] AddressManager - new
2015/11/19 22:30:49 [DEBUG ] RequestCounter - new
2015/11/19 22:30:49 [DEBUG ] RequestCounter - increase
2015/11/19 22:30:49 [DEBUG ] AddressManager - getAddressList
2015/11/19 22:30:49 [DEBUG ] RequestCounter - getRequestCountWithinSession=1
2015/11/19 22:30:54 [DEBUG ] AddressManager - getAddressList
2015/11/19 22:30:54 [DEBUG ] RequestCounter - increase
2015/11/19 22:30:54 [DEBUG ] RequestCounter - getRequestCountWithinSession=2
2015/11/19 22:31:00 [DEBUG ] RequestCounter - increase
2015/11/19 22:31:00 [DEBUG ] AddressManager - getAddressList
2015/11/19 22:31:00 [DEBUG ] RequestCounter - getRequestCountWithinSession=3
2015/11/19 22:31:07 [DEBUG ] AddressManager - addAddress Address [addressString=Test1]
2015/11/19 22:31:07 [DEBUG ] AddressManager - getAddressList
2015/11/19 22:31:10 [DEBUG ] ContentExporter - new
2015/11/19 22:31:10 [DEBUG ] ContentExporter - exportAddressList
2015/11/19 22:31:10 [DEBUG ] AddressManager - getAddressList
2015/11/19 22:31:10 [INFO  ] ContentExporter - 2600 Vác, Damjanich u.1
2015/11/19 22:31:10 [INFO  ] ContentExporter - 8600 Szeged, Diófa u. 39
2015/11/19 22:31:10 [INFO  ] ContentExporter - 3300 Eger, Faiskola út 15.
2015/11/19 22:31:10 [INFO  ] ContentExporter - 3000 Hatvan, Horváth Mihály út 18.
2015/11/19 22:31:10 [INFO  ] ContentExporter - Test1
2015/11/19 22:31:15 [DEBUG ] ContentExporter - new
2015/11/19 22:31:15 [DEBUG ] ContentExporter - exportAddressList
2015/11/19 22:31:15 [DEBUG ] AddressManager - getAddressList
2015/11/19 22:31:15 [INFO  ] ContentExporter - 2600 Vác, Damjanich u.1
2015/11/19 22:31:15 [INFO  ] ContentExporter - 8600 Szeged, Diófa u. 39
2015/11/19 22:31:15 [INFO  ] ContentExporter - 3300 Eger, Faiskola út 15.
2015/11/19 22:31:15 [INFO  ] ContentExporter - 3000 Hatvan, Horváth Mihály út 18.
2015/11/19 22:31:15 [INFO  ] ContentExporter - Test1

Test session scope as request counter is increased every time you refresh the page.
Test request scope as pushing Export button.

Setup and run GWT Project in eclipse

This is a maven project, but to proper setup a debuggable gwt project in eclipse you have to do additional setup in project properties. After your setup, you will be able to run this project from eclipse in GWT development mode, that allows you on the fly debugging in GWT client code.
These steps are documented in: GWT Eclipse setup.docx

To use Classic GWT Development mode, you will have to download firefox 24.0 that you can get from here:
http://pcforum.hu/letoltes/3029/firefox+24.html

References:
https://code.google.com/p/google-guice/wiki/GettingStarted
http://www.scottmcmaster365.com/2012/10/adding-guice-to-gwt-sample-application.html

This tutorial does not list all the files, but you can
download working example from here:

Written by Dániel Hári

Dániel Hári is the founder of log4jtester.com, cleancodejava.com. Who is an enthusiastic Java developer who enhances his knowledge by continously searching for best practices and modern technologies. Engaged to clean coding, and honors the engineering profession as releasing quality work.