CDI (Part 1): Factory With @Produces
In the first part of this series, let's explore CDI 2.0, how it interacts with your code (a logger in this example), and how to use the @Produces annotation.
Join the DZone community and get the full member experience.
Join For FreeHello!
This is the Part 1 of the CDI Series in Java that contains:
- Part 1: Factory in CDI with the @Produces annotation
- Part 2: 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
In this post, we're going to see how to use the @Produces
annotation that is probably one of the most used annotations in the CDI world in Java!
Let's contextualize our challenge here! We must create the following steps in our program:
- Create a Checkout class to... you know... finish a checkout
- Log the operations in the console
- Create a Logger class to keep this log in its own class, keeping the cohesion
- Customize this Logger to receive a Configuration that indicates which log mode should be used
Pretty simple, right? Let's jump into code!
Step 1: Creating the Special Main Class in CDI 2.0
Before creating the main class to execute the CDI code, let's create the important Checkout class:
public class Checkout {
public void finishCheckout() {
System.out.println("Finishing Checkout");
}
}
Great!
In this example, we're going to use CDI 2.0, which allows us to use CDI in a standalone fashion!
To create a CDI Container that will bring to us CDI power, just create the code:
CDI<Object> container = new Weld().initialize()
Nice! Let's see the complete code to have an instance of the Checkout class:
public class MainApplication {
public static void main(String[] args) {
try (CDI<Object> container = new Weld().initialize()) {
Checkout checkout = container.select(Checkout.class).get();
checkout.finishCheckout();
}
}
}
Pretty easy, isn't? Notice the following code:
Checkout checkout = container.select(Checkout.class).get();
That code is the same as the following:
@Inject
private Checkout checkout;
Now, it's time to execute our CDI example, to see that the environment is ok!
You will see in your console something like this:
INFO: WELD-ENV-002003:
Weld SE container STATIC_INSTANCE initialized Finishing Checkout
Great! Everything is up and running!
Step 2: Creating a Specialized Class for Logger
Our code should have good cohesion, so we should create a Class that is responsible for logging some messages. This class will be called SpecialLogger, as you can see below:
public class SpecialLogger {
public void log(String message) {
System.out.println("LOG: " + message);
}
}
Perfect! Now we'd like to update the Checkout class to use the Logger class:
public class Checkout {
private SpecialLogger logger;
public void finishCheckout() {
logger.log("Finishing Checkout");
}
}
Sounds good, because now the Checkout class doesn't know how a Log works under the hood, we're just using it!
Step 3: Configuration Mode to Log Messages
Sometimes we would like to change the mode that the log is printed out in. These modes could be:
- Debug Mode
- Info Mode
- Error Mode
- Etc.
Our SpecialLogger should receive the desired Log and print out the message using this Configuration Mode.
It's time to create the Configuration class that will receive the Log mode:
public class LogConfiguration {
private boolean infoMode;
private boolean debugMode;
public LogConfiguration(boolean infoMode, boolean debugMode) {
this.infoMode = infoMode;
this.debugMode = debugMode;
}
public boolean isInInfoMode() {
return infoMode;
}
public boolean isInDebugMode() {
return debugMode;
}
}
I know, that could be better, but this is just to keep the example clean and simple.
Let's change the SpecialLogger class to be able to Log a message based on a Configuration mode:
public class SpecialLogger {
@Inject
private LogConfiguration configuration;
public SpecialLogger(LogConfiguration configuration) {
this.configuration = configuration;
}
public void log(String message) {
if (configuration.isInDebugMode()) {
System.out.println("DEBUG LOG: " + message);
}
else if (configuration.isInInfoMode()) {
System.out.println("DEBUG LOG: " + message);
} else {
System.out.println("DEFAULT LOG: " + message);
}
}
}
As you can see, we're checking if the log should use the Debug or Info mode, otherwise the message must be printed out by using the Default mode.
Let's try to run it:
WELD-001408:
Unsatisfied dependencies for type SpecialLogger with qualifiers @Default
at injection point [BackedAnnotatedField]
@Inject
private com.hackingcode.cdi.produces.Checkout.logger
Yes, an exception will be thrown in our face. And that makes sense. CDI does not know how to inject the SpecialLogger object.
CDI will try the following steps:
- Hey, I can see that you need a SpecialLogger object. That's ok for me. I'll try to find this class
- I found the SpecialLogger class
- I'll try to create a new SpecialLogger object for you right now
- Ohhh, I can't do that! The SpecialLogger receives a LogConfiguration in its constructor. I don't know what it is and I don't know how to create this !
Let's teach CDI how to use the LogConfiguration class in the next step!
Step 4: Creating a Factory With the @Produces Annotation in CDI
It's time to create a Factory to create the SpecialLogger based on the LogConfiguration:
public class SpecialLoggerFactory {
public SpecialLogger createLogger() {
LogConfiguration logInDebugMode = new LogConfiguration(true, false);
return new SpecialLogger(logInDebugMode);
}
}
It's a pretty simple Factory class. It has the method createLogger(), which returns a LogConfiguration object.
But CDI doesn't know about this class yet, or even its method! Let's use the annotation @Produces
.
public class SpecialLoggerFactory {
@Produces
public SpecialLogger createLogger() {
LogConfiguration logInDebugMode = new LogConfiguration(true, false);
return new SpecialLogger(logInDebugMode);
}
}
@Produces indicates to CDI that the method createLogger() should be used when a LogConfiguration object is needed
The @Produces
annotation will say to CDI:
Hey CDI, please use the createLogger() method when you need to Inject a SpecialLogger object in some place
Of course, the returned object of the method createLogger() must be the same type that you're interested in, in this case the SpecialLogger.
That's it! I really hope that this article could be helpful to you!
In the next part we're going to hack a lot of code with CDI - Qualifiers
Don't forget to see all parts :)
Follow me to keep up to date!
Thanks!
Published at DZone with permission of Alexandre Gama. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments