In the previous part of this series we developed an application that contained a simple no interface EJB which fed quotes to a QuoteBean which, in turn, supplied them to the JSF page. In this part I’ll modify the QuoteService to make it an interface and then provide two different implementations of that interface.
Providing multiple implementations of an interface is not something I tend to do all that often as I tend to be coding on systems where we know exactly what we want it to do and how we want it to do it. There are times though where it makes a lot of sense to be able to provide multiple implementations and in those situations the interface is your friend.
Up until now I have made all the changes to the code without stopping the server but at this point I suggest you stop it to make the following changes. In theory the system should be able to cope but in my experience it rarely manages to. The problem seems to be centered around the conversion of the QuoteService from a concrete class into an interface which trips up the injection mechanism.
The first thing we do is convert the QuoteService into an interface like this:
package example.simpleproject; public interface QuoteService { String getQuote(); }
Next create a new class called SimpleQuoteService and make it implement the QuoteService interface:
package example.simpleproject; import javax.ejb.Stateless; @Stateless public class SimpleQuoteService implements QuoteService { @Override public String getQuote() { return "Those people who think they know everything are a great annoyance to those of us who do - Isaac Asimov "; } }
Notice that this class is annotated with @Stateless making it a session bean. Fire up the server and load up the test page, you should see the quote defined in the SimpleQuoteService.
Stop for a second and think about what just happened, the QuoteBean is injected with QuoteService but we just modified that to be and interface. What the CDI system has done is go looking for something that implements the QuoteService interface and, since it found something, it injected it. This does raise an interesting question though, what happens if there is more then one implementation of an interface?
Creating a Second QuoteService
Quickly create an alternative quote service and save it so that auto-deploy loads it.
package example.simpleproject; import javax.ejb.Stateless; @Stateless public class AlternativeQuoteService implements QuoteService { @Override public String getQuote() { return "A nickel ain't worth a dime anymore - Yogi Berra"; } }
If you watch the console window in NetBeans you will see a stack trace fly by which reads something like this:
SEVERE: Exception while loading the app : WELD-001409 Ambiguous dependencies for type [QuoteService] with qualifiers [@Default] at injection point [[field] @Inject private example.simpleproject.QuoteBean.quoteService]. Possible dependencies [[Session bean [class example.simpleproject.AlternativeQuoteService with qualifiers [@Any @Default]; local interfaces are [QuoteService], Session bean [class example.simpleproject.SimpleQuoteService with qualifiers [@Any @Default]; local interfaces are [QuoteService]]] org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies for type [QuoteService] with qualifiers [@Default] at injection point [[field] @Inject private example.simpleproject.QuoteBean.quoteService]. Possible dependencies [[Session bean [class example.simpleproject.AlternativeQuoteService with qualifiers [@Any @Default]; local interfaces are [QuoteService], Session bean [class example.simpleproject.SimpleQuoteService with qualifiers [@Any @Default]; local interfaces are [QuoteService]]] at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:309) at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:139) at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:162)
If you read the stack trace message you’ll notice that it’s telling you that it’s found two possible matches for the injection and therefore can’t just inject without more information. There are two ways to solve this problem, the first is to switch the injection from an interface to one of the concrete types (which rather defeats the point of using an interface in the first place) the second is to use an injection qualifier which will be the subject of the next article.