My perspective on Atinject
Back in February, a discussion flared up over Guice's lack of support for industry-standard annotations. James Strachan described the problem succinctly:So my show stopper issue with ever adopting & recommending Guice is to be able to use IoC framework agnostic annotations for lifecycle & injection (JSR 250/EJB3 for starters, @Resource, @PostConstruct, @PreDestroy - you could throw Spring/WebBeans/JAX-RS/JAXWs in there too really but JSR250/EJB3 is the tip of this massive iceberg). i.e. so that my application code can be used by Spring or Guice IoC containers without having to double-annotate everything (using JSR 250 and Guice annotations) or using JSR 250 annotations then forcing producer methods for every class I write to be written by users using Guice.
In response to the immediate issue, Guice got support for custom injectors. And we're planning an API for lifecycle callbacks.
Unfortunately, the current annotations aren't really sufficient. @Resource precludes immutability. It lacks a compiler-checked way to qualify a type. And it lacks a mechanism for lazy or multiple injection.
Since @Resource is mostly a non-starter, each of the established containers defines its own annotations:
public class TweetsClient {
@Autowired
@com.google.inject.Inject
@org.apache.tapestry5.ioc.annotations.Inject
public TweetsClient(OpenIdCredentials credentials,
HttpConnectionFactory connectionFactory) {
...
}
}
The differences between these are superficial. There just aren't many ways to mark an injection point!
To unity their annotations, the established Java dependency injection vendors collaborated on a new API to serve as a common standard. The entire API is five annotations (including @Inject) plus Provider for lazy/multiple injection.
The spec enables class portability. Your classes can be used with any injector: annotate implementation class once to support all of Spring, Guice, PicoContainer, Tapestry IoC, and Simject.
But the new standard does not cover injector configuration. The lack of standardized configuration hurts application portability, because you must reconfigure for each injector.
Configuration was left out because there's no consensus on the best way to do it. Unlike annotations, each injector takes a distinct approach, each with relative strengths and weaknesses. For example, consider this (simplified) matrix:
Injector | XML etc. | Code | Annotations | Notes |
---|---|---|---|---|
Spring | ✔ | optional | optional | |
Guice | ✔ | ✔ | ||
Butterfly | ✔ | has its own DSL | ||
JSR 299 | ✔ | ✔ | plus classpath scanning | |
PicoContainer | ✔ | ✔ |
I'm excited about the new proposal because it's pragmatic. It paves the well-worn paths (the annotations), but permits innovation to foster elsewhere. Fantastic work guys!