News Ticker

Java EE Revisits 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 or delegates the creation of the object to a subclass. 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.

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.

CDI Framework

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-classes from lower level classes. This decoupling allows the implementation of the concrete class to change without affecting the client: reducing coupling and increasing flexibility.

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
}

Use it like so:

@Inject
DrinksMachine drinksMachine;

Here, the container creates an instance of the CoffeeMachine concrete class, it is selected based on its interface DrinksMachine and injected wherever the container finds a qualifying injection point. This is the simplest way to use the CDI implementation of the factory pattern. However, it’s not the most flexible.

Disambiguation

What happens if we have more than one concrete implementation of the DrinksMachine interface?

public class CoffeeMachine implements DrinksMachine {
  // Implementation code
}
public class SoftDrinksMachine implements DrinksMachine {
  // Implementation code
}

Which implementation should be injected? SoftDrinksMachine or CoffeeMachine?

@Inject
DrinksMachine drinksMachine;

The container does not know and so deployment will fail with an “ambiguous dependencies” error.

Qualifiers

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 SoftDrink. 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.

The two concrete implementations of the DrinksMachine interface are annotated appropriately. The CoffeeMachine class is annotated @Coffee while the SoftDrinksMachine class is annotated @SoftDrink.

@Coffee
public class CoffeeMachine implements DrinksMachine {
  // Implementation code
}


@SoftDrink
public class SoftDrinksMachine implements DrinksMachine {
  // Implementation code
}

Now you annotate the injection points. Use the qualifier @SoftDrink to denote where you want the container to inject the SoftDrinksMachine class and 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.

@Inject @SoftDrink
DrinksMachine softDrinksMachine;


@Inject @Coffee
DrinksMachine coffeeDrinksMachine;

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 object’s creation.

It is important to remember that the CDI framework will only instantiate POJOs that meet 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. Let’s dive deeper and look at how we can use the CDI framework to inject ANY class of ANY type into an injection point.

Producer Methods

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 customized initialization can also be produced ready for injection via a producer method.

Let’s 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;
}

A list of Book objects will be injected into the injection point annotated @Library.

Use it like so:

@Inject @Library
List<Books> 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 @DependentScoped. 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 @RequestScoped it will be invoked only once for each HTTP request in which it participates, lasting for the duration of the request.

@RequestScoped
@Produces
@Library
public List<Book> getLibrary(){
  // Generate a List of books called 'library'
  return library;
}

Possible scopes are:

RequestScoped – HTTP Request Scope
SessionScoped – HTTP Session Scope
ApplicationScoped – Shared across users
ConversationScoped – Interactions with JSF
DependentScoped – Default, inherits from client

  • The Good: easy to implement, no boilerplate code, works magically, any object can be made injectable, Automatic per class configuration
  • The Bad: named annotation is not type safe
  • and the ugly: object creation is hidden, hard to follow execution flow, IDE should help

What Next

If you are interested in learning more about Java EE, why not check out my new course here, you can even start with a free trial. Also check out my other articles on the Observer PatternDecorator PatternSingleton Pattern, and the Facade Pattern.

1 Comment on Java EE Revisits the Factory Pattern

  1. Those simple examples always confuse me, as they appear to first hide the implementation type and then create one annotation per implementation type in order to refer to a specific implementation. At this scale it seems so pointless.

1 Trackback / Pingback

  1. Factory Pattern | Dinesh Ram Kali.

Leave a Reply

Discover more from Digital Transformation and Java Video Training

Subscribe now to keep reading and get access to the full archive.

Continue reading