JavaEE dependency injection – common mistakes

In this post, I will cover some common mistakes people make when it comes about injection in enterprise environment.

1.) @EJB and the new keyword

I’ve seen dozens of forum posts, was asked the question so many times: “Instead of injecting my dependencies, the container throws a NullPointerException. Why?”

Most of the times, the answer to this question is really simple: because you are instantiating your EJB with the new operator, and don’t let the container do its job. For example, let’s consider the following piece of code:

@Stateless
public class Car {

  @EJB
  private Engine engine;

  //...

  public void startEngine() {
    engine.start();
  }

  //...
}

@Stateless
public class CarSalon {

  //...

  public void testDrive() {
    Car car = new Car();
    car.startEngine();
    // ...
  }
}

You see both classes here are stateless session beans; however, if you tried to run the code above, you’d get a big fat NullPointerException. The reason is that the object Car is not managed by the container, even if it’s a session bean. When you use the new keyword, you get in charge for managing that object. An object instantiated this way is outside the reach of the container, and it has no way of injecting dependencies. None of the @EJB, @Resource, @PersistenceContext etc. injections will have any effect. Simply put, using new you can only create POJOs, not Enterprise Java Beans.

In order to fix this error, you have to get the container take care of the Car object. Nothing easier than that, we just have to either look up the bean tgrough an instance of the InitialContext class:

@Stateless
public class CarSalon {

  //...

  public void testDrive() {
    InitialContext context;
    try {
		context = new InitialContext();
		Car car = (Car)context.lookup(CAR_JNDI_NAME);
		car.startEngine();
		//...
    } catch (NamingException e) {
        //...
    }
}

or, have the container inject the dependency:

@Stateless
public class CarSalon {

  @EJB
  private Car car;
  //...

  public void testDrive() {
    car.startEngine();
    //...
  }
}

Either way, the container will get you a fully initialized instance of the bean from the bean pool. And all the injections start working again.

2.) POJO injection

By POJO injection, we can mean two different things: injecting POJOs into Beans, or injecting Beans into POJOs.

Unless we are using CDI (which may be the topic of another post), we cannot inject a POJO into a session bean. You can only inject EJBs into EJBs. Intuitively, you cannot use the @EJB annotation to inject a POJO (as it is not an EJB), also, you can only look up EJBs using the InitialContext (as POJOs have no JNDI names). In one sentence, without CDI you cannot inject POJOs anywhere.

The other way around, is possible, though. You can use a fully initialized EJB in your POJO code. The @EJB annotation will not work, as only an EJB can be injected into another EJB using annotations. However, your object needs not be an EJB to be able to use the InitialContext.lookup() mechanism (provided that there actually is a container running under your application).

Note that starting from EJB 3.1, JNDI names are standardized. If (using the example above) we suppose that we have an EAR called Salon_EAR amd an EJB project, called Salon_EJB then the JNDI name for the object Car is:  java:global/Salon_EAR/Salon_EJB/Car.

3.) EJB injection and constructors

This one is related to Glassfish(3.1.1) application server and perhaps several others (some other app servers may support this, but Glassfish is the reference implementation, so…)

Let’s get back to the car salon example above. Given this piece of code:

@Stateless
public class CarSalon {

  @EJB
  Car car;

  public CarSalon() {
    car.startEngine();
  }

  // ...
}

Surprisingly enough, this code will throw a NullPointerException in deploy time. The Car object injected using the @EJB annotation is not available in the constructor. And no, it’s not because CarSalon is created first and Car second (you can even annotate the Car class with @Startup to be sure about the initialization sequence).

What is the solution then? Is there no way of using container managed objects in the object initialization process? There is, fo course. Let’s move all the logic from the constructor into a @PostConstruct method. The code now looks like this:

@Stateless
public class CarSalon {

  @EJB
  Car car;

  public CarSalon() {
    System.out.println("Constructor");
  }

  @PostConstruct
  public void init() {
    System.out.println("PostConstruct");
    car.startEngine();
  }

  // ...
}

And guess what, this actually gets deployed. The post construct block will run as part of the initialization process, but still outside the constructor. It even makes your code cleaner since we all know that it is not a good idea to place work in the constructor. Not to say that all the injected resources are available in such methods.

Advertisements

Author: tamasgyorfi

Senior software engineer, certified enterprise architect and certified Scrum master. Feel free to connect on Twitter: @tamasgyorfi

3 thoughts on “JavaEE dependency injection – common mistakes”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s