Fork me on GitHub

WOInject is a dependency injection framework for WebObjects based on Google Guice.

Introduction

WOInject is an extension of the Google Guice framework created to enable the use of dependency injection with WebObjects applications and frameworks. Dependency injection (DI) is a useful technique for program modularization leading to more testable code. WOInject allows to write better APIs and decoupled code reducing the hurdle of wiring things together.

Google Guice is a lightweight framework for dependency injection. Its key features include type safe binding configuration, scopes and basic AOP. If you're not familiar with Guice, check the Guice's User Guide, the Bob Lee talk and Dhanji Prasanna presentation. If you want a complete reference on the subject, read the Dependency Injection book from Dhanji Prasanna.

Why Dependency Injection?

DI and programming by interfaces are techniques that lead to more testable and decoupled code.

WOInject Setup

It is simple to initialize the application with WOInject. Update the Application class to extend the InjectableApplication (line 6). Then initialize the applicaiton using the WOInject.init method (line 8).

package my.app;

import com.woinject.InjectableApplication;
import com.woinject.WOInject;

public class Application extends InjectableApplication {
    public static void main(String[] args) {
        WOInject.init("my.app.Application", args);
    }
    ...
}

IMPORTANT: the application class name cannot be obtained programmatically (for example, Application.class.getName()). No WebObjects core classes should be loaded before the WOInject initialization.

Loading Guice configuration modules is also straightforward. The modules method of the InjectableApplication class can be overridden to return an array of modules to be loaded by the injector.

public class Application extends InjectableApplication {
    ...
    @Override
    protected Module[] modules() {
        return new Module[] { new MyModule() };
    }
}

The Session and Request Scopes

Scopes is one of the best features provided by Guice. It let change the lifecycle of objects easily with a simple configuration modification. Guice provides the @Singleton annotation that can be used to create objects that are instantiated once per injector and reused whenever needed. No special code is required to instantiate the object as a singleton. If you want to change the object's lifecycle behavior just change the scope, and it's done.

WOInject contributes two scopes: WORequest scope and WOSession scope. Scopes can be configured in bind statements (lines 5 and 8):

public class MyModule extends AbstractModule {
	...
	protected void configure() {
		bind(Formatter.class).to(NotThreadSafeFormatter.class)
			.in(WORequestScoped.class);

		bind(Config.class).to(ConfigImpl.class)
			.in(WOSessionScoped.class);
	}
}

Alternatively, it's possible to specify the scope for a type by applying the scope annotation to the implementation class directly (line 1).

@WORequestScoped
public class SimpleFormatter implements Formatter {
	...
}

The @Current Annotation

There are certain situations where WebObjects logic requires the current WOContext. WOInject provides the @Current annotation and automatically binds the existing WOContext object. The current context can be injected like this:

public class AnyObject {
	@Inject @Current
	private WOContext context;
	...
}

The same annotation can be used to inject the current session. It supports the WOSession, ERXSession or Session (yes, the session class of your application) types.

Deploying on Servlet Environments

Using WOInject on servlet environments is also possible. In order to initialize WOInject correctly, the WOInjectServletContextListener must be loaded earlier in the context of servlet applications. Add the following snippet into the application's web.xml to load the WOInject servlet context listener:


	com.woinject.servlet.WOInjectServletContextListener

Limitations

Conclusion

Guice is a powerful framework for dependency injection. WOInject incorporates Guice features into WebObjects applications in a simple and non intrusive form allowing for dependency injection in a type safe manner.