About Bryn

Just some guy to likes to code.

CDI for Guice users

I am a Guice user who also uses CDI, I like both, but starting firmly in the Guice camp left me confused about how to effectivly use CDI.

The problem was that although Guice and CDI are both dependency injection frameworks, they require a slightly different mindset which means you have to organise your projects differently. Don't expect your Guice application to work in CDI without modification, and moving from CDI to Guice is likely to be painful. 

The Guice way

With Guice you are in complete control over how your application is configured, although defaulting is possible, if you need to specify an explicit implementation you can do so via a module in your bootstrap class.

Guice configuration uses a fluent configuration API to achive application specific configuration. This is great if you do a lot of refactoring as the configuration gets refactored along with the rest of your code.

For example, here we have an application that is creating a starship:

Although TranswarpDrive and WarpDrive are available implementations of engines, we are specifying that we want to use WarpDrive.

Advantages

  • Great refactoring support.
  • It's easy to see how injection is configured.

The CDI way

With CDI you must let the container take control over what is being injected. If you've been using Guice this will seem unnatural, like letting a plane fly itself, but it the idea is that CDI components should automatically configure themselves as much as possible.

This is fine, except that when converting a Guice application to CDI for the first time you will probably encounter something like:

The fundemental difference between CDI and Guice is that everything on the classpath is a candidate for injection, and the CDI container will tell you if there is an ambiguous injection. In this case if we ask for an Engine the CDI container can't tell which implementation to use.

There are a couple of ways to remedy this situation:

Using alternatives

If you have several implementations of a class then you can annotate them with the @Alternative annotation. Any class annotated with @Alternative can be specified in META-INF/benas.xml, if it is then it will override other implementations on the classpath.

In our example, if WarpDrive was annotated with @Alternative then it would be OK for TranswarpDrive to be on the classpath.

Using Maven

If you are prepared to split your implementations into different maven artifacts then you can use Maven to select the implementation that you want to use. This is more applicable to library developers, you can leave it to the client to select what implementation they want to use by including it as a dependency in the pom.

In our example, if Engine, WarpDrive and TranswarpDrive are all in different artifacts, then using the pom we can select to just have the WarpDrive on the classpath. The CDI container doesn't know anything about TranswarpDrive.

CDI sounds like a step backwards, but it isn't

At this point I was wondering why on earth I should be using CDI instead of Guice, the use of XML for alternatives instead of the Guice fluent config feels very wrong. However after working with CDI for a while I realised that it wasn't a problem:

  • CDI aware components configure themselves – If a component is CDI aware then you generally just include them on the classpath and start injecting the services you need. No module required.
  • Alternatives should hardly ever be used  Instead if the different implementations are required at runtime then use @Instance.
  • CDI extensions are first class citizens – With CDI an extension can hook directly into the container injection mechanism, with Guice you only get the opportunity to inject after guice has had first dibs.
  • Lifecycle support – Lack of lifecycle support in Guice lifecycle support is sometimes problematic for applications that require a clean shutdown.
  • It's the standard – Like it or not, CDI is the default dependency injection that'll be bundled in with modern application servers, at some point you'll find it easier to just write the code to put food on the table rather than worrying about what library is doing dependency injection.

Don’t get me wrong, I am still a big fan of Guice, and and there are still cases where Guice wins on simplicity and performance, just think of CDI as another tool in the toolbox.

CDI Unit testing needs some Guice

There is one fly in the ointment when using CDI. During unit testing you usually want to replace an implementation with an alternative implementation for testing or mock. Using Guice I would create an injector for my unit tests that had the appropriate configuration. However, simply firing up the JavaSE Weld implementation won't work because:

  • Everything on the classpath gets included in the container, of you have some code that listens to the startup event then this can slow down running the test.
  • There is no opportunity to reconfigure what is being injected without modifying you main application code.

Instead you need to be able to configure what goes into CDI container for the unit test in a similar way that you would with Guice. Take a look at these projects to see how it's done:

Post to Twitter

CDI-Unit 0.9.8 released

After having failed to get CDI-Unit released in two weeks, I have finally got round to adding some javadocs and doing another release. The user guide is also now fairly detailed, but could always do with some improvement.

The thing that got me in to gear was that some kind soul added a couple of issues to the bug tracker, the effect of knowing that someone is trying your code and finding issues creates a desire to fix things, after all it is my code that is on show.

Apart from javadocs the only other change is Weld 1.0.1 users will get a nice error message when trying to run a CDI-Unit test. Weld 1.0.1 did not contain the necessary extension points to enable CDI unit to function.

 

Post to Twitter

CDI-Unit 0.9.6 released!

Added support for specifying alternatives using annotations.

I still need to fill out all the javadocs and get the everything reviewed before releaseing 1.0.0. In particular I am unhappy with the naming of the annotations: SupportClasses, TestAlternative and TestAlternatives as they are not sufficiently capture their purpose. It is likely that these names will change in the next release.

Post to Twitter

Programmer Karma

I am a big fan of open source, but not in the way it is supposed to be. I often take but rarely give.

In 2005 I worked for a company called Decisionsoft in Oxford. This company contained many smart people and I learnt two major principles that I have used in my career ever since:

  1. Reuse before create – If someone else has created a solution to a problem then chances are they will have invested far more time thinking about the problem than you have. Don't waste your time reinventing a car if you want to get from A to B.
  2. Test early, test often – Don't want to discover that your product is broken a week before release? Unit testing and continuous integration testing will save you late nights at the office.

Open source has given me countless libraries and soft ware that I use all day every day, for free… but I have not been a good citizen of the open source community. Sometimes I submit bug reports, on occasion I will find the root of the problem and suggest an approach for a fix, but patches are pretty much non-existent. I feel bad.

So now I have decided to try and change my ways, starting with a small contribution that will be useful to those who are trying to unit test CDI applications. If I concentrate then it will be ready in a week or two.

Many thanks to my current employer (Carbon Hero Ltd) for supporting this project.

Post to Twitter