Background
The Java Persistence API (JPA) provides Java developers with an object/relational mapping facility for managing relational data in Java applications. The latest version of the JPA standard is 2.1 and is part of Java EE 7.
JBoss Enterprise Application Platform is a fully certified Java EE application server and JBoss EAP 7 which is currently in Beta is certified according to the most recent Java EE 7 specification.
Hibernate is one of the most popular JPA implementations and is known for it’s High Performance, Scalability and Reliability.
For more details about JPA and Hibernate I recommend reading Java Persistence with Hibernate, Second Edition.
What’s new in JPA 2.1
Querying Stored Procedure
Using stored procedures to implement parts of the application logic in the database is a widely used approach in huge, data heavy applications. Nevertheless there was no good support for them before JPA 2.1. You had to use a native query, to call the stored procedure in the database.
Since the JPA 2.1 release, JPA supports two different ways to call stored procedures, the dynamic StoredProcedureQuery and the declarative @NamedStoredProcedureQuery.
Code example calling a dynamic SP Query:
The above code example uses Arquillian to deploy and call a stored procedure call my_sum. The stored procedure in this example is a PostgreSQL function.
Attribute Converter
Attribute Converter provides a nice and easy way to define a custom mapping between an entity property and a database column. The only thing that is needed is a class that implements the AttributeConverter interface. This is particularly useful for encrypting things like passwords and credit card details. Another good usage for Attribute Converter is to implement a custom type mapping to persist a non-supported data type like the new Java Date and Time API. However as you will see later in this article Hibernate 5 already has support for that.
Below is an example where we use Base64 encoder to store the user's password in the database:
Constructor Result Mapping
The @ConstructorResult annotation is a handy addition to the already existing @SqlResultSetMapping and can be used to map the result of a query to a constructor call.
Programmatic Named Queries
Before JPA 2.1 the @NamedQuery annotation was the only way to define named queries. A programmatic creation was not supported. This was changed with JPA 2.1. The EntityManagerFactory now provides the addNamedQuery(String name, Query query) method to do this.
Named Entity Graph
Lazy loading was often an issue with JPA 2.0. You have to define at the entity if you want to use FetchType.LAZY (default) or FetchType.EAGER to load the relation. FetchType.EAGER is used if we want to always load the relation upon fetching the root entity. FetchType.LAZY is used to delay the association loading, and to get a well performing and scalable application.
But this is not without drawbacks. If you need to access a LAZY property, you need to make sure that the relation gets initialized within the transaction and while the Persistence Context is open. This can be done by using a specific query that reads the entity and the required relations from the database. But this will result in use-case specific queries. Another option is to navigate the relation within your business code which will result in an additional query executed for each lazy relation. Both approaches are far from perfect.
JPA 2.1 entity graphs are a better solution for it. The definition of an entity graph is independent of the query and defines which attributes to fetch from the database. An entity graph can be used as a fetch or a load graph, giving additional possibility to tweak queries.
JPQL Enhancements
There were several enhancements to the JPQL which can come in handy. You can now use the keyword ON to define additional join clause criteria, call database functions by using FUNCTION and downcast entities with TREAT.
Criteria API Bulk Operations
Prior to JPA 2.1 the Criteria API did not provide any support for update or delete operations. The only options available were to perform the update on an entity or to write a native query to update multiple records at once.
Unsynchronized Persistence Context
Using a synchronized persistence context to propagate every change to the database is the default approach in JPA. If you need more control over when changes are propagated to the database, you can now use the unsynchronized persistence context. Therefore you need to provide the synchronization mode to the injection with @PersistenceContext(synchronization=SynchronizationType.UNSYNCHRONIZED). You then need to call EntityManager.joinTransaction() manually to synchronize the changes.
Generating DB Schema
Up to JPA 2.1 you needed to use vendor-specific configuration parameter to define the database setup in the persistence.xml file. Starting from version 2.1 there is also a standard way to do this.
CDI-Support in Entity Listener
The integration with CDI was improved with JPA 2.1. You can now use CDI to inject beans into EntityListeners and to implement the @PreDestroy and @PostConstruct methods.
Hibernate and JBoss EAP 7 Specific Features
Hibernate is a great JPA implementation and, although you might not need to consider other JPA provider, as a developer, you should always strive to avoid locking your code to a particular framework or product. This becomes even more important if you are using a closed source (proprietary) alternative. Therefore, I strongly recommend to use the following feature with caution and evaluate the benefits of using it to the potential future cost of migrating away from it.
Java 8 Date Time API
Date and Time has for a long time been a problem of Java and for O/R mapping there are also the ambiguous relations between java.util.Date and java.sql.Date. To make things even worse java.util.Date class is not Thread safe or immutable. Java 8 offers a solution to this with the Java Date Time API located in the java.time package.
Since JPA 2.1 is connected to Java EE 7 which in turn depends on Java 7 or later the current JPA standard does not include support for Java 8 Date Time API. However, this is likely to be part of future versions of the standard so using it will probably not cause any long term lock-in effects.
In Hibernate 5 (and JBoss EAP 7) the Java 8 Date and Time types are supported in domain model mappings. The mapping between the standard SQL Date/Time types and the supported Java 8 Date/Time class types looks as follows:
-
DATE: java.time.LocalDate
-
TIME: java.time.LocalTime and java.time.OffsetTime
-
TIMESTAMP: java.time.Instant, java.time.LocalDateTime, java.time.OffsetDateTime and java.time.ZonedDateTime
The Hibernate support for Java 8 Date Time API is provided in a separate module called hibernate-java8
, however if you are using JBoss EAP 7 this modules is provided by default and you do not need to add special dependencies etc to use Java 8 Date Time API in JBoss EAP 7.
Here is a test-case accessing a using LocalDateTime as a @Column:
Expanded AUTO id generation support
JPA defines support for GenerationType#AUTO limited to just Number types. Starting in 5.0 Hibernate offers expandable support for a broader set of types, including built-in support for both Number types (Integer, Long, etc) and UUID. Users are also free to plug in custom strategies for interpreting GenerationType#AUTO via the new org.hibernate.boot.model.IdGeneratorStrategyInterpreter extension.
Second Level Caching
Second level caching or 2nd level cache is a great way to improve performance for a Java application that is using a relational database. JBoss EAP 7 second level cache is based on the Infinispan project, but JBoss EAP 7 also provides a customized implementation called SimpleCache that is optimised for the second level caching and early testing shows really promising performance results. I will cover second level cache in more detail in a future article.
Summary
Hibernate 5 and JPA 2.1 contains a number of useful improvements. When JBoss EAP 7 is released it will contain Hibernate 5 and until then you can use JBoss EAP 7 Beta which is available to download for free from http://developers.redhat.com. Please note that the source code for this example is based on an internal test release, but I will update it as soon as EAP 7 is released.
A special thanks to Vlad Mihalcea (@vlad_mihalcea), Gail Badner and Scott Marlow for helping me with comments and suggestions on improvements.
For a working examples of the source code in this article please check out https://github.com/tqvarnst/hibernate5-demos.
Last updated: February 22, 2024