EJB Dependency injection misunderstandings

When I’m doing interviews, I like to ask the following question (provided that the candidate has real life experience with EJBs):

There are two stateless session beans, A and B. A has a dependency on B; at what point can bean A use its injected (@EJB) dependency?

This turns out to be a tough question, as most people get it wrong. I’ve already heard a load of answers, but the most common ones are these: “anywhere if we use constructor injection”, “in the body of the business methods” and “the body of the constructor” (this is the most common one, actually). Let’s see how it really is, and why these answers are not (entirely) correct.

1.) Anywhere with constructor injection: Constructor injection is not possible with EJBs only; it is only available in JavaEE if you enable CDI (put an empty beans.xml file in your META-INF directory). That  is, however, a different story, so let’s skip CDI for this post. This means that we are left with enterprise beans only (@EJB injection style), in which case the following code will not work; it will not even compile, as the @EJB annotation is disallowed for constructors:

@EJB
public EjbA(EjbB ejbB) {
  this.ejbB = ejbB;
  // ...
}

public void doSomeWork() {
  ejbB.calculate();
  // ...
}

2.) In the body of a business method: Strictly speaking, this answer is not entirely wrong. Dependency injection would be completely useless if it was not available for business methods, so, this code will just work fine:

@EJB
private EjbB ejbB;

public EjbA() {
  // ...
}

public void doBusiness() {
  ejbB.calculate();
 // ...
}

Although this code is functional, the answer cannot be considered a good one, since a business method is not our earliest possibility to work with injected dependencies.

3.) The body of the constructor: let’s take an example. Consider the following code:

@EJB
private EjbB ejbB;

public EjbA() {
  ejbB.calculate();
}

Usually it is a bad idea to place any work in the constructor, but this is never truer than in our case. Surprise, this piece of code will not work, but throw a NullPointerException upon deployment. Why? Let’s see how EJBs are created by the container.

The EJB 3.1 specification mandates that every EJB has a public, default constructor (again, when CDI comes into play, this requirement is relaxed, but that’s a different story). The specification requires some pooling logic is present for Stateless and Message Driven Beans, (some containers will also pool Stateful beans too – even though it’s not required by the spec), so instances have to be created to populate the bean pool. In order to achieve that, the container reflectively calls the public, default constructor. By the time the constructor has completed, there is nothing injected into the EJB. From DI perspective, at this point our EjbA bean is just a simple, normal Java object, and its state is the very same as it would have been if we had instantiated it using the new operator.

As soon as the construction is complete, the magic kicks in and the container starts injecting all the dependencies the EJB has. After that process is finished, a construction finished event is fired; if the bean is registered for this event -e.g. it has defined a @PostConstruct method -, the container will call this method, which turns out to be the very first point in the lifecycle of an EJB, where any of the injected EJBs are available.

In short, the @PostConstruct lifecycle callback method is the answer to the question. That is the first point where EJB B will be available to EJB A. Trying to reference those dependencies any sooner will result in a NullPointerException.

Advertisements

Author: tamasgyorfi

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

One thought on “EJB Dependency injection misunderstandings”

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