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 {

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:

InjectorXML etc.CodeAnnotationsNotes
Butterfly has its own DSL
JSR 299 plus classpath scanning

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!
Just to clarify one aspect:

In Spring, externalized XML based configuration, internal or invasive annotations (i.e. @Autowired, @Resource), and externalized annotations (@Configuration, @Bean, which are available in Spring 3 out of the box, and were previously in the separate JavaConfig project) are all full "citizens" w/respect to specifying dependency injection configuration. Spring works with a metadata representation of the configuration internally, so you can not say that one is necessarily more prefered or optional than the others, as your table would imply.

People can chose whatever mix of XML config, internal annotations, and externalized annotation based config that makes sense for their particular needs...

For anybody interested in trying the externalized annotation based configuration that has moved into Core Spring from the JavaConfig project, the best way is to download the Spring 3.0 M3 milestone that has just come out:

Thanks Colin. My main motivation with the table was to show the minimum configuration needed to put a real app into production.

With Spring, you can get by on XML alone. JSR 299 needs both XML and annotations. And Guice requires both code and annotations.
Hi Jesse,

I agree that multiple annotations are bane and introduce duplication. But I fear that the atInject as of this moment is overly simplistic and does not address all possible scenarios.

For example: can a single Inject annotation inject two constructor arguments with single annotation or if constructor arguments are passed by the instance rather than the injector (something like assistedinject).

I just blogged my viewpoint here: