The Java Persistence API provides a programming language framework for managing relational data through entity management and ORM APIs. Libraries like Hibernate and Guice Persist implement the services defined in the JPA specification. The result is an abstraction layer that manages the underlying concerns of a relational database while providing a consistent API that doesn’t vary from one database to another.
However, even with a database abstraction layer, there are instances where the concerns of the database are also the concerns of the programmer. Moreover, these concerns can affect a number of areas in an application, and addressing them often leads to code duplication.
Aspect-oriented programming (AOP) is a programming paradigm that addresses cross-cutting concerns and eliminates the need for code duplication. Guice has built-in support for method interception that brings the AOP programming paradigm to life.
Transactions
Transactions are commonplace in database programming and are often required when updating or saving an entity. Transactions are a cross-cutting concern, which means programmers may find themselves dealing with transactions throughout their codebase.
For example, we may want to encapsulate any change made to an entity in a transaction where we commit it on success and rollback any changes if we encounter an error.
The code above is concerned with persisting an entity to the database. However, the bulk of code is dealing with creating, starting, and either committing or rolling back a transaction.
Luckily for us, Guice Persist has provided a solution to this problem where our above code is reduced to:
…where the Transactional
annotation indicates that the save
method should be wrapped in a transaction (a subclass is generated at runtime where a new method is defined that wraps a transaction around the original save implementation). The save method is now only concerned with persisting the entity and isn’t dealing with any extraneous concerns.
An Example Problem
Stale Data: A Cross-Cutting Concern
A common issue that we’ve come across using JPA and Hibernate is that data can become stale and out-of-date over a period time. The main reason for this is that entity managers are not thread-safe. The solution to this issue is to use thread local entity managers, which in turn maintain their own persistence context.
It’s likely that entities in one persistence context may differ from another persistence context across different threads. Until they are explicitly refreshed and synchronized with the database, they’ll remain out-of-date or stale. For example, one entity may have had its name updated, and entities that it owns could have been removed. It will remain unaware of these changes until it has been refreshed.
An Initial Solution
In order to ensure that entities are up-to-date, we need to make sure they are refreshed before using them:
The problem with this particular solution is that each time we lookup and return an entity or set of entities, we have to duplicate the code that refreshes the entities.
One Step Further
The next step would be to abstract the refresh code into a helper method (or delegate it to another object):
The above solution is obviously DRYer than our first one. However, we are still concerning ourselves with refreshing entities while our primary responsibility lies in looking up entities. Additionally, this particular solution only works for SchoolBus
entities and would require creating similar code for other entity types.
Aspect-Oriented Solution
The problem with our above solutions is that we are duplicating code and forcing the code to address the refreshing of entities.
We want a solution that:
- Doesn’t require that we duplicate code.
- Allows the code to focus on its primary concern by automatically refreshing the entity and any entities it may own.
- Works across a heterogenous set of entities.
…and looks like:
Implementation
While the transaction example in the previous section seems somewhat “magical,” it’s actually relatively straightforward to implement our own AOP solution. It requires that we create an annotation, a class that implements the MethodInterceptor interface, and setup Guice bindings in a injector module.
The RefreshEntity Interface
The Method Interceptor
The full implementation of the method interceptor can be found here. The RefreshEntityInterceptor
ensures that any entity retrieved is properly refreshed before it is returned to its caller.
Specifically, it does the following:
- Invokes the method annotated with the
RefreshEntity
interfaces. - Determines whether the result is a single entity or a collection of entities.
- Clears any collections that are defined as
OneToMany
relationships. - Refreshes the entity and returns it.
Guice Bindings
In our injector module, we need to create an interceptor binding to ensure that any methods that are annotated with RefreshEntity
are dynamically subclassed and wrapped by the RefreshEntityInterceptor
.
Conclusion
Even with a relatively nice data abstraction layer, there instances where the concerns of the database or the entity management layer become the concern of the programmer as well. Using the Aspect-oriented programming techniques and Guice, we can isolate those concerns into one or a few areas and keep the rest of our codebase relatively free of data layer issues.
you need to call UnitOfWork.end() to close the EM at the end of your request/transaction(whatever) and you won’t have the problem anymore