; last updated - 4 minutes read

These days I've discovered a nice feature of CDI. What do you make of this code?

@Inject @Any Instance validators;

Instance indicates that a single object is injected, but that's quite the case. In my case the program uses the Instance like so:

for(IValidator validator:validators){ validator.validate(); }

Obviously, @Inject Instance<IValidator> does something completely different than @Inject IValidator.

As it turns out, you can do several things with @Inject Instance<T>. First of all, it doesn't inject anything. At least not the way you might expect it to do. The injection is deferred until the object is used. So, the first thing you can use @Inject Instance<T> to gain some extra performance. You pay this extra performance with a few keystrokes. Instead of simply writing validators.validate() you have to write validators.get().validate.

Performance gain or performance penalty?

However, if you're concerned about performance, you should use @Inject Instance<T> with caution. Thing is, the dependency is resolved at runtime (as opposed to being resolved at injection time). In other words, it's resolved each time you call the get() method. Which results in a performance penalty. So, you should think about caching the results. Read Romain Manni-Bucau's article for more details.

On the other hand, the nice thing about @Inject Instance<T> is that you gain a lot of flexibility. For instance, your program can act intelligently to different deployment scenarios. For instance, imagine you were to write a library using object of a certain type. Consider the example at the beginning of this article. It deals with validators, but it copes with any number of implementations. More precisely, it doesn't matter, if your application contains one, two or more implementations of the interface. Or, for what it's worth, if there's no matching implementation at all.

Multiple matches

The application I'm currently working on uses this feature to validate the user input against a flexible set of validators. All you have to do is to implement a @Named bean implementing the interface IValidator. That's enough to make sure the user input is validated against your new validator. That, in turn, is because the line @Inject @Any Instance<IValidator> catches every matching IValidator.

@Inject Instance isn't limited to a single implementation. It discovers every matching implementation. If you use the get() method, this is boiled down to one and only one implementation, raising an exception if there's no implementation, or if the implementation is ambiguous, but get() isn't the only way to use it. First of all, the Instance is an Iterator. In other words, you can use it in a for loop.

Flexible reaction to different deployment scenarios

Second, you can check beforehand if there's no implementation at all (Instance::isUnsatisfied) or if there's more than one implementation (Instance::isAmbiguous()). If you don't use Instance, both situations result in an exception. Instance allows you to react in a flexible way to these situations.

Reacting to changing requirements at runtime

@Inject @Any @Instance<T> doesn't stop there. There's a select method allowing you to filter the result set at runtime. This comes in handy if the bean type or qualifiers vary dynamically at runtime. If that sound sophisticated to you: that's a common scenario when you think of configuration files allowing the operations department to configure the behavior of your application.

Wrapping it up

What starts as a minor change - just adding the Instance keyword to the variable declaration of an attribute populated by CDI's injection magic - turns out to be a really interesting, useful and nifty tool. However, it's not without caveats, to I recommend to read the blog of Romain Manni-Bucau who explains the dos and don'ts of CDI nicely.

Dig deeper

Romain Manni-Bucau article

The official JavaEE 6 documenation

StackOverflow on lazily initializing CDI beans

StackOverflow on the difference between @Inject T and @Inject Instance<T>


Comments