Java Implementation of the Factory Pattern
Lets look at another example of how Java EE has changed the way we implement the factory pattern.
The factory pattern is a creational design pattern whose intent is to provide an interface for creating families of related or dependent objects without specifying their concrete classes. The creational logic is encapsulated within the factory which either provides a method for its creation (factory method pattern) or delegates the creation of the object to a subclass (abstract factory method). The client is not aware of the different implementations of the interface or class. The client only needs to know the factory to use to get an instance of one of the implementations of the interface. Clients are decoupled from the creation of the objects.
public class DrinksMachineFactory implements AbstractDrinksMachineFactory { public DrinksMachine createCoffeeMachine() { return new CoffeeMachine(); } } AbstractDrinksMachineFactory factory = new DrinksMachineFactory(); DrinksMachine coffeeMachine = factory.createCoffeeMachine();
This shows how the drinks machine factory provides a method that creates a coffee machine and the client only needs to know what factory to use and the creation method to invoke. The implementation knows nothing about the way the object was created. It is completely decoupled.
In Java EE we can take advantage of the CDI framework to create objects without knowing the details of their creation. The decoupling occurs as a result of the way Java EE implements inversion of control. The most important benefit this conveys is the decoupling of higher-level-class from lower level classes. This decoupling allows the implementation of the concrete class to change without affecting the client: reducing coupling and increasing flexibility.
Often the factory pattern is implemented as a singleton or a static class as only one instance of the factory is required. This centralizes the object creation.
The CDI framework itself is an implementation of the factory pattern. The container creates the qualifying object during application start up and injects it into any injection point that matches the injection criterion. The client does not need to know anything about the concrete implementation of the object, not even the name of the concrete class is known to the client.
public class CoffeeMachine implements DrinksMachine { // implementation code }
Used as follows:
@Inject DrinksMachine drinksMachine;
The container creates an instance of the CoffeeMachine concrete class, it is selected based on its interface DrinksMachine and injected where ever the container finds a qualifying injection point. This is the simplest way to use the CDI implementation of the factory pattern. However its not the most flexible.
Have a look at this example. Here we have two concrete implementation of the DrinksMachine interface.
public class CoffeeMachine implements DrinksMachine { // implementation code } public class SoftDrinksMachine implements DrinksMachine { // implementation code } @Inject DrinksMachine drinksMachine; // which DrinksMachine to inject: SoftDrinksMachine or CoffeeMachine?
What happens if we have more than one concrete implementation of the DrinksMachine interface? Which implementation should be injected? SoftDrinksMachine or CoffeeMachine? The container does not know and so deployment will fail with an “ambiguous dependencies” error.
So how does the container distinguish between concrete implementations? Java EE gives us a new tool: Qualifiers. Qualifiers are custom annotations that mark the concrete class and the point where you want the container to inject the object.
Returning to our Drinks machine and the two concrete classes of the same type CoffeeMachine and SoftDrinksMachine we would distinguish them by the use of two qualifier annotations:
@Qualifier @Retention{RetentionPolicy.RUNTIME} @Target({ElementType.METHOD, ElementType.FIELD)} public @interface SoftDrink
@Qualifier @Retention{RetentionPolicy.RUNTIME} @Target({ElementType.METHOD, ElementType.FIELD)} public @interface Coffee
We create one qualifier name SoftDrinks. This will annotate the SoftDrinksMachine concrete class and Coffee will annotate the CoffeeMachine class.
The @Target annotation restricts where we can use these qualifiers to mark injection points, in this case on method and field injection points. The annotation with retention policy RUNTIME ensures that the annotation is available to the JVM through runtime.
The possible values for Target are: TYPE, METHOD, FIELD, PARAMETER.
@Coffee public class CoffeeMachine implements DrinksMachine { // implementation code }
@SoftDrink public class SoftDrinksMachine implements DrinksMachine { // implementation code }
The two concrete implementations of the DrinksMachine interface are annotated appropriately. The CoffeeMachine class is annotated @Coffee while the SoftDrinksMachine class is annotated @SoftDrink.
@Inject @SoftDrink DrinksMachine drinksMachine;
@Inject @Coffee DrinksMachine drinksMachine;
Now you annotate the injection points. Use the qualifier @SoftDrink to denote where you want the container to inject the SoftDrinksMachine class and the the qualifier @Coffee where you want the container to inject the CoffeeDrinkMachine. Now we have made it clear to the container where our concrete implementations should be injected and deployment will succeed.
Conclusions so far:
We have seen how Java EE’s CDI framework is an implementation of the factory pattern, how it hides the concrete implementation of an object and allows the creation to be decoupled from its use. We have seen how qualifiers are used to select the required implementation without the need to know anything about the objects creation.
It is important to remember that the CDI framework will only instantiate POJOs that meets all of the conditions of the managed beans specification JSR 299. But what if the object you want to inject doesn’t, does that mean we cannot take advantage of the CDI framework’s injection capabilities for classes that don’t comply. No it doesn’t. Java EE provides us with a solution. Lets dive deeper and look at how we can use the CDI framework to inject ANY class of ANY type into an injection point.
Java EE has a feature called producer methods. These methods provide a way to instantiate and therefore make available for injection objects that don’t conform to the managed bean specifications such as objects which require a constructor parameter for proper instantiation. Objects whose value might change at runtime and objects whose creation requires some customised initialization can also be produced ready for injection via a producer method.
Lets have a look at a producer method which produces a List populated with Books objects.
@Produces @Library public List<Book> getLibrary(){ // generate a List of books called 'library' return library; } @Inject @Library List<Books> library;
A list of Book objects will be injected into the injection point annotated @Library.
an important feature of the producer method is its scope. This will determine when the method is invoked and for how long the object it produces will live.
By default the producer method scope is @Dependent. This means that it inherits the scope of its client.
We can extend this example further by giving it a wider scope. If we annotate the producer method @SessionScope it will be invoked only once for each HTTP session in which it participate, Lasting for the duration of the session.
@SessionScope @Produces @Library public List<Book> getLibrary(){ // generate a List of books called 'library' return library; }
Possible scopes are:
RequestScoped – HTTP Request Scope
SesionScoped – HTTP Session Scope
ApplicationScoped – Shared across users
ConversationScoped – Interactions with JSF
DependentScoped – Default, inherits from client
Producer method can accept parameters, thus making configuration of the object specific to our needs without needing to know the underlying implementation of the object you want to produce.
public class LoggerFactory { @Produces public Logger logger(InjectionPoint injectionPoint) { return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName()); } }
@Inject private transient Logger logger;
The producer method accepts an InjectionPoint instance that provides access to metadata about the point where it was injected in this example you use the injection point to get the class name so that the logger can be configured. The scope of this producer is @Dependent meaning that the method is called for each injection. This allows per class usage configuration.
Conclusions so far:
Object creation has been simplified as much as is possible by handing it over control to the container. It is no longer necessary to implement the factory pattern for POJO creation, and as we have just seen any object can be created by a producer method and make available for injection. In fact the enhancements to the factory pattern (as implemented by the CDI container) allow the creation of native types initialised with data as demonstrated by the List of books example above.
Harnessing the power of CDI
The advanced features of the CDI framework have unleashed a great deal of power that if used imaginatively can leading to some interesting pattern variations. I am going to show an example of a pattern implementation that uses a selection of these advanced features.
If your application has multiple implementations of an interface and you want to produce instances of these objects you will have to write the required producer methods for each implementation. This will become verbose and difficult to maintain. Fortunately we have a solution in the form of the @Any annotation and the imaginative use of enum types, annotation literals and the Instance class.
The @Any annotation instructs the container that all beans that implement the given interface should be injected at that injection point.
@Any @Inject private Instance<MessageType> messages
Now that all instances of MessageType have been collected and injected into the variable messages we need a way to distinguishes them and select the implementation we want. This is where the use of annotation literals and enum types come into play.
@Qualifier @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE}) public @interface Message { Type value(); enum Type{ SHORT, LONG } }
Here we have defined an enum qualifiers to disambiguate between SHORT and LONG messages.
Now our classes need to be annotated as in the examples above.
@Dependent @Message(Message.Type.SHORT) public class ShortMessage implements MessageType{ // ... }
@Dependent @Message(Message.Type.LONG) public class LongMessage implements MessageType{ // ... }
Now we have all the piece of puzzle we must put it together.
The message factory
@Dependent public class MessageFactory { @Inject @Any private Instance<MessageType> messages; public MessageType getMessage(Message.Type type) { MessageLiteral literal = new MessageLiteral(type); Instance<MessageType> typeMessages = messages.select(literal); return typeMessages.get(); } }
In the factory class all dependencies that implement the MessageType interface are injected into the member variable messages then from the method getMessage you use the Message.Type parameter to create a new MessageLiteral that you use to select the MessageType implementation that you want from messages, which in turn is returned to the client.
We use it like so:
The client injects the factory and calls the getMessage method passing in the Message.Type that it requires.
@Inject MessageFactory mf; public void doMessage(){ MessageType m = mf.getMessage(Message.Type.SHORT); }
An instance of the message type SHORT will be returned.
In an application that has multiple message types this way of constructing and selecting message objects results in a big reduction of boilerplate code and simplifies the construction of multiple objects of the same interface type.
Conclusion
You have seen how the factory pattern has been virtually rendered unnecessary by the CDI framework. Object instantiation and injection is taken care of by the container. Substantially less code is required to create an object even when disambiguation is required, we still need very little code to achieve what the factory pattern would have achieved with a lot of boilerplate code.
The CDI framework has brought us new tools we can use to implement new variations of pattern themes. These tools, if used imaginatively, result in new ways to solve old problems. You have seen how the collect and select pattern takes full advantage of the CDI framework to create a new way to produce objects.
Next: Other patterns: Facade, Decorator, Observer and much more
Can you please add MessageLiteral implementation on how does it return the Annotation type?
Do we need to create MessageLiteral or is a class from a lib that we need to import with Maven? Thanks.