Maven and Gradle Hibernate Enhance Plugin
Imagine having a tool that can automatically detect JPA and Hibernate performance issues. Wouldn’t that be just awesome?
Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, or Play Framework.
So, enjoy spending your time on the things you love rather than fixing performance issues in your production system on a Saturday night!
Introduction
In this article, I’m going to explain how the configure the Maven and Gradle Hibernate Enhance Plugin.
The goal of the Hibernate Enhance plugin is to instrument the JPA entity bytecode in order to improve the effectiveness and efficiency of the associated data access operations.
Maven Hibernate Enhance Plugin
For Maven, Hibernate offers the hibernate-enhance-maven-plugin
that allows you to enable JPA entity bytecode enhancement.
So, in your project pom.xml
Maven configuration file, you need the following plugin:
<plugin> <groupId>org.hibernate.orm.tooling</groupId> <artifactId>hibernate-enhance-maven-plugin</artifactId> <version>${hibernate.version}</version> <executions> <execution> <configuration> <enableLazyInitialization>true</enableLazyInitialization> <enableDirtyTracking>true</enableDirtyTracking> <enableAssociationManagement>true</enableAssociationManagement> <enableExtendedEnhancement>false</enableExtendedEnhancement> </configuration> <goals> <goal>enhance</goal> </goals> </execution> </executions> </plugin>
Gradle Hibernate Enhance Plugin
If you’re using Gradle, then in the build.gradle
configuration file, you need to add the following plugin in order to enable the JPA entity bytecode enhancement mechanism.
plugins { id "org.hibernate.orm" version hibernateVersion }
Last, in order to configure the execution of the bytecode enhancement plugin, you need to add the following configuration:
hibernate { enhance { enableLazyInitialization = true enableDirtyTracking = true enableAssociationManagement = true enableExtendedEnhancement = false } }
Configuring the Maven and Gradle Hibernate Enhance Plugin
As you have already seen, there are four properties you can configure:
enableLazyInitialization
enableDirtyTracking
enableAssociationManagement
enableExtendedEnhancement
By default, all these settings are set to the value of false
, so if you need to enable a given bytecode enhancement setting, you have to do it explicitly.
Maven and Gradle Hibernate Enhance Plugin – enableLazyInitialization
By setting the enableLazyInitialization
to true
, Hibernate changes the bytecode of the getter and setter methods to intercept the call and trigger the property initialization on demand.
So, the entity class Java Bean getter and setter methods are going to be changed from this:
public PostDetails getDetails() { return details; } public void setDetails(PostDetails details) { this.details = details; }
to this:
public PostDetails getDetails() { return this.$$_hibernate_read_details(); } public void setDetails(PostDetails details) { this.$$_hibernate_write_details(details); } public PostDetails $$_hibernate_read_details() { if (this.$$_hibernate_getInterceptor() != null) { this.details = (PostDetails) this.$$_hibernate_getInterceptor() .readObject( this, "details", this.details ); } return this.details; } public void $$_hibernate_write_details(PostDetails details) { if (this.$$_hibernate_getInterceptor() != null) { this.details = (PostDetails) this.$$_hibernate_getInterceptor() .writeObject( this, "details", this.details, details ); } else { this.details = (PostDetails) details; } }
The $$_hibernate_getInterceptor
method that’s being called looks as follows:
public PersistentAttributeInterceptor $$_hibernate_getInterceptor() { return this.$$_hibernate_attributeInterceptor; }
And the $$_hibernate_attributeInterceptor
object is defined like this:
@Transient private transient PersistentAttributeInterceptor $$_hibernate_attributeInterceptor;
So, as you can see, the bytecode has changed significantly.
For more details about the
enableLazyInitialization
bytecode enhancement option and how you can use it to load entity attribute lazily, check out the following two articles:
Maven and Gradle Hibernate Enhance Plugin – enableDirtyTracking
The enableDirtyTracking
option allows you to record which properties have changed so that the Hibernate dirty checking mechanism gets the list of changes without having to inspect every property via Java Reflection.
Once you activate the enableDirtyTracking
option, you will see that the entity property Java Beans setters are changed like this:
public void setDetails(PostDetails details) { this.$$_hibernate_write_details(details); } public void $$_hibernate_write_details(PostDetails details) { if (!Objects.deepEquals(details, this.details)) { this.$$_hibernate_trackChange("details"); } this.details = details; }
The $$_hibernate_trackChange
method looks as follows:
public void $$_hibernate_trackChange(String property) { if (this.$$_hibernate_tracker == null) { this.$$_hibernate_tracker = new SimpleFieldTracker(); } this.$$_hibernate_tracker.add(property); }
The SimpleFieldTracker
will then store the entity properties that were modified and provide this information to the dirty checking mechanism when the Persistence Context is flushed.
Maven and Gradle Hibernate Enhance Plugin – enableAssociationManagement
The enableAssociationManagement
option tries to address the requirement of synchronizing both sides of a bidirectional association.
So, instead of relying on you to provide addChild
and removeChild
methods in the parent entity, Hibernate changes the setter methods:
public void setDetails(PostDetails details) { this.$$_hibernate_write_details(details); } public void $$_hibernate_write_details(PostDetails details) { if (this.details != null && Hibernate.isPropertyInitialized( this.details, "post" ) && details == null ) { ((PostDetails)this.details).$$_hibernate_write_post((Post)null); } this.details = details; if (details != null && Hibernate.isPropertyInitialized(details, "post") && ((PostDetails)details).$$_hibernate_read_post() != this) { ((PostDetails)details).$$_hibernate_write_post(this); } }
The
enableAssociationManagement
cannot intercept changes happening in a collection of child entities, and, for this reason, you are better off using theaddChild
andremoveChild
methods.
Maven and Gradle Hibernate Enhance Plugin – enableExtendedEnhancement
The enableExtendedEnhancement
option allows the bytecode enhancement mechanism to instrument methods beyond getter and setters.
So, consider that your entity has the following utility method:
public boolean contains(PostComment comment) { return this.comments.contains(comment); }
If you enable the enableExtendedEnhancement
option, the Hibernate can enhance this method as well:
public boolean contains(PostComment comment) { return this.$$_hibernate_read_comments().contains(comment); }
This will allow you to initialize or track changes happening to entity properties even outside the scope of getter or setter methods.
When it comes to getter and setters, the method definition is rather straightforward, and the automatic bytecode instrumentation outcome can be deterministic. However, other methods might be more complex, and if you enable the enableExtendedEnhancement
option, it could be that the bytecode enhancement mechanism makes unintended changes, so you should be very careful when enabling this option.
I'm running an online workshop on the 11th of October about High-Performance SQL.If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.
Conclusion
The Maven Gradle Hibernate Enhance Plugin allows you to instrument the JPA entity properties so that you can enable property-level lazy loading, track changes, or synchronize bidirectional associations.
