Rick has posted 25 posts at DZone. You can read more from them at their website. View Full User Profile

CDI Dependency Injection - An Introductory Tutorial Part 1 - Java EE

03.28.2011
| 148942 views |
  • submit to reddit

CDI is the Java standard for dependency injection (DI) and interception (AOP). It is evident from the popularity of DI and AOP that Java needs to address DI and AOP so that it can build other standards and JSRs on top of it. DI and AOP are the foundation of many Java frameworks, and CDI will be the foundation of many future specifications and JSRs.

This article discusses dependency injection in a tutorial format. It covers some of the features of CDI such as type safe annotations configuration, alternatives and more. This tutorial is split into two parts, the first part covers the basis of dependency injection, @Inject, @Produces and @Qualifiers. The next part in this series covers advanced topics like creating pluggable components with Instance and processing annotations for configuration.

CDI is a foundational aspect of Java EE 6. It is or will be shortly supported by Caucho's Resin, IBM's WebSphere, Oracle's Glassfish, Red Hat's JBoss and many more application servers. CDI is similar to core Spring and Guice frameworks. Like JPA did for ORM, CDI simplifies and sanitizes the API for DI and AOP. If you have worked with Spring or Guice, you will find CDI easy to use and easy to learn. If you are new to Dependency Injection (DI), then CDI is an easy on ramp for picking up DI quickly. CDI is simpler to use and learn.

CDI can be used standalone and can be embedded into any application.

Source code for this tutorial, and instructions for use.

It is no accident that this tutorial follows this Spring 2.5 DI tutorial (using Spring "new" DI annotations) written three years ago. It will be interesting to compare and contrast the examples in this tutorial with the one written three years ago for Spring DI annotations.



Design goals of this tutorial


This tutorial series is meant to be a description and explanation of DI in CDI without the clutter of EJB 3.1 or JSF. There are already plenty of tutorials that cover EJB 3.1 and JSF with CDI as a supporting actor.

CDI has merit on its own outside of the EJB and JSF space. This tutorial only covers CDI. Repeat there is no JSF 2 or EJB 3.1 in this tutorial. There are plenty of articles and tutorials that cover using CDI as part of a larger JEE 6 application. This tutorial is not that. This tutorial series is CDI and only CDI.

This tutorial only has full, complete code examples with source code you can download and try out on your own. There are no code snippets where you can't figure out where in the code you are suppose to be.

We start out slow, step by step and basic. Then once you understand the fundamentals, we pick up the pace quite a bit.

All code examples have actually been run. We don't type in ad hoc code. If it did not run, it is not in our tutorial. We are not winging it.

There are clear headings for code listings so you can use this tutorial as a cookbook when you want to use some feature of CDI DI in the future. This is a code centric tutorial. Again, the code listings are in the TOC on the wiki page so you can find just the code listing you are looking for quickly like an index for a cookbook.

Decorators, Extentions, Interceptors, Scopes are out of scope for this first tutorial. Expect them in future tutorials.

If this tutorial is well recieved and we get enough feedback through, the JavaLobby articles, our google group and comments section of the wiki then we will add a comprehensive tutorial on CDI AOP (Decorators and Interceptors) and one on Extentions. The more positive and/or constructive feedback we get the more encouraged we will be to add more.



Dependency Injection


Dependency Injection (DI) refers to the process of supplying an external dependency to a software component. DI can help make your code architecturally pure.

It aids in design by interface as well as test-driven development by providing a consistent way to inject dependencies. For example, a data access object (DAO) may depend on a database connection.

Instead of looking up the database connection with JNDI, you could inject it.

One way to think about a DI framework like CDI is to think of JNDI turned inside out. Instead of an object looking up other objects that it needs to get its job done (dependencies), a DI container injects those dependent objects. This is the so-called Hollywood Principle, "Don't call us‚" (lookup objects), "we'll call you" (inject objects).

If you have worked with CRC cards you can think of a dependency as a collaborator. A collaborator is an object that another object needs to perform its role, like a DAO (data access object) needs a JDBC connection object for example.



Dependency Injection-AutomatedTellerMachine without CDI or Spring or Guice


