Monday, March 18, 2013

Dependency Injection: @Resource, @Inject, @Autowired

Overview

When using Spring there's the choice of 3 annotations for injecting resources with advantages and disadvantages:
  1. @Autowired
    The original, "proprietary" annotation from Spring.
    - not standard, Spring proprietary
    + resolves by type
    + for optional dependencies 
  2. @Resource
    The JSR-250 annotation
    + standard dependency injection
    - resolves by name, fallback by type
    - not for optional dependencies 
  3. @Inject
    The JSR-330 annotation
    + resolves by type
    + standard dependency injection

    + for optional dependencies (- slightly different API) 

Injection by type or by name

When the @Resource annotation was introduced, I switched to it to not have Spring as a hard dependency. I never used dependency resolving by name, and relied on the fallback by type. This bit me a couple of times with code like:

@Resource
private SomeVeryDescriptiveClassName className;

when a class with the name ClassName existed because then that was injected, or attempted to be injected.

Now I'll switch from @Resource to the newer @Inject which does exactly what I want.

Optional dependencies

Unfortunately, both of the standard Java DI annotations lack the attribute that @Autowired provided: @Autowired(required=false)

Every couple of months I find myself in the situation where I really need an optional dependency. Not having exactly one implementation throws (having multiple and using the @Qualifier annotation works too).

An example is an interface provided by a framework, and the userland code may provide an implementation if desired.

Without optional injections one way to solve this is with the "priority" int. I use this concept when multiple implementations of an interface might exist, maybe including a system provided default implementation, and only the most important one should be used:

public interface Foo {
  int getPriority();
  void doSomething();
}

Each implementation returns a number, and the highest one wins in the injection:

@Inject
private void setFoos(List foos) {
  //choose
}

I prefer to keep it short, and thus kept using the proprietary @Autowired annotation in these rare cases. But @Inject has its way for handling this too (thanks to rliesenfeld's comment):

@Inject Instance< Foo> fooSource;
Foo foo = fooSource .get(); //returns null or the instance

Unfortunately you need Java EE for the Instance interface.

Conclusion

@Inject is what I'll use in general from now on, and what probably most situations ask for.

This blog post shows the differences of dependency injection (by type or by name, with @Qualifier) in detail.

Note: To use the @Inject annotation the following dependency is required:
<dependency>
  <groupId>javax.inject</groupId>
  <artifactId>javax.inject</artifactId>
  <version>1</version>
</dependency>

The import for the Instance interface is from Java EE:
import javax.enterprise.inject.Instance;

2 comments:

  1. Optional dependencies are supported in CDI (@Inject), by using the "Instance" interface. See http://docs.jboss.org/weld/reference/latest/en-US/html/injection.html#lookup

    ReplyDelete
    Replies
    1. Great! I've updated the blog post and my programming style thanks to your comment.

      Delete