Table of Contents
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 @Produces
annotations, 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.
Frequently Asked Questions (FAQs) about CDI, Weld, JPA, Hibernate, and Entity Managers
What is the role of CDI in Java and how does it interact with Weld?
Contexts and Dependency Injection (CDI) is a standard dependency injection framework included in Java EE 6 and above. It provides a robust and comprehensive solution to manage your application’s services, enhancing modularity, and promoting loose coupling. Weld is the reference implementation of CDI. It provides advanced integration with Servlet containers and Java EE application servers, allowing you to leverage the full power of CDI in your applications.
How does Hibernate work with JPA?
Hibernate is a popular Object-Relational Mapping (ORM) tool in Java, which implements the Java Persistence API (JPA). JPA is a specification that describes the management of relational data in applications using Java Platform, Standard Edition, and Java Platform, Enterprise Edition. Hibernate provides a powerful, high-performance implementation of the JPA specification, making it easier to work with relational databases in Java applications.
How can I use Entity Manager in CDI extension?
Entity Manager is a crucial component in JPA, responsible for managing the persistence operations on entities. To use it in a CDI extension, you need to inject it using the @Inject annotation. However, remember that the Entity Manager is not thread-safe, so it should not be used in a shared context.
What are the common issues when using Hibernate with CDI and how can I resolve them?
Some common issues include transaction management problems, lazy loading issues, and missing bean exceptions. These can be resolved by ensuring proper transaction boundaries, using fetch joins or entity graphs for lazy loading, and correctly configuring your beans.xml file.
How can I integrate Hibernate with TomEE?
Apache TomEE is a lightweight, yet powerful, JavaEE Application server. It supports JPA out of the box, so integrating Hibernate is straightforward. You need to include the Hibernate libraries in your application and configure the persistence.xml file to use Hibernate as the JPA provider.
How can I handle missing bean exceptions when using Hibernate Search as a JAR?
Missing bean exceptions typically occur when CDI cannot find a bean to inject. This can be resolved by ensuring that the bean is correctly annotated and that it is located in a bean archive (a JAR file with a beans.xml file in the META-INF directory).
How can I use Weld with a Servlet container?
Weld provides excellent integration with Servlet containers. You need to include the Weld Servlet library in your application and configure the web.xml file to use the Weld listener and filter.
How can I manage transactions in a CDI application?
Transaction management is a crucial aspect of any enterprise application. In a CDI application, you can manage transactions using the @Transactional annotation. This annotation can be applied to methods or classes, and it instructs the CDI container to automatically start and commit/rollback transactions.
How can I optimize the performance of Hibernate in my application?
Hibernate provides several features to optimize performance, including lazy loading, caching, and batch processing. You can also optimize the performance by writing efficient HQL queries and by using the Criteria API for complex queries.
How can I debug issues in my CDI application?
Debugging CDI applications can be challenging due to the dynamic nature of dependency injection. However, Weld provides a built-in development mode that provides detailed logging and validation. You can also use standard Java debugging techniques, such as setting breakpoints and inspecting variables.
Alejandro Gervasio is a senior System Analyst from Argentina who has been involved in software development since the mid-80's. He has more than 12 years of experience in PHP development, 10 years in Java Programming, Object-Oriented Design, and most of the client-side technologies available out there.