Maven and Gradle Hibernate Enhance Plugin

Imagine having a tool that can automatically detect JPA and Hibernate performance issues. Hypersistence Optimizer is that tool!

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 take the following steps in order to enable the JPA entity bytecode enhancement mechanism.

First, you need to add the hibernate-gradle-plugin dependency:

buildscript {
    repositories {
        mavenLocal()
        mavenCentral()
    }
    dependencies {
        classpath "org.hibernate:hibernate-gradle-plugin:$hibernateVersion"
    }
}

Second, you need to apply the hibernate-gradle-plugin, like this:

apply plugin: 'org.hibernate.orm'

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 the addChild and removeChild 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.

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.

Transactions and Concurrency Control eBook

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.