Sunday Apr 24, 2011

TOTD #161: Java EE 6 CDI Qualifiers explained - @Default, @Any, @New, @Named

The CDI specification (JSR-299) defines "Qualifer" as a means to uniquely identify one of the multiple implementations of the bean type to be injected. The spec defines certain built-in qualifiers (@Default, @Any, @Named, @New) and new qualifiers can be easily defined as well. This Tip Of The Day (TOTD) discusses the in-built qualifiers and how they can be used.

The @Named qualifier makes a bean EL-injectable, that's it!

The @Default qualifier, appropriately called as "default qualifier", exists on all beans without an explicit qualifer, except @Named. Consider the following bean type and implementation:

public interface Greeting {
    public String greet(String name);
}


public class SimpleGreeting implements Greeting {
    public String greet(String name) {
        return "Hello " + name;
    }
}

So SimpleGreeting defined above is equivalent to:

@Default
public class SimpleGreeting implements Greeting {
    . . .
}

Similarly

@Named
public class SimpleGreeting implements Greeting {
    . . .
}

is equivalent to:

@Named
@Default
public class SimpleGreeting implements Greeting {
    . . .
}

The default qualifier works for the type injection as well. So

@Inject Greeting greeting;

and

@Inject @Default Greeting greeting;

are equivalent. However it is not recommended to use @Named as injection point qualifier, except in the case of integration with legacy code that uses string-based names to identify beans.

@Any is another in-built qualifier on all beans, including the ones with implicit or explicit @Default qualifier, except @New qualified beans (more on this later). So the SimpleGreeting implementation is equivalent to:

@Default @Any
public class SimpleGreeting implements Greeting {
    . . .
}

And can be injected as:

@Inject @Any Greeting greeting;

or even

@Inject @Any @Default Greeting greeting;

Now lets add a new implementation of the Greeting as:

public class FancyGreeting implements Greeting {
    public String greet(String name) {
        return "Nice to meet you, hello " + name;
    }
}

Now all of the following injections fail:

@Inject Greeting greeting;
@Inject @Default Greeting greeting;
@Inject @Any Greeting greeting;
@Inject @Default @Any Greeting greeting;

with the "ambiguous dependencies" error because both the implementations now have @Default and @Any qualifiers.

This can be resolved by adding a new qualifier called @Fancy to the FancyGreeting implementation as:

@Fancy
public class FancyGreeting implements Greeting {
    . . .
}

which is also equivalent to:

@Fancy @Any
public class FancyGreeting implements Greeting {
    . . .
}

Now all the following inject statements:

@Inject Greeting greeting;
@Inject @Default Greeting greeting;
@Inject @Any @Default Greeting greeting;

will inject the SimpleGreeting implementation. However

@Inject @Any Greeting greeting;

will throw an "ambiguous dependency" error because now there are two implementations with that qualifier. The right implementation can be picked by specifying the additional qualifier such as:

@Inject @Any @Default Greeting greeting;

will inject the SimpleGreeting implementation and

@Inject @Any @Fancy Greeting greeting;

will inject the FancyGreeting implementation. The following injection will work anyway:

@Inject @Fancy Greeting greeting;

Lastly

@Inject @Default @Fancy Greeting greeting;

will give an "unsatisfied dependency" error because any bean with an explicit qualifier, except @Named, does not have the @Default qualifier.

@Any may also be used to add qualifiers programmatically such as:

@Inject @Any Instance<Greeting> greeting;
greeting.select(new AnnotationLiteral<Fancy>(){}).get();

will return a Greeting implementation with @Fancy qualifier. Here the "javax.enterprise.inject.Instance" and "javax.enteprise.util.AnnotationLiteral" classes are defined by the CDI spec.

@Any may also be used to iterate over all Greeting implementations such as:

@Inject @Any Instance<Greeting> greeting;
for (Greeting g : greeting) {
    // do something with g
}

The @New qualifier allows to obtain a depdendent object of a specified class, independent of the declared scope. So if SimpleGreeting is defined as:

@RequestScoped
public class SimpleGreeting implements Greeting {
    . . .
}

and injected as:

@Inject Greeting greeting;

then a request-scoped Greeting implementation (SimpleGreeting in this case) is injected. However if it is injected as:

@Inject @New Greeting greeting;

then the injected SimpleGreeting is in the @Dependent scope and only has @New qualifier (neither @Default or @Any).

I tried all of this using GlassFish 3.1 and NetBeans 7.0 that provides complete development and fully-clustered deployment environment for your Java EE 6 applications. Where are you deploying your Java EE 6 apps ?

Technorati: totd cdi qualifier javaee6 glassfish

About

profile image
Arun Gupta is a technology enthusiast, a passionate runner, author, and a community guy who works for Oracle Corp.


Java EE 7 Samples

Stay Connected

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today