Guice in Java Web Application

Google’s Guice framework promises to be a lightweight(!) Inversion-of-Control (IoC) container.

Advantages compared to Spring:

  • Spring is much more than an IoC container, and therefore overkill for many projects.
  • Configuration by code. NO XML.

Based on my previous post showing how to use AngularJS with a Java RESTful backend I extended the simple demo application to use Guice.

Let’s say we have a UserServiceImpl class which depends on a UserFactory interface. The UserFactory interface is injected into the constructor of the UserServiceImpl class.

The only thing we have to do is add the @Inject annotation to the constructor so that Guice can do its job.

package ngdemo.service.impl;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import ngdemo.domain.User;
import ngdemo.service.contract.UserFactory;
import ngdemo.service.contract.UserService;

import java.util.List;

public class UserServiceImpl implements UserService {

    private final UserFactory userFactory;

    @Inject
    public UserServiceImpl(UserFactory userFactory) {
        this.userFactory = userFactory;
    }

    @Override
    public List<User> getDefaultUsers() {
        return this.userFactory.createUsers();
    }

    @Override
    public User getDefaultUser() {
        return this.userFactory.createUser();
    }

}

For the IoC container to know which implementation to inject we have to create a Guice Module which derives from AbstractModule:

package ngdemo.infrastructure;

import com.google.inject.AbstractModule;
import ngdemo.service.contract.UserFactory;
import ngdemo.service.contract.UserService;
import ngdemo.service.impl.UserFactoryImpl;
import ngdemo.service.impl.UserServiceImpl;

public class UserModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(UserFactory.class).to(UserFactoryImpl.class);
        bind(UserService.class).to(UserServiceImpl.class);
    }
}

The UserModule class demonstrates the advantage of Guice vs. Spring: NO XML. When using Spring you normally would have to create Spring beans in an XML file like this:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

	<bean id="userService" class="ngdemo.service.impl.UserServiceImpl">
		<constructor-arg ref="userFactory"/>
	</bean>
	
	<bean id="userFactory" class="ngdemo.service.impl.UserFactoryImpl" />
		
</beans>

Next we have to create a replacement for the servlets required by the servlet container:

package ngdemo.infrastructure;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.servlet.GuiceServletContextListener;
import com.google.inject.servlet.ServletModule;
import com.sun.jersey.api.core.PackagesResourceConfig;
import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;

public class NgDemoApplicationSetup extends GuiceServletContextListener {

    @Override
    protected Injector getInjector() {

        return Guice.createInjector(new ServletModule() {

            @Override
            protected void configureServlets() {

                super.configureServlets();

                // Configuring Jersey via Guice:
                ResourceConfig resourceConfig = new PackagesResourceConfig("ngdemo/rest");
                for (Class<?> resource : resourceConfig.getClasses()) {
                    bind(resource);
                }
                serve("/rest/*").with(GuiceContainer.class);
            }
        }, new UserModule()); // <-- Adding other Guice Dependency Injection Modules
    }
}

And finally the file web.xml:

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app id="WebApp_ID" version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.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>ngdemo.infrastructure.NgDemoApplicationSetup</listener-class>
    </listener>
</web-app>

The file web.xml is now free of any <servlet> tags. The only thing that has to be configured in XML is the <listener-class>. The value of the <listener-class> is our Java class NgDemoApplicationSetup, so all further configuration can be defined in a type safe manner.

You can clone a copy of this project here: https://github.com/draptik/angulardemorestful.

To checkout the correct version for this demo, use the following code:

git clone git@github.com:draptik/angulardemorestful.git
cd angulardemorestful
git checkout -f step2-guice

In case you are not using git you can also download the project as ZIP or tar.gz file here: https://github.com/draptik/angulardemorestful/releases/tag/step2-guice

comments powered by Disqus