Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Using Dependency Injection with Java EE

DZone's Guide to

Using Dependency Injection with Java EE

When Java EE 6 introduced the CDI specification, Java EE finally included dependency injection horizontally. Here are some examples that show how to use CDI with some Java EE specifications.

· Java Zone
Free Resource

Learn how to troubleshoot and diagnose some of the most common performance issues in Java today. Brought to you in partnership with AppDynamics.

Before Java EE 6, components could be injected in the following ways:

  • Through the @EJB annotation, where your class needs to be an EJB or Servlet.

  • Through the @Resource annotation, where your class needs to be an EJB or Servlet.

  • Through the @WebServiceRef annotation in web services.

  • Using a framework that implements DI such as: Spring (@Autowired) or JBoss Seam (@In), among others.

When Java EE 6 introduced the Contexts and Dependency Injection (CDI) specification, I was amazed that Java EE finally included dependency injection (DI) horizontally. In other words, any component can be injected into any other component, regardless of whether it's an EJB, a web service, or a POJO. Thus, you can inject a component from a Java EE container using the @Inject annotation, since the file named beans.xml is present in the WEB-INF/META-INF directory to indicate to the container which classes should be scanned.

Some questions appeared in my head after the new spec was released, and I considered the following:

  • Regarding the frameworks that provide DI: do I have to migrate to Java EE and forget they exist? No, you must think in CDI when you want to migrate a full profile of Java EE container.

  • Regarding the @EJB annotation: is it now deprecated? No, you can use the @EJB annotation normally, but this annotation isn't needed when you want to inject local components. In this case, I suggest to use @Inject and forget @EJB because CDI attends to both components.

  • Which annotation should be used with JSF: @Named or @ManagedBean? @Named, because some JSF annotations were created to provide similar features offered by the CDI spec, and now they should be discontinued on my vision.

Based on my above considerations, I created five examples that show how to use CDI with some Java EE specifications.

Example 1 - CDI and JAX-WS:

@WebService(portName = "HelpSoapPort", serviceName = "HelpSoapService", 
            name = "HelpWS", targetNamespace = "http://localhost:8080")
public class HelpSoap {

    @Inject HelpCDIService helpCDIService;
    @Inject HelpEJBService helpEJBService;

    @WebMethod
    public String ping() {
        return helpEJBService.ping();
    }
}


In the example above, both components (CDI and EJB) can be injected using the @Inject annotation and applicable within a web service SOAP.

If you want to change the web service to be an EJB, you just have to include an @Stateless, @Stateful, or @Singleton annotation, and no more.

Example 2 - CDI and JAX-RS:

@Path("/helps")
public class HelpsResource {

    @Inject HelpCDIService helpCDIService;
    @Inject HelpEJBService helpEJBService;

    @GET
    @Path("/ping")
    public String ping() {
        return helpEJBService.ping();
    }
}


For the JAX-RS spec, you can do the same thing described previously.

Example 3 - CDI and EJB:

@Stateless
public class HelpEJBService {

    @Inject AnotherHelpEJBService anotherHelpEJBService;

    public String ping() {
        return anotherHelpEJBService.ping();
    }
}


For the EJB spec, you can also use the @Inject annotation to inject another EJB.

Example 4 - CDI and JSF:

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
...
@Named
@RequestScoped
public class FooNamedController {

    @Inject HelpEJBService helpEJBService;

    public String displayWelcomeMessage() {
        return helpEJBService.displayWelcomeMessage();
    }
}


For JSF I suggest using CDI both for exposing components to XHTML pages and for defining scopes. But if you want to use the @ManagedBean annotation with the view scope provided only by JSF, you continue to be able to use CDI, as shown below:

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.inject.Inject;
...
@ManagedBean
@ViewScoped
public class FooManagedBeanController {

    @Inject HelpEJBService helpEJBService;

    public String displayWelcomeMessage() {
        return helpEJBService.displayWelcomeMessage();
    }
}

Example 5 - CDI and JNDI:

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.annotation.Resource;
import javax.ejb.Singleton;
import javax.enterprise.inject.Produces;
import javax.inject.Qualifier;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
import javax.sql.DataSource;
import javax.xml.ws.WebServiceRef;

@Singleton
public class JavaEEContainerResourceAdaptor {

    @Qualifier
    @Target({ TYPE, METHOD, PARAMETER, FIELD })
    @Retention(RUNTIME)
    public @interface DefaultDataSource {}

    @Produces
    @WebServiceRef(lookup = "java:app/foo-app/HelpSoap")
    static HelpSoap helpSoap;

    @Produces
    @Resource(lookup = "java:jboss/datasources/ExampleDS")
    @DefaultDataSource
    static DataSource defaultDS;

    @Produces
    @PersistenceContext(unitName = "DefaultPU")
    @DefaultDataSource
    EntityManager defaultEntityManager;

    @Produces
    @PersistenceUnit(unitName = "DefaultPU")
    @DefaultDataSource
    EntityManagerFactory defaultEntityManagerFactory;
}


The code above shows how to provide JNDI resources to be injected using CDI. You need to create an adaptor to expose the resources as producer fields. You can also expose resources as producer methods, but the simpler way is using the @Resource annotation.

Below you'll see how to inject these resources using the @Inject annotation and the @DefaultDataSource qualifier from a RESTful web service:

@Path("/helps")
public class HelpsResource {

    private static final int VALIDATION_TIMEOUT_IN_SECONDS = 30;

    @Inject
    @DefaultDataSource
    DataSource dataSource;

    @GET
    @Path("/ping/db")
    public String pingDB() {
        Boolean connected = false;
        try {
            connected = dataSource.getConnection().isValid(
            VALIDATION_TIMEOUT_IN_SECONDS);
        } catch (SQLException e) {
            connected = false;
        }
        return connected ? "Pong!" : "Sorry :(";
    }
}

Conclusion

CDI is quite powerful and will continue being the dependency injection mechanism of Java EE for a long time. I also believe that gradually specifications that provide some kind of DI like EJB will be replaced by features offered by the CDI.

Understand the needs and benefits around implementing the right monitoring solution for a growing containerized market. Brought to you in partnership with AppDynamics.

Topics:
java ,java ee ,cdi ,ejb ,jax-rs ,jax-ws

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}