Java EE Context and Dependency Injection @Qualifier
In the previous tutorial we saw how to use the @Inject
annotations.
In this tutorial we will show you how to use the @Qualifier annotation. At system initialization time, the container must validate that exactly one bean is satisfying exactly one injection point. This means that if no implementation of an interface is available, the container would issue a warning indicating that it has an unsatisfied dependency and the application will not be deployed. If there is only one implementation, injection will work using the @Default
qualifier. If there are more than one implementation, the container would inform you of an ambiguous dependency and will again not deploy the application. You can only inject one bean.
SportSevice
package com.memorynotfound.cdi;
public interface SportService {
String play();
}
HockeyService implementation of SportService
Here is a concrete implementation of the SportService
which we annotate with the @Sport
annotation which tells that when an injection point with the same qualifier is used, then this concrete implementation will be injected by the container.
package com.memorynotfound.cdi;
@Sport(Sports.HOCKEY)
public class HockeyService implements SportService {
@Override
public String play() {
return "playing hockey";
}
}
FootballService implementation of SportService
Same goes for this implementation, when a qualifier witch this enumeration is used in an injection point, the container will inject a reference of this concrete implementation for you.
package com.memorynotfound.cdi;
@Sport(Sports.FOOTBALL)
public class FootballService implements SportService {
@Override
public String play() {
return "playing football";
}
}
Sport enumeration
When working with many implementation it is wise to consider working with enumerations. Otherwise you’ll end up with a huge amount of custom annotations.
package com.memorynotfound.cdi;
public enum Sports {
HOCKEY,
FOOTBALL
}
@Qualifier
You can create a custom qualifier. This annotation is associated with a type that is satisfied by some implementation of that type. This means that you can specify this annotation on a concrete implementation of the interface and in order to inject this concrete implementation using the @Inject
annotation you must also specify this on the injection point.
package com.memorynotfound.cdi;
import javax.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface Sport {
Sports value();
}
Context and Dependency Injection @Qualifier example
Putting it all together: We inject both services in a servlet with the @Qualifier
annotation using the prober enumerations to satisfy the injection points.
package com.memorynotfound.cdi;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import static com.memorynotfound.cdi.Sports.*;
@WebServlet(urlPatterns = {"/sport"})
public class SportServlet extends HttpServlet {
@Inject
@Sport(HOCKEY)
private SportService hockeyService;
@Inject
@Sport(FOOTBALL)
private SportService footballService;
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("<h1>Java EE: Context Dependency Injection @qualifier annotation</h1>");
out.print("<p>" + hockeyService.play() + "</p>");
out.print("<p>" + footballService.play() + "</p>");
}
}
Demo
URL: http://localhost:8080/qualifier/sport