Google Guice, Classpath scanning, automatic Beans binding and Module installation

Veröffentlicht: September 6, 2010 in Automatic Binding for Guice, Java
Schlagwörter:, , , , , ,

Today I wanted to share a new Proof-of-Concept of mine.

I’m working for an ECM company, which often faces to create new Integration for customers or in other products. Some months ago I created a http-based Interfaces for a customer. To give it a general touch, I decided to make it highly configurable, so it can be used for more projects.

This led me to the Command- and Chain of Responsibility-Pattern. I created a mechanism to configure the steps, which are taken when a new document should be archived. These Plugins (Java Classes) are annotated, so I can find them at runtime.

You ask yourself now, what does it have to do with Google Guice?

I started the project without Dependency Injection and used Reflections (http://code.google.com/p/reflections/), to scan my Classpath for my plugins. Due the fact that I have vacations and have to look after my son (15 months), I started to investigate a little bit to learn GWT and Guice.

I really like the idea of the Guice ESL to bind all my stuff, but for a project like mine where I need configurable bindings, this doesn’t fit. So I started to search for Classpath Scanners for Guice and found a project created by Sonatype.

This project did exactly what I want. It scans my classpath and informs me about Classes and its annotations. The problem was that just for scanning the footprint was to much and there were some design decisions which I don’t like.

So I created the “Guice Automatic Injection”-Project, with a small Classpath Scanner which uses ASM to load and inspect classes. I also created some interfaces, so I can use Reflections or Sonatype as a Scanner, too.

After a lot of experiments, I found my way how to do it. I created some listeners.

Number 1: Installs all Google Guice Modules, which are annotated with @GuiceModule

@GuiceModule
public class ExampleModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(Example.class).to(ExampleImpl.class);
    }
}

I use this Annotation in cases, where AutoBind doesn’t fit or where I have fixed bindings. The advantage is, I can spread several bindings about multiple Modules and I don’t have to specify each of them, when creating an Injector.

Number 2: Binds all Bean, which are annotated with @AutoBind

@AutoBind(name = "Example", bind={Example.class, ExampleImpl.class})
public class ExampleImpl implements Example {
    @Override
    public String sayHello() {
        return "yeahhh!!!";
    }
}

The name- and bind-Attribute for the @AutoBind are optional. Each class which is annotated with @AutoBind will be bound:

binder().bind(Example.class).to(ExampleImpl.class)

If you specify the name-Attribute, this will lead to a named binding:

binder().bind(Example.class).annotatedWith(Names.named(annotation.name())).to(ExampleImpl.class)

If you specify the bind-Attribute, you can overwrite the Interfaces, which will be used for binding. If not, the Class will be bound to all implemented Interfaces.

So and what is missing?
How to start my Application? :)

public class ExampleApp {
	public static void main(String[] args) throws IOException {
		Injector injector = Guice.createInjector(new StartupModule(VirtualClasspathReader.class, "de.devsurf"));
		DynamicModule dynamicModule = injector.getInstance(DynamicModule.class);
		injector = injector.createChildInjector(dynamicModule);

		System.out.println(injector.getInstance(Example.class).sayHello());
	}
}

So the only difference to the normal Guice start is, that you have to use the StartupModule. The StartupModule binds your chosen ClasspathScanner-Implementation and Packages. With this new Injector, you have to get an Instance of a Class which is bound to the DynamicModule-Interface. (This is also done by the StartupModule, which will bind the ScannerModule to it.) With that Module you can create a new child Injector, which have all Beans annotated with @AutoBind and all Modules annotated with @GuiceModule installed.

At the moment you can choose between my own Classpath Scanner which uses ASM to inspect Classes, the Reflections- or the Sonatype-API.

We are using the first Injector instance to create and inject our ScannerModule. We have to do it this way, because we can only inject Objects, if the Injector was created completely. You don’t have the chance to inject Objects, will still installing a Module.

I’m still at the beginning of the project. So if you are interested in improving it, write me a Mail. :)

The Source Code is available at: http://github.com/manzke/guice-automatic-injection
Statistics can be found at: https://www.ohloh.net/p/guice-auto-injection

TODO: Maven Release

Bye,
Daniel

About these ads

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ photo

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s