Our goal is to create a swap-in replacement for Plexus built on top of Guice. Ideally this should be done without changing the core Guice code, but if this is not possible then any fixes or new functionality should be written up and reported on the Guice issues page. While there is no guarantee that these changes will make it into an official Guice release, improvements that benefit a wider audience should have a better chance of making it into Guice.
Sonatype currently maintains a patched build of Guice trunk with the following major patches:
This build also contains some experimental changes which have not yet been written up because they are still being tested:
The solution is separated into re-usable, pluggable modules that together provide a replacement for the existing Plexus container. There is also an artifact that combines these modules into a single JAR, as this would make it easier to swap between the old and new container. Each module has a specific responsibility and any dependencies between modules is kept at a minimum. The following is a list of the components or modules that comprise the Guice/Plexus integration project.
Guice is a Dependency Injection framework that injects constructors, methods, and fields annotated with @Inject. Guice recognizes both the JSR 330 and the original Guice form of this annotation.
Every injection point (constructor, method, or field) has a number of dependencies, each one represented by a key: the type to be injected plus an optional qualifier annotation that lets you choose between different implementations of the same type. For example:
public class Car { // Injectable constructor @Inject public Car(Engine engine) { ... } // Injectable field @Inject @Named("Corinthian Leather") private Seat seat; // Injectable package-private method @Inject void install(Windshield windshield, Trunk trunk) { ... } }
Has the following injection points and dependency keys:
Constructor ---> Key[ Engine ] Field "seat" ---> Key[ Seat, @Named( "Corinthian Leather" ) ] Method "install" ---> Key[ Windshield ], Key[ Trunk ]
The Guice injector maintains a set of bindings that map dependency keys to providers that supply instances of the key type. These providers may use different strategies to supply instances: per-lookup, singleton, per-conversation, even your own custom strategies.
When you configure Guice you are registering bindings from one key to another, or between keys and providers:
// Key[ Seat ] ---> Key[ FoamSeatImpl ] bind( Seat.class ).to( FoamSeatImpl.class ); // Key[ Seat, @Named( "Corinthian Leather" ) ] ---> Key[ LeatherSeatImpl ] bind( Seat.class ).annotatedWith( Names.named( "Corinthian Leather" ) ).to( LeatherSeatImpl.class ); // Key[ Engine ] ---> Key[ V8EngineImpl ] bind( Engine.class ).to( V8EngineImpl.class ); // Key[ V8EngineImpl ] ---> Provider[ V8EngineImpl, "singleton" ] bind( V8EngineImpl.class ).in( Singleton.class ); // Key[ Windshield ] ---> Provider[ Windshield, "custom" ] bind( Windshield.class ).toProvider( WindshieldProvider.class ); // Key[ Trunk ] ---> Provider[ TrunkImpl, "constant" ] bind( Trunk.class ).toInstance( new TrunkImpl() );
The injector can also create certain types of bindings on-demand when no such explicit binding already exists, such as:
// Key[ FoamSeatImpl ] ---> Provider[ FoamSeatImpl , "per-lookup" ] // Key[ LeatherSeatImpl] ---> Provider[ LeatherSeatImpl, "per-lookup" ]
The Key[...] and Provider[...] markup is pseudo-code |
So far so good, but what if you have classes that don't mark dependencies with @Inject? What if they're identified in XML or marked with custom annotations like @Requirement or @Configuration?
Since 2.0 Guice has provided a way to supplement the core injection process with your own custom injections. Here's what you need to do:
You'll notice that Guice does not dictate how each type should be scanned or prepared for custom injection. While Guice does provide utility methods that can tell you which class members are annotated with @Inject, there's no general-purpose mechanism to scan class members looking for custom annotations. On the one hand this is good, because it avoids bloating the core JAR with code you might not need. But on the other hand each custom injection client could end up implementing similar scanning code again and again. The recommended approach is to put optional code like this in an extension library that people can use if they need to, rather than keep folding it into the core.
We're going to use custom injection to support Plexus components whose dependencies may be annotated or configured in XML. Plexus components are similar to Java beans in that they can have fields or setter methods, so rather than write a custom injector that's closely tied to Plexus let's see if we can develop an extension library for "beans" in general. That way we can build support for Plexus on top of it, and allow people to re-use it for other bean-style injections.