Monday, January 30, 2017

Using CDI/Weld to Inject JPA/Hibernate Entity Managers

In this post we'll learn how easy it is to leverage the power of CDI (Contexts and Dependency Injection) / Weld in the development of a full-blow JPA / Hibernate application. The inherently permissive nature of CDI allows to turn literally any class into an injectable component, thus making the injection of Java EE resources as easy as injecting POJOs. This means that, for example, entity managers and even datasources objects can be injected anywhere by using just a few custom qualifiers.

This is a very powerful - yet pretty underrated - feature, quite often overlooked by CDI newcomers, who just don't know that the standard provides this functionality out of the box. Let's see now how to make an entity manager an injectable resource and build a simple JPA application from the ground up!

In a recent article I covered the basics of the CDI / Weld tandem, ranging from using the @Default, @Alternative and @Producesannotations, to working with a few more distilled features, such as polymorphic injection points and custom qualifiers. I used them to develop a naive standalone application, which showed how to inject different implementers of a simple interface into a client object at run time to parse a string entered in the console. We will use these skills now, so if you're not entirely sure how to do those things, read up on it - I'll wait.

Considering that we'll be working extensively with JPA / Hibernate in this walkthrough, I assume that you have at least a minimal background on them - otherwise check this Hibernate tutorial.

Creating an Injectable Entity Manager

The crux of the matter of any CDI-based JPA application is the creation of an injectable entity manager. It's worth noting that regardless of the approach that we use to get the manager, once it becomes an injectable Java EE resource, the entirety of the examples shown in the rest of the post are equally valid. From that point onward, creating and injecting all sort of objects across different layers is quite simple.

So the first task that we need to tackle is exactly that one: making the entity manager an injectable resource. In doing so, we can bind JPA to Hibernate (the reference JPA implementation) and run CRUD operations on some naive JPA entities without hassle.

In fact, there are a few straightforward approaches that we can pick from to accomplish this.

Using the @PersistentContext Annotation

The most painless way, which only works with a Java EE application server, such as Apache TomEE, JBoss Widlfly or Jetty, is the @PersistenceContext annotation. As we might expect, this methodology binds a persistence context (and a persistence unit, of course) to an entity manager, and the manager's lifecycle is entirely managed by the container (aka a container-managed entity manager).

At a broadly generic level, this approach can be implemented by using a custom qualifier like this:

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD,
        ElementType.TYPE, ElementType.PARAMETER})
public @interface MySQLDatabase {}

public class EntityManagerProducer {

    @Produces
    @PersistenceContext(unitName = "my-persistence-unit")
    @MySQLDatabase
    private EntityManager entityManager;

}

In this case, the unitName attribute specifies the name of a sample persistence unit associated with the corresponding persistence context. So, if you're going to use this approach, make sure the name matches the one specified in Hibernate's persistence.xml file.

With that code in place, a simple DAO class that takes the entity manager in the constructor can be defined as follows:

public class MyDao {

    private EntityManager entityManager;

    @Inject
    public MyDao(@MySQLDatabase EntityManager entityManager) {
        this.entityManager = entityManager;
    }

}

While this will work with a fully-qualified Java EE container (feel free to give it a try if you already have one installed on your system), we don't want to rely on that particular method, since we won't be using a Java EE container for running the JPA application presented in this article.

Using a Producer Method

Just plain Java, CDI, and Weld should get the job done for us. How do we do the injection of the manager in this environment? Well, we can encapsulate the creation of a non-managed entity manager inside a producer method and bind to it a custom qualifier, as follows:

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD,
        ElementType.TYPE, ElementType.PARAMETER})
public @interface MySQLDatabase {}

public class EntityManagerProducer {

    @Produces
    @MySQLDatabase
    public EntityManager createEntityManager() {
        return Persistence
                .createEntityManagerFactory("my-persistence-unit")
                .createEntityManager();
    }

    public void close(
            @Disposes @MySQLDatabase EntityManager entityManager) {
        entityManager.close();
    }

}

In this case, the createEntityManager() method is responsible for creating the non-managed entity manager through an entity manager factory. As with the first approach, the name of the persistence unit passed to the createEntityManagerFactory() method must be the same as the one defined in Hibernate's configuration file. Make sure to do that, before you pull out your hair trying to figure out why Hibernate can't find a persistence unit to work with.

This is JPA at its most elemental level, so the only point worth stressing here is the use of the @Disposes annotation. It informs the CDI container that this method closes the entity manager, which makes the container call it before releasing the manager.

At this stage, we've managed to create a fully injectable entity manager with a simple producer method. But let's think through this: Why should we bother ourselves with the twist and turns of this process, if we're not going to use the manager in a productive way? Yikes!

As we saw earlier, a typical use case is to inject the manager into a DAO class, something that would allow us to perform CRUD operations on some JPA entities through an easily consumable API, and, best of all, without having to unnecessarily expose from top to bottom the manager's API to client code. The most effective way to design this distilled, abstract API is by implementing a simple data access layer (DAL). CDI makes building this layer a breeze, but as usual, an example would help us understand the inner workings of this process much more easily.

[caption id="attachment_146280" align="aligncenter" width="1024"]Published by Sean Michael Ragan under CC-BY 2.0 Published by Sean Michael Ragan under CC-BY 2.0[/caption]

Abstracting Data Access with a Basic Data Access Layer (DAL)

Continue reading %Using CDI/Weld to Inject JPA/Hibernate Entity Managers%


by Alejandro Gervasio via SitePoint

No comments:

Post a Comment