Java - - By Alejandro Gervasio

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.

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

While it’s of course possible to run CRUD operations on JPA entities by using the entity manager as a standalone component, in doing so we’d be missing out on the benefits of three big pillars of object-oriented design. The first one is dependency injection itself (that’s why there’s a DI in CDI after all), the second one is separation of concerns, the third one is abstraction.

A data access layer is an additional tier that accesses the underlying storage mechanism (in this case a MySQL database, but it could be anything else). By implementing at least a basic DAL we’d be killing two birds with one stone: For one thing, we’d be using CDI for injecting the entity manager into this tier and for another thing, we’d be exposing a neat abstract interface for accessing the storage in question to client code.

In this case, the layer will be made up of a generic interface and just one implementation (even though a few more could be added further down the road to swap persistence mechanisms, e.g. others than an entity-relational database, at runtime):

public interface EntityDao<T> {

    T find(int id);

    List<T> findAll(String table);

    void update(int id, Consumer<T>... updates) throws Exception;

    void save(T entity);

    void remove(int id);

}

The above interface models a typical CRUD API, and the implementers honoring it would be able to run CRUD operations on a given entity of type T.

The implementer, on the flip side, is slightly more complex, but it shows in a nutshell how to inject the non-managed entity manager into the constructor of a DAO class:

public class BaseEntityDao<T> implements EntityDao<T> {

    private EntityManager entityManager;
    private Class<T> entityClass;

    @Inject
    public BaseEntityDao(
            @MySQLDatabase EntityManager entityManager,
            @UserClass Class<T> entityClass) {
        this.entityManager = entityManager;
        this.entityClass = entityClass;
    }

    public T find(int id) {
        return entityManager.find(entityClass, id);
    }

    public List<T> findAll(String table) {
        String str = "select e from table e";
        String jpql = str.replace("table", table);
        return entityManager.createQuery(jpql).getResultList();
    }

    public void update(int id, Consumer<T>... updates) throws Exception {
        T entity = find(id);
        Arrays.stream(updates).forEach(up -> up.accept(entity));
        beginTransaction();
        commitTransaction();
    }

    public void save(T entity) {
        beginTransaction();
        entityManager.persist(entity);
        commitTransaction();
    }

    public void remove(int id) {
        T entity = find(id);
        beginTransaction();
        entityManager.remove(entity);
        commitTransaction();
    }

    private void beginTransaction() {
        try {
            entityManager.getTransaction().begin();
        } catch (IllegalStateException e) {
            rollBackTransaction();
        }
    }

    private void commitTransaction() {
        try {
            entityManager.getTransaction().commit();
        } catch (IllegalStateException | RollbackException e) {
            rollBackTransaction();
        }
    }

    private void rollBackTransaction() {
        try {
            entityManager.getTransaction().rollback();
        } catch (IllegalStateException | PersistenceException e) {
            e.printStackTrace();
        }
    }

}

(Note: I’d like to give the corresponding credits to our Java Channel editor Nicolai Parlog, who after some productive feedback on GitHub, provided a more robust implementation of the update() method than the one I originally wrote).

Modeled around a classic Aggregation relationship, the BaseEntityDao class is just an adapter with a declarative API, which performs CRUD operations on a supplied entity. But the class’ actual workhorse (aka the adaptee) that pushes all this functionality behind the API is the injected entity manager! See how easy is to inject the manager into a DAO class by using CDI? I bet you do.

Even better, the class exposes only the CRUD methods to client code, while neatly hiding the entity manager’s entire API, as it isn’t required in this specific domain.

In addition, BaseEntityDao declares a dependency to the domain class that models user entities. Here are the custom qualifier and the producer required for injecting this class:

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

public class UserClassProducer {

    @Produces
    @UserClass
    public Class createUserClass() {
        return User.class;
    }

}

The UserClassProducer class is a typical CDI producer that creates, yes… a User entity class. For the sake of brevity, I haven’t included the entity class here because it looks exactly the same as the one shown in a previous Hibernate post. Feel free to check it there.

At this point, we’ve implemented a functional data access layer, which uses a DAO class for performing CRUD operations on some user entities. While this is pretty handy, as the class can be effectively used in different contexts and scenarios, there’s a tiny detail missing here.

While not strictly mandatory, it’d be nice to implement at least a thin application layer and drop all the functionality required for letting users run CRUD operations through the data access layer into it. This would make even clearer how to utilize CDI / Weld as the underlying DI mechanism in a JPA application.

A Simple Application Layer

There’s a really broad spectrum of environments where our neat data access layer can be consumed, ranging from web and mobile applications, to desktop-based ones. Options are pretty much limitless. To keep things simple, though, we’ll use it for fetching, updating and deleting user entities from a MySQL database, based on a set of numeric options displayed in the console.

