Tuesday, March 13, 2007

Simple comparison with the two DI containers, Seasar and Guice

Lightweight DI container, Guice 1.0 has been released. This news draws remarkable attention of Japanese Java developers who use DI container in their products. While Seasar(http://www.seasar.org/en/), which has been developed by Japanese Java programmers, is a de fact DI container and is used broadly in Japan. To study how I can write a code using Guice, I rewrote the example introduced in Seasar's quick start tutorial(http://s2container.seasar.org/en/DIContainer.html#Quickstart) and compaired two types of programs reinforced by a DI containter.

The two programs I wrote show a simple well-known message, "Hello World!" and inject two implemented classes in each series of codes. In my programs, a GreetingClient type object uses a Greeting type object, and the implementation classes of Greeting and GreetingClient are injected. When I wrote codes for Guice, Paul Barry's blog(http://paulbarry.com/articles/2007/03/12/guice-hello-world) helped me a lot.

First three codes, Greeting.java, GreetingImpl.java and GreetingClinet.java are identical for both Seasar and Guice are utilized.

//Greeting.java
public interface Greeting {
String greet();
}

//GreetingImpl.java
public class GreetingImpl implements Greeting {

public GreetingImpl() {
}

public String greet() {
return "Hello World!";
}
}

//GreetingClient.java
public interface GreetingClient {
void execute();
}

However, the implementation class of GreetingClient for Guice has an @Inject annotation to inject the implementation for the Greeting type class, while it is still POJO as a Seasar's code.

//GreetingClientImpl.java for Guice
import com.google.inject.Inject;

public class GreetingClientImpl implements GreetingClient {
private Greeting greeting;

public GreetingClientImpl() {
}

public void execute() {
System.out.println(greeting.greet());
}

@Inject
public void setGreeting(Greeting greeting) {
this.greeting = greeting;
}
}

//GreetingClientImpl.java for Seasar
public class GreetingClientImpl implements GreetingClient {

private Greeting greeting;

public void setGreeting(Greeting greeting) {
this.greeting = greeting;
}

public void execute() {
System.out.println(greeting.greet());
}
}

Besides, I wrote the class to inject the implementation of GreetingClient, whereas the role of this class might be performed by a Dicon file for Seasar. The Dicon is an XML file and defines dependencies, adds intercepting classes and more.

//GreetingController.java for Guice
import com.google.inject.Inject;

public class GreetingController {
private GreetingClient greetingClient;

public GreetingController() {
}

public void execute() {
greetingClient.execute();
}

@Inject
public void setGreetingClient(GreetingClient greetingClient) {
this.greetingClient = greetingClient;
}
}

//GreetingMain2.dicon
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC
"-//SEASAR//DTD S2Container 2.3//EN"
"http://www.seasar.org/dtd/components23.dtd">
<components>
<component name="greeting"
class="examples.di.impl.GreetingImpl"/>
<component name="greetingClient"
class="examples.di.impl.GreetingClientImpl">
<property name="greeting">greeting
</component>
</components>

Main classes for Guice and Seasar are as follows.

// Main.java for Guice
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.Guice;

public class Main {

public Main() {
Injector injector = Guice.createInjector(new GreetingModule());
GreetingController controller = new GreetingController();
injector.injectMembers(controller);
controller.execute();
}

public static void main(String[] args) {
new Main();
}

private class GreetingModule extends AbstractModule {
protected void configure() {
bind(Greeting.class).to(GreetingImpl.class);
bind(GreetingClient.class).to(GreetingClientImpl.class);
}
}
}

// Main.java for Seasar
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;

public class GreetingMain2 {

private static final String PATH =
"examples/di/dicon/GreetingMain2.dicon";

public static void main(String[] args) {
S2Container container =
S2ContainerFactory.create(PATH);
GreetingClient greetingClient = (GreetingClient)
container.getComponent("greetingClient");
greetingClient.execute();
}
}

Comparting two series of code powered by Guice and Seasar, I assured Guice is configuration free DI container. It is convenient, flexible and easy to understand. However, today's DI containers are not merely a DI container. They have additional useful features such as utility classes of logging, exception handling, integration to other products and etc. I wonder people who are accustomed to other DI container and have many codes depends on it can start to use Guice soon.

Anyway, Guice programming dosen't require to write XML based configuration file and is probably easy to use(I'm note sure because I just wrote one simple application).At least, it is a great advantage for users who newly started to use DI containers.