In the previous article we looked at how we can use the CDI qualifier system to pick which one of multiple possible implementations should be used when an injection takes place. In this article I show you how to decide what gets injected at runtime rather than at build time.
Being able to select which implementation gets injected at build time is useful but often it is necessary to modify an applications behaviour based on which the clients business needs. In our case we want to be able to decide between the SimpleQuoteService and a newly developed SeriousQuoteService (that only deliverys serious, high brow, quotations) at runtime.
Create the new SeriousQuoteService:
package example.simpleproject; import javax.ejb.Stateless; import javax.enterprise.inject.Alternative; @Stateless @Alternative public class SeriousQuoteService implements QuoteService { @Override public String getQuote() { return "A prudent question is one-half of wisdom - Francis Bacon"; } }
Notice that it’s annotated with @Alternative – we’ll come to that in a moment. Now annotate the SimpleQuoteService with @Alternative as well (SimpleQuoteService should have only @Alternative and @Stateless annotations). Finally remove the @Substitue annotation from the QuoteBean injection.
At this point you might think we are back in the situation where we have two choices for the CDI system to inject and that if you fired up the server now you would get an exception telling you that that CDI can’t choose between the two options (AlternativeQuoteService isn’t an option because of the the qualifier). There is a problem but it’s not too much choice now it’s to little! The @Alternative annotation causes the class to be removed from the selection process for injection so now if you fired up the server you would get an “Unsatisfied dependencies for type [QuoteService]” exception because there was nothing to inject.
Beans.xml to the Rescue
I bet you were thinking that beans.xml file was just a waste of time but not at all it’s going to come into it’s own right now. In this situation we need to enable one of the QuoteService beans marked with @Alternative in the beans.xml file. This file can be supplied with the system at deployment so it’s perfect for configuration at client sites. Modify your beans.xml file so that it looks like this:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> <alternatives> <class>example.simpleproject.SeriousQuoteService</class> </alternatives> </beans>
The alternatives block is used to pick which classes are activated for injection purposes, in this case we have selected the SeriousQuoteService for our fictional client. If you fire up the server and view the test page you should now see the quote from the SeriousQuoteService. Try changing the class selected in the beans.xml file to change which QuoteService is used.
That concludes the brief introduction to Java EE 6, CDI and JSF 2.0. I suppose it was a bit light on the JSF 2.0 side of things so I’ll try to address that in some other articles coming up later. I’ll also be discussing some aspect so CDI in more detail and other features of JEE6 such as web services.