Let's say that you have an automated teller machine (ATM, also known as an automated banking machine in other countries) and it needs the ability to talk to a bank. It uses what it calls a transport object to do this. In this example, a transport object handles the low-level communication to the bank.

This example could be represented by these two interfaces as follows:



Code Listing: AutomatedTellerMachine interface
package org.cdi.advocacy;

import java.math.BigDecimal;

public interface AutomatedTellerMachine {

    public abstract void deposit(BigDecimal bd);

    public abstract void withdraw(BigDecimal bd);

}


Code Listing: ATMTransport interface
package org.cdi.advocacy;

public interface ATMTransport {
    public void communicateWithBank(byte[] datapacket);
}

Now the AutomatedTellerMachine needs a transport to perform its intent, namely withdraw money and deposit money. To carry out these tasks, the AutomatedTellerMachine may depend on many objects and collaborates with its dependencies to complete the work.

An implementation of the AutomatedTellerMachine may look like this:



Code Listing: AutomatedTellerMachineImpl class
package org.cdi.advocacy;
...
public class AutomatedTellerMachineImpl implements AutomatedTellerMachine {
	
    private ATMTransport transport;
	
        ...
    public void deposit(BigDecimal bd) {
        System.out.println("deposit called");
        transport.communicateWithBank(...);
    }

    public void withdraw(BigDecimal bd) {
        System.out.println("withdraw called");
        transport.communicateWithBank(...);
    }

}

The AutomatedTellerMachineImpl does not know or care how the transport withdraws and deposits money from the bank. This level of indirection allows us to replace the transport with different implementations such as in the following example:



Three example transports: SoapAtmTransport, StandardAtmTransport and JsonAtmTransport


Code Listing: StandardAtmTransport
package org.cdi.advocacy;


public class StandardAtmTransport implements ATMTransport {

    public void communicateWithBank(byte[] datapacket) {
        System.out.println("communicating with bank via Standard transport");
                ...
    }

}


Code Listing: SoapAtmTransport
package org.cdi.advocacy;

public class SoapAtmTransport implements ATMTransport {

    public void communicateWithBank(byte[] datapacket) {
        System.out.println("communicating with bank via Soap transport");
                ...
    }

}



Code Listing: JsonRestAtmTransport
package org.cdi.advocacy;

public class JsonRestAtmTransport implements ATMTransport {

    public void communicateWithBank(byte[] datapacket) {
        System.out.println("communicating with bank via JSON REST transport");
    }

}

Notice the possible implementations of the ATMTransport interface. The AutomatedTellerMachineImpl does not know or care which transport it uses. Also, for testing and developing, instead of talking to a real bank, you could easily use Mockito or EasyMock or you could even write a SimulationAtmTransport that was a mock implementation just for testing.

The concept of DI transcends CDI, Guice and Spring. Thus, you can accomplish DI without CDI, Guice or Spring as follows:



Code Listing: AtmMain: DI without CDI, Spring or Guice
package org.cdi.advocacy;

public class AtmMain {
        
        public void main (String[] args) {
                AutomatedTellerMachine atm = new AutomatedTellerMachineImpl();
                ATMTransport transport = new SoapAtmTransport();
                /* Inject the transport. */           
                ((AutomatedTellerMachineImpl)atm).setTransport(transport);
                
                atm.withdraw(new BigDecimal("10.00"));
                
                atm.deposit(new BigDecimal("100.00"));
        }

}

Then injecting a different transport is a mere matter of calling a different setter method as follows:



Code Listing: AtmMain: DI without CDI, Spring or Guice: setTransport
ATMTransport transport = new SimulationAtmTransport();
((AutomatedTellerMachineImpl)atm).setTransport(transport);

The above assumes we added a setTransport method to the AutomateTellerMachineImpl. Note you could just as easily use constructor arguments instead of a setter method. Thus keeping the interface of your AutomateTellerMachineImpl clean.



Running the examples


To run the examples quickly, we setup some maven pom.xml files for you. Here are the instructions to get the examples up and running.



Dependency Injection-AutomatedTellerMachine using CDI


To use CDI to manage the dependencies, do the following:

  1. Create an empty bean.xml file under META-INF resource folder
  2. Use the @Inject annotation to annotate a setTransport setter method in AutomatedTellerMachineImpl
  3. Use the @Default annotation to annotate the StandardAtmTransport
  4. Use the @Alternative to annotate the SoapAtmTransport, and JsonRestAtmTransport.
  5. Use the @Named annotation to make the AutomatedTellerMachineImpl easy to look up; give it the name "atm"
  6. Use the CDI beanContainer to look up the atm, makes some deposits and withdraws.
  7.  



Step 1: Create an empty bean.xml file under META-INF resource folder


META-INF/beans.xml

CDI needs an bean.xml file to be in META-INF of your jar file or classpath or WEB-INF of your web application. This file can be completely empty (as in 0 bytes). If there is no beans.xml file in your META-INF or WEB-INF then that war file or jar file will not be processed by CDI. Otherwise, CDI will scan the jar and war file if the beans.xml file exists even if it is 0 bytes.



Code Listing: META-INF/beans.xml just as empty as can be
<beans xmlns="http://java.sun.com/xml/ns/javaee" 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/beans_1_0.xsd">

</beans>

Notice that we included a starter beans.xml file with a namespace and a `` element. Although beans.xml could be completely empty, it is nice to have a starter file so when you need to add things (like later on in this tutorial) you can readily. Also it keeps the IDE from complaining about ill formed xml when you actually do have a 0 byte beans.xml. (I hate when the IDE complains. It is very distracting.)



Step 2: Use the @Inject annotation to annotate a setTransport setter method in AutomatedTellerMachineImpl

The @Inject annotation is used to mark where an injection goes. You can annotate constructor arguments, instance fields and setter methods of properties. In this example, we will annotate the setTransport method (which would be the setter method of the transport property).



Code Listing: AutomatedTellerMachineImpl using @Inject to inject a transport
package org.cdi.advocacy;

...

import javax.inject.Inject;

public class AutomatedTellerMachineImpl implements AutomatedTellerMachine {
	
    private ATMTransport transport;

    @Inject
    public void setTransport(ATMTransport transport) {
        this.transport = transport;
    }

       ...

}

Continue reading... Click on the navigation links below the author bio to read the other pages of this article.

Be sure to check out part II of this series as well: Part 2 plugins and annotation processing !



About the author
This article was written with CDI advocacy in mind by Rick Hightower with some collaboration from others. Rick Hightower has worked as a CTO, Director of Development and a Developer for the last 20 years. He has been involved with J2EE since its inception. He worked at an EJB container company in 1999. He has been working with Java since 1996, and writing code professionally since 1990. Rick was an early Spring enthusiast. Rick enjoys bouncing back and forth between C, Python, Groovy and Java development.

Although not a fan of EJB 3, Rick is a big fan of the potential of CDI and thinks that EJB 3.1 has come a lot closer to the mark.

Rick Hightower is CTO of Mammatus and is an expert on Java and Cloud Computing. Rick is invovled in Java CDI advocacy and Java EE. CDI Implementations - Resin Candi - Seam Weld - Apache OpenWebBeans

Published at DZone with permission of its author, Rick Hightower.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Dave Macpherson replied on Mon, 2011/03/28 - 10:21am

"...Thus marking it so is redundant; and not only that its redundant"

 

This made me laugh. Good one!

(Good intro article too!)

 Dave

Josh Marotti replied on Mon, 2011/03/28 - 2:28pm

I have to admit, I hate the qualifier is put into an annotation.  Why can't we inject and qualify by name we used from the @Named annotation instead (to kill the coupling that will occur with a new annotation)?

Turn this:

@Inject
public void setTransport(@Soap ATMTransport transport) {
   this.transport = transport;
}


Into this:

@Inject
public void setTransport(@Qualified("soap") ATMTransport transport) {
   this.transport = transport;
}

It may not be as readable, but doesn't require the annotation, and, thereby, code coupling.  Perhaps it can already do this and you just haven't mentioned it?

 

Rick Hightower replied on Mon, 2011/03/28 - 3:23pm

Josh Marotti, There is a way to do something similar to that. I discuss it in the second article in this series. "There could be an explosion of qualifers annotations in your project. Imagine in our example if there were 20 types of transports. We would have 20 annotations defined." "This is probably not want you want. It is okay if you have a few, but it could quickly become unmanageable." CDI allows you to descriminate on members of a qualifier to reduce the explosion of qualifiers. Instead of having three qualifier you could have one qualifier and an enum (or a string like you have above although this is frowned upon in CDI). Then if you need more types of transports, you only have to add an enum value instead of another class. There are examples of this in the next article.

Reza Rahman replied on Mon, 2011/03/28 - 4:25pm in response to: Rick Hightower

You indeed can use @Named as a qualifier.

The trade-off is sacrificing Java-based type-safety and readability as mentioned. The way I see it personally, in most real-life projects, you will only really need a handful of qualifers, so I don't see more type-safe qualifiers as a big issue, but an overall improvement over traditional name based injection point qualification (in fact I suspect it is an evolutionary quirk arising fom the heavy XML dependence of early DI frameworks).

Walter Bogaardt replied on Mon, 2011/03/28 - 6:36pm

Cheers Rick,

Claming a little ignorance, but will you also be illustrating testing an application via mock objects using CDI. In spring using the xml mappings its easy as swaping out the xml files, but be interested in annotation based solution to this.

 

 

Rick Hightower replied on Mon, 2011/03/28 - 10:02pm

Walter,

The short answer is Alternatives. I don't remember if I cover them here or in the next article. (I wrote the example code already).

The longer answer will have to wait until I put the kids to bed.

Cloves Almeida replied on Mon, 2011/03/28 - 10:18pm

Seam 3 (designed as a set of extensions on top of CDI) has a XML config module that could achive such flexibility.

Rick Hightower replied on Mon, 2011/03/28 - 11:23pm

Walter,

Also you can use alternatives. There is a section in this tutorial on alternatives. Using @Alternative to select an Alternative Earlier, you may recall, we defined several alternative transports, namely, JsonRestAtmTransport and SoapRestAtmTransport. Imagine that you are an installer of ATM machines and you need to configure certain transports at certain locations. Our previous injection points essentially inject the default which is the StandardRestAtmTransport transport.

You can scan for it.

Here is a link to the section in the wiki version of this tutorial Alternatives

As cloves was saying if you wanted to use the XML files. Seam has XML CDI plugin that is similar to what you would expect in a spring context xml file. Resin also supports an XML file version. In most cases, you should be able to use Alternatives.

Rick Hightower replied on Mon, 2011/03/28 - 11:24pm

Walter,

One more thing. There are several unit testing frameworks for CDI. We plan on writing tutorials about them in the future. There is a lot more to come. There is a lot out there. CDI is nascent but coming together quickly.

Josh Marotti replied on Tue, 2011/03/29 - 11:08am in response to: Rick Hightower

I saw that, but it is still user-based created annotations or enums.  When I load spring, for example, with just a config.xml, the actual objects are 'pure' in that they don't have external annotations or objects.  I liked the idea of using annotations in spring, but it coupled the objects to spring, which I felt was dirty.  When CDI came out, it causes a dependency to J2EE 6, but at least that was something that would have been loaded if we reused the objects in another project.  The necessity of bringing the custom annotations or enums, though, makes me feel that it is back to where we were with spring... bringing along other coupled code for an object that can almost stand alone.

 

I'm not saying it's the end of the world or anything.  It is cleaner than what we have now.  I just am wishing for a blue-sky perfectionism that we just don't find in architecture.

Rick Hightower replied on Tue, 2011/03/29 - 12:36pm in response to: Josh Marotti

As mentioned earlier, the Seam Weld project has a CDI plugin that provides a "config.xml" that is similar to Springs. Since it is a CDI plugin (called extensions), it should work on any standard CDI implementation. Expect a future article on using this plugin. Also Resin CANDI (another CDI implementation) has XML support, and this CDI XML support is also how you configure the server itself so the whole thing uses CDI throughout.

