Adam Bien's Weblog
Injecting Different Implementations Into An EJB 3 - Killing Factories
In most cases the EJB 3 container relies on conventions and injects the one and only existing EJB 3 implementation. It is convenient because in vast majority of all cases you only have one single implementation of an interface. Because it is the only possible choice, additional configuration doesn't provide any added value. It wouldn't be DRY.
But if you get an additional implementation of the interface - this approach will break.
You will have to specify, what implementation has to be injected. You have two choices:
@Local
public interface Service {
public String getMessage();
}
@Stateless
public class DefaultService implements Service {
public String getMessage() {
return "Hello from: " + this.getClass().getName();
}
}
//additional implementation - breaks the DI conventions
@Stateless
public class SpecificService implements Service {
public String getMessage() {
return "Hello from: " + this.getClass().getName();
}
}
1. The use of annotations:
@Stateless
@WebService
public class ClientAnnotationBean implements Client {
@EJB(beanName="DefaultService")
private Service service;
public String getHello() {
return this.service.getMessage();
}
}
The "DefaultService" in the @EJB annotation is the name of the EJB (DefaultService.class.getSimpleName()). You will have to recompile the code the client on every change...
2. The use of XML-configuration. In this case you can skip the beanName attribute in the annotation and specify it in the ejb-jar.xml. You could even entirely omit the @EJB annotation - but it doesn't provide additional benefits. You don't have to recompile your code, but provide and maintain an ejb-jar.xml file:
The particular implementation has to be specified in the ejb-jar.xml configuration then:
@Stateless
@WebService
public class ClientXMLBean implements Client {
@EJB
private Service service;
public String getHello() {
return this.service.getMessage();
}
}
<ejb-jar xmlns = "http://java.sun.com/xml/ns/javaee"
version = "3.0"
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/ejb-jar_3_0.xsd">
<enterprise-beans>
<session>
<ejb-name>ClientXMLBean</ejb-name>
<ejb-local-ref>
<ejb-ref-name>com.abien.samples.di.client.ClientXMLBean/service</ejb-ref-name>
<local>com.abien.samples.di.service.Service</local>
<ejb-link>DefaultService</ejb-link>
</ejb-local-ref>
</session>
</enterprise-beans>
</ejb-jar>
In EJB 3.1 interfaces are actually superfluous for common cases. Interfaces are only needed for the encapsulation of multiple implementations. With DI and EJB 3 you don't need factories any more. The whole sample was pushed into: http://kenai.com/projects/javaee-patterns/ and tested with Glassfish v2 and Netbeans 6.5/6.7.1
[See also: "Real World Java EE Patterns - Rethinking Best Practices", chapter 1, page 37 for more details about DI]
Posted at 09:49AM Aug 03, 2009 by Adam Bien in Real World Java EE Patterns - Rethinking Best Practices | Kommentare[5]
[my tweets]
Rss My book: Real World Java EE - Rethinking Best Practices


Killing factories...really? This is fine and good but factories are still an important part of your toolbox. The method described above only addresses the case when you know at compile time what bean you will need. A factory is still required when you can only determine a bean at runtime.
Gesendet von todd am August 03, 2009 at 11:21 PM CEST #
@Todd,
exactly - this approach is static. With factories and reflection you could swap the implementation dynamically. BUT: in the context of a typical business app it is very rare.
You will have to use a ServiceLocator then....
Factories inside the container are rarely needed,
thanks for your comment!,
adam
Gesendet von Adam Bien am August 04, 2009 at 08:31 AM CEST #
@Todd,
see also: http://www.adam-bien.com/roller/abien/entry/ejb_3_1_beanlocator_when
regards,
adam
Gesendet von Adam Bien am August 04, 2009 at 09:10 AM CEST #
@EJB(beanName="DefaultService")
private Service service;
leads to the same tight coupling as
private Service service = new DefaultService();
In fact this is a lookup even it is powered by DI mechanisms.
Gesendet von Christian am December 09, 2009 at 05:01 PM CET #
@Christian,
"@EJB(beanName="DefaultService")
private Service service;
leads to the same tight coupling as..."
with that name - yes. But you can name it however you want. You could even override the annotations with XML.
thanks for your feedback!,
adam
Gesendet von Adam Bien am December 09, 2009 at 09:03 PM CET #