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.
DI and programming by interfaces are techniques that lead to more testable and decoupled code.
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() }; } }
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 { ... }
@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.
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
WOContext
class must be bound with an annotation. The WOInject framework already binds the existing WOContext using the @Current
annotation.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.