Since the Seam CDI Weld project has a nice plugin, it might become the de facto standard for when you want XML instead of annotations. Personally, I prefer to use the annotations whenever possible and keep the XML as small as possible.

Andy Gibson replied on Tue, 2011/03/29 - 12:43pm

Josh the benefits of qualifiers, or qualifiers with Enums is that you get type safety when defining injection points and items to be injected. You could just use named but thats just attaching an untype safe name to the bean.

I see what you are saying about having to drag external qualifiers in there, and I have two answers for that.

First the qualifier could be regarded as part of your object semantics, the SoapTransport class really is a @Transport and marking it with that qualifier is along the lines of implementing the Transport interface. Think about it, you don't need to implement the Transport interface, you do it to make it type safe and to take advantage of polymorphism. Likewise you add a qualifier to make it type safe and to take advantage of looking up beans of similar types but with different qualifiers (i.e. semantic polymorphism or something!)

 We don't get rid of an interface to keep our objects pure when we only use one implementation of the interface (there are times we should but we don't always). Same way we don't throw out qualifiers just because we aren't always accessing the beans using the qualifier.

Second option is to can create your pure SoapTransport class with no CDI annotations and have a CDI aware transport factory with a method to create a SoapTransport that is annotated with @Produces @Transport(TransportType.SOAP) . You would have to build the instance (or get it from the CDI container) and return it.

However, you run into problems because if the SoapTransport class needs an xyz bean injecting into then its not going to happen automatically because you didn't define the injection point with @Inject because your bean knows nothing about CDI. At which point, you have to handle your own injection like you would if you had to define it in xml.

In this case CDI makes you do your manual injections in type safe code rather than in untype safe xml, usually with no code assist either.

Thanks for your thoughts,  I think this is a good idea for a blog post.

 

Reza Rahman replied on Tue, 2011/03/29 - 2:59pm in response to: Rick Hightower

Just to be absolutely clear, you can put *all* meta-data in XML with CDI if you so wish (of course you'd be reverting back to name based qualification).

XML config is definitely worth a look: http://docs.jboss.org/seam/3/config/latest/reference/en-US/html/. As far as XML goes, it is far more compact, readable and type-safe because it is schema driven as opposed to most legacy XML configuration (CanDI XML is the same way). In fact, I wish we could adopt the model for Java EE overall.

Now, I doubt it's anything that anyone would recommend because other than a preference to remove all meta-data from Java code, there are few benefits to that approach and a lot of pitfalls - particularly because injection related meta-data hardly changes all that much and is likely semantically linked to the code anyway.

BTW, chances are CDI XML configuration might be standardized in Java EE 7.

Rick Hightower replied on Tue, 2011/04/05 - 4:30pm

Part 2 is out: Part 2
It is a bit shorter than Part 1

Rick Hightower replied on Wed, 2011/04/06 - 7:28pm

FYI... (like XML) and tags Foo were getting stripped out by the output processing of JavaLobby. Essentially tags that are not allowed are still in the content mgmt system, but not processed.

I changed all < to < and all < to >. I actually have a Python text processor that I wrote that converts from google WIKI markup into other markups so it was as easy as adding
line = line.replace("<", "<").replace(">",">").
To the part that does the code processing.

James Weitlauf replied on Thu, 2011/04/14 - 7:39am

Is it possible to mix the DI between xml and annotations, ie use @Inject for a bean that I configured using xml?  Reason I ask is because I configured my Hibernate session factory in the xml but I need that injected into my Dao, which gets injected into Foo.

So I would like to @Inject the Dao into Foo and @Inject my sessionfactory into my Dao.

I am using Spring 3 if that matters.

Nevermind, I found my answer... amazing what you can find if you read the documentation.

Carla Brian replied on Tue, 2012/05/29 - 9:10am

Good thing I stumbled upon in this post. I am new to this application. Thanks for sharing your insights. - Byron Pederson

David Espinosa replied on Sat, 2014/03/29 - 10:44pm

 This is the best tutorial about CDI.
Thanks.

Dinoop Paloli replied on Sat, 2014/03/29 - 3:35pm

Hi, What is beanContainer Object and how can I get it? I am using Jboss 7 to deploy the above examples

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.