CDI Qualifiers in Java: Polymorphism in Dependency Injection

CDI Qualifiers in Java: Polymorphism in Dependency Injection

Hello!

This is the Part 2 of the CDI Series in Java that contains:

  • Part 1: Factory in CDI with @Produces annotation
  • Part 2: Polymorphism with CDI Qualifiers
  • Part 3: Events and Observers in CDI
  • Part 4: CDI and Lazy Initialization
  • Part 5: Interceptors in CDI
  • Part 6: CDI Dependency Injection and Alternatives
  • Part 7: Working with CDI Decorators

We'll use the scenario from the previous part, when we talked about @Produces annotations.

Let's remember that scenario and add a few more steps

  • Create a Checkout class and log on the console when a checkout is finished
  • Create a Simple Logger class that will have the logic to print a log
  • Create the Logger object choosing the desired Log mode; Debug, Info, or Warn mode

Are you ready?

Step 1: Using CDI 2.0 in a Standalone Mode

It's a good time to review the code from the previous part of this series that runs CDI in a standalone mode.

First of all, let's create the MainApplication class that will start the CDI Container. Just a reminder, in the following code we're using CDI 2.0, but Qualifiers can be used from version 1.0.

This code doesn't compile yet since we don't have the Checkout class.

Step 2: Creating the Checkout Class

Let's create the Checkout class with a simple logger:

That code doesn't compile either. Let's create the SimpleLogger class.

Step 3: Creating the SimpleLogger Class

This class will just use a log a message based on a configuration mode.

As you can see, we should have the class LogConfiguration to be able to configure the mode to be used when printing a log.

Step 4: Creating the LogConfiguration class

This class will contain 3 modes to be passed to the SimpleLogger class:

Notice that the SimpleLogger class should have a LogConfiguration object built.

In this case, we should create a Factory to teach CDI how to create a SimpleLogger object.

Let's move on!

Step 5: Factory With @Produces in CDI

We're going to use the @Produces annotation to create a Factory to build a SimpleLogger object.

This object will be built with the boolean debugMode as true to indicate that a message should be printed in the debug mode.

Great! So far we have just made an overview from the previous post.

Step 6: More Logger Modes

As you may notice, so far, we have just 1 mode to work with the Logger, the Debug mode!

But we'd like to use another Logger mode, for example, Info mode. How can we do that?

The first and simplest way to resolve this: Create another method in the Factory to create a Logger object that has the info mode

Let's explore this solution!

Yes, we renamed the previous method to be clear that a Debug Logger will be created, and besides that, we created a new method called createInfoLogger().

Notice that both methods are using the @Produces annotation and yes, CDI allows us to have many methods annotated with @Produces annotation in the same class.

Let's run the code?

Yes, an exception has thrown in our face! What's happened?

CDI can't understand and can't choose which method should be used when the SimpleLogger object is needed.

CDI will say to you:

Hey, I have 2 methods that Produces the object that you are interested in. You should teach me which one I should pick up.

And that really makes sense. CDI doesn't have the capacity to understand your desire when you're injecting a dependency.

Let's teach CDI how to pick up the correct Logger to be injected.

Step 7: Polymorphism With @Qualifiers

There is a great annotation called @Qualifiers since the version 1.0. With this annotation, we can teach CDI which method should be used and CDI will create the correct object.

First of all, we need to mark our Debug method, indicating that this method will use Debug mode.

How can we mark classes or methods in Java? Using annotations! So, let's create a new one!

Easy! We created the DebugMode annotation and we will mark the method that creates a Debug logger.

Notice that the ElementType in the annotation indicates where this annotation should be used. In our case, this will be used in methods and fields.

Using this annotation in the createDebugLogger() method:

Ok! But at any moment, CDI knows that the DebugMode annotation should be used. At this time, we should use its @Qualifier annotation:

Now CDI knows that the DebugMode annotation is a qualified annotation and will be used to filter which method should be used when a new Logger is requested.

Let's run it?

Awesome! Everything is working!

Not so fast! As you can see, we are printing the INFO LOG, right? But we would like to print the DEBUG LOG.

Yes, CDI needs that you specify explicitly which Qualifier should be used. If you don't pass any Qualifier, CDI will use its default Qualifier, called...@Default!

Under the hood, the method createInfoLogger has the @Default qualifier annotation:

And notice that CDI will configure the @Default Qualifier in the injection point:

So, keep in mind that we always have the @Default annotation when we don't have a specific CDI Qualifier.

Step 8: Choosing Another Qualifier in the Injection Point

Now it's easy to choose the Debug Mode in the Injection Point:

Let's run it again!

Everything is working!

Step 9: Creating More Log Modes using Qualifiers

An important note about the approach about CDI Qualifiers:

Qualifiers bring to us the ability to use polymorphism at the Injection Point

So, it's time to create a new Qualifier to the INFO and WARN modes to get the benefits from polymorphism and CDI:

And the entirely SimpleLoggerFactory class should be as follows:

Using the WARN mode:

If you run the code again, the message will be printed in the WARN mode!

Step 10: @Qualifiers With Arguments

We have 3 Log modes so far. But if we need 5 more modes? Creating 5 more annotations doesn't sound like a good idea

It's time to refactor our code and use Qualifiers with arguments to have less code being written. Yes, Qualifiers accept arguments in its annotation!

So, we'll create a new annotation called @LoggerMode, a more generic annotation:

We can use an Enum to indicate which mode we would like to use in the annotation:

The complete Qualifier code will be:

Pretty cool! We just need to change the methods in the Factory class to use the new annotation with the desiredMode option configured:

Now we can remove all 3 annotations to use just 1, the @LoggerMode annotation!

If we have 5 more Log Modes, don't worry, you can create 5 more types on Enum and don't need to create more 5 annotations! Excellent! Polymorphism rocks!

That's it! I hope that this article could be helpful to you!

Let's explore Events and Observers in CDI in the next post!

Thanks!

Alexandre Gama

Alexandre Gama

Hacking Code Founder

Hacking Code Founder and Writer, Passionate Senior Software Engineer and Team Leader at @Elo7, Teacher of several courses at Caelum, Speaker at many conferences and terrible guitar player.
CDI - Factories with @Produces Annotation - Hacking Code Java Tutorial

CDI - Factories with @Produces Annotation

Do you want to create powerful and easy Factories in CDI? Let's see how!

CDI Qualifiers Tutorial - Java CDI Guide by Hacking Code

CDI Qualifiers

Working with CDI Qualifiers
CDI Observers and Events Tutorial - Java CDI Guide by Live Coding

CDI Events and Observers

Let's see why and how to use CDI Events and Observers
CDI Lazy Initialization Tutorial - Java CDI Guide by Live Coding

CDI Lazy Initialization Tutorial

Did you know that we can initialize CDI beans lazily?
CDI Interceptors Tutorial - Java CDI Guide by Live Coding

CDI Interceptors

How to use CDI Interceptors from scratch
CDI Alternatives Tutorial - Java CDI Guide by Live Coding

CDI Alternatives Tutorial

Lear how to use Argument Matcher in its Fundamental way

CDI Decorator Tutorial - Java CDI Guide by Live Coding

CDI Decorator Tutorial

CDI Decorator is a powerful feature to deal with business Decoration!

0 Comments

Trackbacks/Pingbacks

  1. CDI – Creating Factories with @Produces Annotation | Hacking Code - […] Part 2: CDI Qualifiers […]

Leave a Reply

Share This
Subscribe To Our Newsletter

Subscribe To Our Newsletter

Join our mailing list to receive the latest news and updates from our team.

You have Successfully Subscribed!

%d bloggers like this: