Understanding Jakarta EE 8 - C.D.I. (Part 2) - Qualifying your beans.
Buhake Sindi
Posted on December 13, 2020
[As we continue with this series, we will refer to some content and examples from the CDI 2.x specification].
In order for the CDI container to recognise your bean for injection, your bean needs to be qualified. This can be achieved by associating a bean with a qualifier type. A qualifier type represents some client-visible semantic associated with a type that is satisfied by some implementations of the type (and not by others). In other words, a qualifier type identifies a bean with a type that can be satisfied to one specific implementation of the same type (else it becomes an unsatisfied dependency).
Let's look at how a bean can be qualified using a bean qualifier types.
Bean Qualifier Types
There's 3 standard qualified types that are defined in the javax.enterprise.inject
package:
-
@Any
: Every bean has the built-in qualifier@Any
, even if it does not explicitly declare this qualifier, except for the special@New
. -
@Default
: If a bean does not explicitly declare a qualifier other than@Named
, the bean has the qualifier@Default
. -
@New
: The@New
qualifier allows the application to obtain a new instance of a bean which is not bound to the declared scope, but has had dependency injection performed.
The following declarations are equivalent:
@Default
public class Order { ... }
public class Order { ... }
Both declarations result in a bean with two qualifiers: @Any
and @Default
.
The default qualifier is also assumed for any injection point that does not explicitly declare a qualifier, Thus, the following declarations, in which the use of the @Inject
annotation identifies the constructor parameter as an injection point, are equivalent:
public class Order {
@Inject
public Order(@Default OrderProcessor processor) { ... }
}
public class Order {
@Inject
public Order(OrderProcessor processor) { ... }
}
In conclusion, the @Any
and the @Default
qualifier are always assumed during bean qualification as well as at injection point when the qualifier hasn't been explicitly declared.
The @Named
Qualifier
The @Named
is defined by the package javax.inject
. This qualifier is used to specify the name of a bean. For example, this bean is named currentOrder
:
@Named("currentOrder")
public class Order { ... }
The above declaration results in a bean with three qualifiers: @Any
, @Default
and @Named("currentOrder")
.
If @Named
is declared by the bean with no bean name provided, the default bean name is used, after converting the first character of the class name to lowercase. For example, using the example above, if Order
class was just annotated with @Named
, the default bean name will be order
.
For more information, please refer to section 3.1.5 Default bean name for a managed bean.
If @Named
is not declared by the bean, nor by its stereotypes, a bean has no name.
Now that you have a basic insight on qualifying beans, let's look at various examples of qualifying beans using bean qualifier types. Note that we've set the bean-discovery-mode
as all
, the CDI container successfully recognised our classes as a qualified classes, ready for injection.
Example 1: CDI injection of implicit @Default
bean class (with no interfaces)
The tutorial source code can be found here and the running executable class file can be found here and it follows the example as mentioned in the previous article. The DefautService
and MainController
classes are simple classes that don't extend nor inherit any other class or interfaces respectively and has not been annotated with any bean qualifiers. This is due to the fact that all qualified bean are implicitly set as @Any
and @Default
.
Example 2: CDI injection of implicit @Default
bean class (injection on interface)
This is the extension of Example 1 but, in this case, the DefaultService
implements the Service
interface.
The tutorial source code can be found here and the running executable class file can be found here. On MainController
class we simply inject on the property which links to the Service
interface.
Seeing that there are no annotations on DefaultService
, the CDI container has managed to successfully discovery one implementation of the Service
interface and thus, creating a contextual context around the Service
interface (which in turn will inject DefaultService
when needed).
The DefaultService
implicitly is qualified as a @Any
and @Default
.
Let's pause on here. In the next tutorial we'll look on how to tackle injections of classes / interfaces that can produce more than 1 dependency injections using @Alternative
as well as defining our own custom qualifier type.
Posted on December 13, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.