Here’s how a simple application layer could be implemented whose functionality boils down to performing a specific CRUD operation on a user entity, according to a string entered in the console. Of course, the dependency that actually runs these operations is an instance of the BaseEntityDao class, which is injected into the constructor along with a BufferedReader object. This collaborator is created with a producer method, as shown in the introductory CDI article.

public class UserApplication {

    private EntityDao<User> userDao;
    private BufferedReader userInputReader;

    @Inject
    public UserApplication(
            BaseEntityDao<User> userDao,
            BufferedReader userInputReader) {
        this.userDao = userDao;
        this.userInputReader = userInputReader;
    }

    public void run() throws Exception {
        // runs until the user quits
        Boolean running = true;
        while (running) {
            System.out.println("Enter an option: "
                    + "1) Insert a new user. "
                    + "2) Find a user. "
                    + "3) List all users "
                    + "4) Edit a user. "
                    + "5) Delete a user. "
                    + "6) Quit the application");
            running = runUserOperation(readUserInput());
        }
    }

    private boolean runUserOperation(String option) throws Exception {
        switch (option) {
            case "1":
                persistNewUser();
                return true;
            case "2":
                fetchExistingUser();
                return true;
            case "3":
                fetchAllExistingUsers();
                return true;
            case "4":
                updateExistingUser();
                return true;
            case "5":
                removeExistingUser();
                return true;
            case "6":
                return false;
        }
        return true;
    }

    private void persistNewUser() throws IOException {
        String name = requestStringInput("the name of the user");
        String email = requestStringInput("the email of the user");
        userDao.save(new User(name, email));
    }

    private void fetchExistingUser() throws IOException {
        int id = requestIntegerInput("the user ID");
        User user = userDao.find(id);
        System.out.println(user);
    }

    private void fetchAllExistingUsers() throws IOException {
        userDao.findAll("User").stream().forEach(System.out::println);
    }

    private void updateExistingUser() throws Exception {
        int id = requestIntegerInput("the user ID");
        String name = requestStringInput("the name of the user");
        String email = requestStringInput("the email of the user");
        userDao.update(id,
                user -> user.setName(name),
                user -> user.setEmail(email));
    }

    private void removeExistingUser() throws IOException {
        int id = requestIntegerInput("the user ID");
        userDao.remove(id);
    }

    private String readUserInput() throws IOException {
        return userInputReader.readLine();
    }

    private String requestStringInput(String request) throws IOException {
        System.out.printf("Enter %s: ", request);
        return readUserInput();
    }

    private int requestIntegerInput(String request) throws IOException {
        System.out.printf("Enter %s: ", request);
        return Integer.parseInt(readUserInput());
    }

}

Last but not least, we should launch the application from within our IDE and see if it actually does what it promises. To do so, we need to programmatically bootstrap Weld and get an instance of the UserApplication class from the Weld container, as following.

public class Main {

    public static void main(String[] args) throws IOException {
        Weld weld = new Weld();
        WeldContainer container = weld.initialize();
        UserApplication userApplication = container.instance()
                .select(UserApplication.class)
                .get();
        userApplication.run();
        weld.shutdown();
    }

}

If everything goes well, we should be prompted to enter a numeric option in the console. This would trigger the insertion, fetching, update or deletion of a user entity from the corresponding MySQL database (except when we enter option 6, as this will just exit the program).

Beyond the limited, rather naive functionality of the example, it comes in handy for showing how to use CDI / Weld in the implementation of a full-blown JPA application, and how powerful the standard is when it comes to doing dependency injection in an effortless way. So, no matter the level of complexity that you want to push into the dependencies of your classes, be it either POJOs, entity managers, datasource objects, you name it: CDI will build your object graphs for you behind the scenes, and best of all, with just a few minimal requirements.

Summary

The CDI / Weld tandem makes building JPA applications a no-brainer process, as the standard facilitates the creation of injectable entity managers, either by using the @PersistentContext annotation, or a combination of producer methods and custom qualifiers.

Regardless of the approach you’re using for assembling your object graphs (because you’re doing dependency injection, right?), CDI is here to stay. Some might argue that the standard is too verbose and performs the injection(s) at expenses of unnecessarily polluting your code with a bunch of annotations and factories, and certainly they’d be right, at least to some extend. After all, an injector should ideally do its thing in a transparent, silent way, hence preserving the integrity of its outsider condition. Application logic should always be completely agnostic about the existence of the injector.

But having such an utopian mindset, far away from pragmatism, doesn’t buy us anything really useful. We all know that CDI (and every ORM framework available out there) avidly consumes the Reflection API to do its work, along with a set of standardized annotations.

If you don’t mind living with this, then CDI will make your life a lot easier. On the flip side, if you’re more orthodox and feel more comfortable using plain, old-school factories and builders for constructing your object graphs, well, that’s fine too.

Sponsors
Login or Create Account to Comment
Login Create Account