JPersist is a suite of modern, high-performance, and Gradle Configuration Cache-compliant plugins that automate the configuration of enterprise Jakarta Persistence API (JPA) environments. It provides zero-configuration support for Hibernate and EclipseLink multi-module builds.

1. Getting Started

This section covers the requirements and basic setup to start using JPersist plugins in your Gradle project.

1.1. Requirements

  • Gradle: 7.4+ or 8.x+ / 9.x+

  • Java: JDK 17 or higher (required by modern Jakarta specifications)

1.2. Choosing a Plugin

JPersist provides three main plugins depending on your JPA provider:

Plugin ID Description Provider

io.github.jpersist.jpa

Generates or merges persistence.xml descriptors, validates persistence schema against the database schema, generates JPA GraalVM native image metadata (reflect-config.json), and lints @NamedQuery / @NamedStoredProcedureQuery definitions at compile time

Provider-agnostic

io.github.jpersist.hibernate-persistence

Descriptor generation, metamodel generation, and bytecode enhancement

Hibernate

io.github.jpersist.eclipse-persistence

Descriptor generation, metamodel generation, and static weaving

EclipseLink

The provider-specific plugins (hibernate-persistence and eclipse-persistence) automatically apply the io.github.jpersist.jpa plugin, so you only need to apply one.

1.3. Applying the Plugin

1.3.1. Hibernate example

Groovy
plugins {
    id 'io.github.jpersist.hibernate-persistence' version '1.7.0'
}
Kotlin
plugins {
    id("io.github.jpersist.hibernate-persistence") version "1.7.0"
}
Groovy
plugins {
    id 'io.github.jpersist.eclipse-persistence' version '1.7.0'
}
Kotlin
plugins {
    id("io.github.jpersist.eclipse-persistence") version "1.7.0"
}

1.4. Adding Dependencies

Use the jpa configuration to declare your JPA provider platform BOM. This centralizes version management across all compilation scopes.

1.4.1. Hibernate example

Groovy
dependencies {
    jpa platform('org.hibernate.orm:hibernate-platform:6.6.56.Final')

    implementation 'org.hibernate.orm:hibernate-core'
}
Kotlin
dependencies {
    jpa(platform("org.hibernate.orm:hibernate-platform:6.6.56.Final"))

    implementation("org.hibernate.orm:hibernate-core")
}
Groovy
dependencies {
    jpa platform('org.eclipse.persistence:org.eclipse.persistence.parent:4.0.9')

    compileOnly 'jakarta.persistence:jakarta.persistence-api'
    implementation 'org.eclipse.persistence:org.eclipse.persistence.core'
}
Kotlin
dependencies {
    jpa(platform("org.eclipse.persistence:org.eclipse.persistence.parent:4.0.9"))

    compileOnly("jakarta.persistence:jakarta.persistence-api")
    implementation("org.eclipse.persistence:org.eclipse.persistence.core")
}

That’s it — no additional XML configuration or annotation processing setup is required. The plugin automatically detects your entity classes and generates the appropriate persistence.xml at build time.

2. Jakarta Persistence Plugin

Plugin ID: io.github.jpersist.jpa

The io.github.jpersist.jpa plugin is the core implementation of the JPersist plugin suite and facilitates the integration of provider platform plugins such as EclipseLink and Hibernate. It automatically applies the java plugin, registers a persistence DSL extension, and creates per-source-set tasks for descriptor generation, schema validation, GraalVM native image metadata generation, and static compile-time named query linting.

2.1. Applying the Plugin

Groovy
plugins {
    id 'io.github.jpersist.jpa' version '1.7.0'
}
Kotlin
plugins {
    id("io.github.jpersist.jpa") version "1.7.0"
}

2.2. The jpa Configuration

The plugin registers a jpa dependency configuration that propagates platform/BOM version constraints into all standard Java configurations (implementation, compileOnly, annotationProcessor, runtimeOnly). When the java-library plugin is also applied, the api and compileOnlyApi configurations are extended as well.

Groovy
dependencies {
    jpa platform('org.hibernate.orm:hibernate-platform:6.6.56.Final')

    implementation 'org.hibernate.orm:hibernate-core'
}
Kotlin
dependencies {
    jpa(platform("org.hibernate.orm:hibernate-platform:6.6.56.Final"))

    implementation("org.hibernate.orm:hibernate-core")
}

2.2.1. The modelgenProcessor Configuration

The plugin also registers a global, non-resolvable modelgenProcessor configuration container that centralizes modelgen annotation processor dependencies. (Since 1.7.0)

Each source set’s annotationProcessor configuration lazily extends from this unified root via extendsFrom, so that provider-specific plugins (e.g. Hibernate or EclipseLink) only need to target the single modelgenProcessor configuration. User overrides declared inside modelgenProcessor propagate to all source sets and safely skip any built-in defaults added by provider plugins.

Groovy
dependencies {
    modelgenProcessor 'org.hibernate.orm:hibernate-jpamodelgen:6.6.56.Final'
}
Kotlin
dependencies {
    "modelgenProcessor"("org.hibernate.orm:hibernate-jpamodelgen:6.6.56.Final")
}

2.3. DSL Extension: persistence

The persistence block is a NamedDomainObjectContainer scoped per Java source set. The plugin automatically creates one entry per source set (e.g. main, test).

Groovy
persistence {
    main {
        version = '3.0'

        persistenceUnits {
            'my-unit' {
                provider = 'org.hibernate.jpa.HibernatePersistenceProvider'
                transactionType = 'RESOURCE_LOCAL'

                properties {
                    property 'hibernate.show_sql', 'true'
                }
            }
        }

        validation {
            url = 'jdbc:h2:mem:my_db;DB_CLOSE_DELAY=-1'
        }

        transformer {
            outputProperty 'indent', 'yes'
            outputProperty '{http://xml.apache.org/xslt}indent-amount', '2'
        }
    }
}
Kotlin
persistence {
    create("main") {
        version.set("3.0")

        persistenceUnits {
            create("my-unit") {
                provider.set("org.hibernate.jpa.HibernatePersistenceProvider")
                transactionType.set("RESOURCE_LOCAL")

                properties.put("hibernate.show_sql", "true")
            }
        }

        validation {
            url.set("jdbc:h2:mem:my_db;DB_CLOSE_DELAY=-1")
        }

        outputProperties.put("indent", "yes")
        outputProperties.put("{http://xml.apache.org/xslt}indent-amount", "2")
    }
}

2.3.1. PersistenceExtension Properties

Property Type Default Description

version

Property<String>

"3.0"

JPA specification version written into the root <persistence> element of the generated persistence.xml.

persistenceUnits

NamedDomainObjectContainer<PersistenceUnitExtension>

auto-populated

Named container of persistence unit definitions. Each entry maps to a <persistence-unit> element. Units declared in an existing persistence.xml template are automatically registered.

validation

ValidationExtension

see below

Nested database connection configuration for the schema validation task.

linter

LinterExtension

see below

Nested configuration for the static compile-time @NamedQuery analysis linter.

outputProperties

MapProperty<String, String>

see below

Key-value pairs passed to the XML Transformer that formats the output persistence.xml.

Default Output Properties
  • indent = yes

  • omit-xml-declaration = no

  • encoding = UTF-8

  • \{http://xml.apache.org/xslt}indent-amount = 4

These can be customized via the transformer block (Groovy) or by setting entries directly on outputProperties (Kotlin):

Groovy
persistence {
    main {
        transformer {
            outputProperty 'indent', 'yes'
            outputProperty '{http://xml.apache.org/xslt}indent-amount', '2'
        }
    }
}
Kotlin
persistence {
    create("main") {
        outputProperties.put("indent", "yes")
        outputProperties.put("{http://xml.apache.org/xslt}indent-amount", "2")
    }
}

2.3.2. PersistenceUnitExtension Properties

Property Type Default Description

name

String

(container key)

Read-only. The persistence-unit name used as the name attribute in the generated <persistence-unit> element.

enabled

Property<Boolean>

true

When set to false, the unit is excluded from the generated persistence.xml.

transactionType

Property<String>

"RESOURCE_LOCAL"

The JPA transaction type (RESOURCE_LOCAL or JTA).

description

Property<String>

none

An optional human-readable description for the persistence unit.

provider

Property<String>

none

Fully qualified class name of the JPA persistence provider (e.g. org.hibernate.jpa.HibernatePersistenceProvider).

dataSource

Property<String>

none

The JNDI name of the data source for this persistence unit.

jta

Property<Boolean>

none

Whether the data source is JTA-managed. When true, the data source is emitted as <jta-data-source>; otherwise as <non-jta-data-source>.

mappingFiles

ListProperty<String>

empty

A list of ORM mapping file paths to include in the persistence unit.

jarFileMappings

MapProperty<String, String>

empty

Custom jar-file element layout translations. Key: project path or group:artifact coordinates. Value: the structural path written into the <jar-file> XML tag.

excludedUnlistedClasses

Property<Boolean>

false

Whether unlisted entity classes should be excluded from the persistence unit.

includeAllClasses

Property<Boolean>

true

Whether all discovered entity classes should be included automatically.

sharedCacheMode

Property<String>

none

The shared (second-level) cache mode. When present, emitted as a <shared-cache-mode> element.

validationMode

Property<String>

none

The Bean Validation mode (AUTO, CALLBACK, or NONE). When present, emitted as a <validation-mode> element.

properties

MapProperty<String, String>

empty

Vendor-specific JPA properties included in the <properties> block of the persistence unit.

Example with multiple properties:

Groovy
persistence {
    main {
        persistenceUnits {
            'my-unit' {
                provider = 'org.hibernate.jpa.HibernatePersistenceProvider'
                transactionType = 'RESOURCE_LOCAL'
                sharedCacheMode = 'ENABLE_SELECTIVE'
                validationMode = 'AUTO'

                properties {
                    property 'hibernate.show_sql', 'true'
                    property 'hibernate.format_sql', 'true'
                }
            }
        }
    }
}
Kotlin
persistence {
    create("main") {
        persistenceUnits {
            create("my-unit") {
                provider.set("org.hibernate.jpa.HibernatePersistenceProvider")
                transactionType.set("RESOURCE_LOCAL")
                sharedCacheMode.set("ENABLE_SELECTIVE")
                validationMode.set("AUTO")

                properties.put("hibernate.show_sql", "true")
                properties.put("hibernate.format_sql", "true")
            }
        }
    }
}

2.3.3. ValidationExtension Properties

Property Type Default Description

url

Property<String>

"jdbc:h2:mem:schema_validate_db;DB_CLOSE_DELAY=-1"

The JDBC connection URL used for schema validation.

driver

Property<String>

"org.h2.Driver"

The fully qualified JDBC driver class name.

user

Property<String>

"sa"

The database user name.

password

Property<String>

"" (empty)

The database password.

tenants

NamedDomainObjectContainer<TenantValidationExtension>

empty

Named container of multi-tenant database connection profiles. Each entry defines a separate tenant whose schema is validated independently. When empty, the base properties above are used as a single default profile. (Since 1.7.0)

Groovy
persistence {
    main {
        validation {
            url = 'jdbc:h2:mem:my_validation_db;DB_CLOSE_DELAY=-1'
            driver = 'org.h2.Driver'
            user = 'sa'
            password = ''
        }
    }
}
Kotlin
persistence {
    create("main") {
        validation {
            url.set("jdbc:h2:mem:my_validation_db;DB_CLOSE_DELAY=-1")
            driver.set("org.h2.Driver")
            user.set("sa")
            password.set("")
        }
    }
}
Multi-Tenant Validation

Since 1.7.0

The tenants container inside the validation block allows declaring multiple named database profiles. When tenants are configured, the validatePersistenceSchema task iterates over each tenant and validates every active persistence unit against that tenant’s database independently. Failures are collected across the entire tenant × unit matrix and reported in a single summary.

When no tenants are configured, the base url, driver, user, and password properties are wrapped into a single default profile automatically, preserving backward compatibility.

Groovy
persistence {
    main {
        validation {
            tenants {
                primary {
                    url = 'jdbc:h2:mem:primary_db;DB_CLOSE_DELAY=-1'
                }
                secondary {
                    url = 'jdbc:h2:mem:secondary_db;DB_CLOSE_DELAY=-1'
                    driver = 'org.h2.Driver'
                    user = 'sa'
                    password = ''
                }
            }
        }
    }
}
Kotlin
persistence {
    create("main") {
        validation {
            tenants {
                create("primary") {
                    url.set("jdbc:h2:mem:primary_db;DB_CLOSE_DELAY=-1")
                }
                create("secondary") {
                    url.set("jdbc:h2:mem:secondary_db;DB_CLOSE_DELAY=-1")
                    driver.set("org.h2.Driver")
                    user.set("sa")
                    password.set("")
                }
            }
        }
    }
}
TenantValidationExtension Properties

Since 1.7.0

Each entry in the tenants container is a TenantValidationExtension with its own JDBC connection properties. All properties default to an in-memory H2 database whose name is derived from the tenant name.

Property Type Default Description

name

String

(container key)

Read-only. The unique identifier for this tenant profile.

url

Property<String>

"jdbc:h2:mem:<name>_validate_db;DB_CLOSE_DELAY=-1"

The JDBC connection URL for this tenant.

driver

Property<String>

"org.h2.Driver"

The fully qualified JDBC driver class name for this tenant.

user

Property<String>

"sa"

The database user name for this tenant.

password

Property<String>

"" (empty)

The database password for this tenant.

2.3.4. LinterExtension Properties

Since 1.6.0

Property Type Default Description

enabled

Property<Boolean>

true

Whether the static @NamedQuery analysis task should execute.

failOnError

Property<Boolean>

true

Whether a query syntax error or metamodel mismatch fails the Gradle build. When false, errors are logged as warnings.

ignoreWarnings

Property<Boolean>

false

Whether sub-critical semantic validation warnings should be muted.

Groovy
persistence {
    main {
        linter {
            enabled = true
            failOnError = true
            ignoreWarnings = false
        }
    }
}
Kotlin
persistence {
    create("main") {
        linter {
            enabled.set(true)
            failOnError.set(true)
            ignoreWarnings.set(false)
        }
    }
}

2.4. Legacy JPA Namespace Support

Since 1.5.4

When the version property is set to a legacy JPA specification version (2.0, 2.1, or 2.2), the plugin automatically switches annotation scanning from the jakarta.persistence namespace to the javax.persistence namespace. This ensures correct entity discovery for projects that still target the older Java Persistence API (JPA 2.x), where annotations such as @javax.persistence.Entity are used instead of @jakarta.persistence.Entity.

The namespace resolution is fully lazy: the version value is read at task execution time via a flatMap provider chain, so any DSL overrides applied during the configuration phase are correctly captured.

JPA Version Annotation Namespace

2.0, 2.1, 2.2

javax.persistence

3.0, 3.1, 3.2

jakarta.persistence

Groovy
persistence {
    main {
        version = '2.1'

        persistenceUnits {
            'legacy-unit' {
                provider = 'org.hibernate.jpa.HibernatePersistenceProvider'
            }
        }
    }
}
Kotlin
persistence {
    create("main") {
        version.set("2.1")

        persistenceUnits {
            create("legacy-unit") {
                provider.set("org.hibernate.jpa.HibernatePersistenceProvider")
            }
        }
    }
}
No additional configuration is needed — the plugin detects the legacy version and adjusts the bytecode scanning annotations automatically.

2.5. Dependency Routing with jarFile

For multi-module projects, the plugin registers a jarFile dependency configuration per source set that allows you to declare module dependencies injected as <jar-file> entries in the generated persistence.xml.

The jarFile configuration extends implementation (and api when the java-library plugin is present).

2.5.1. Using the Location Attribute

Groovy
dependencies {
    jarFile(project(':common-entities')) {
        attributes {
            attribute(persist.jakarta.gradle.plugin.JakartaPersistencePlugin.JAR_LOCATION_ATTRIBUTE, 'lib/')
        }
    }
}
Kotlin
dependencies {
    jarFile(project(":common-entities")) {
        attributes {
            attribute(persist.jakarta.gradle.plugin.JakartaPersistencePlugin.JAR_LOCATION_ATTRIBUTE, "lib/")
        }
    }
}

2.5.2. Using DSL Jar File Mappings

You can also declare custom jar-file path mappings directly inside a persistence unit:

Groovy
persistence {
    main {
        persistenceUnits {
            'my-unit' {
                jarFile(project(':ejb-module')) { jarTask ->
                    "${jarTask.archiveBaseName.get()}.jar"
                }
                jarFile 'com.example:external-persistence', 'lib/external-persistence-custom.jar'
            }
        }
    }
}
Kotlin
persistence {
    create("main") {
        persistenceUnits {
            create("my-unit") {
                jarFileMappings.put(":ejb-module", "ejb-module.jar")
                jarFileMappings.put("com.example:external-persistence", "lib/external-persistence-custom.jar")
            }
        }
    }
}

2.6. Tasks

The plugin registers the following tasks per Java source set. For the main source set the task names are as shown below; for other source sets (e.g. test) the source set name is capitalized and inserted (e.g. processTestPersistenceDescriptor).

(Since 1.7.0) Per-source-set tasks and configurations are only registered when the source set’s java.srcDirs or resources.srcDirs contain at least one directory that physically exists on disk. Source sets with no on-disk directories are silently skipped, preventing clean IDE workspaces from being cluttered with empty tasks (e.g. lintTestNamedQueries).

2.6.1. processPersistenceDescriptor

Group: build
Type: ProcessPersistenceDescriptor

Generates or merges the persistence.xml descriptor for the source set.

  • Merge mode: When a user-provided src/main/resources/META-INF/persistence.xml exists, the task parses it, applies extension-defined overrides (provider, data source, properties), injects resolved <class> and <jar-file> entries, and writes the result to the destination.

  • Generate mode: When no source descriptor is present, the task builds a complete persistence.xml from scratch using the DSL configuration.

The task automatically discovers JPA entity classes annotated with @Entity, @Embeddable, @MappedSuperclass, or @Converter using ASM bytecode scanning on the compiled class output.

Property Type Default Description

xmlVersion

Property<String>

"3.0"

The JPA specification version for the root <persistence> element. Bound from persistence.main.version.

units

ListProperty<PersistenceUnitExtension>

from extension

The list of active (enabled) persistence unit configurations to process.

includedClasses

ListProperty<String>

auto-discovered

Fully qualified class names of discovered JPA entity classes injected as <class> elements.

jarFileNames

ListProperty<String>

from jarFile config

Resolved JAR file names injected as <jar-file> elements.

persistenceXml

RegularFileProperty

optional

Path to the user-provided persistence.xml template. When present, enables merge mode.

destinationFile

RegularFileProperty

build/generated/resources/main/META-INF/persistence.xml

The output location of the generated or merged descriptor.

transformerSettings

MapProperty<String, String>

from extension

XML Transformer output properties controlling indentation, encoding, and formatting.

The task is automatically skipped when no persistence units are enabled.

2.6.2. validatePersistenceSchema

Group: verification
Type: ValidatePersistenceSchema

Validates that the JPA entity mappings align correctly with the database schema by booting an isolated JVM worker process. Since 1.7.0, validation is performed by an SPI-loaded SchemaValidator obtained via SchemaValidatorFactory, replacing the previous direct use of the JPA Persistence bootstrap API. The task iterates over every configured tenant profile and validates each active persistence unit against that tenant’s database independently. Failures are collected across the entire tenant × unit matrix and reported in a single summary.

Property Type Default Description

jpaVersion

Property<String>

"3.0"

The JPA specification version used to determine the annotation namespace (jakarta.persistence vs javax.persistence) during bytecode scanning.

persistenceUnitNames

Property<String>

from extension

A comma-separated list of active persistence unit names to validate.

validation

Property<ValidationExtension>

from extension

Nested database connection configuration (URL, driver, user, password) and optional multi-tenant tenants container.

tenantProfiles

ListProperty<String>

from extension

Serialized tenant database connection profiles (Name|URL|Driver|User|Password). When no explicit tenants are configured, a single default profile is synthesized from the base validation properties. (Since 1.7.0)

discoveredEntityClasses

ListProperty<String>

auto-discovered

Fully qualified entity class names discovered by the ASM bytecode scanner, forwarded to the SPI-loaded SchemaValidator for precise mapping resolution. (Since 1.7.0)

resourcesDir

DirectoryProperty

from `processResources`

The resources directory containing META-INF/persistence.xml.

classpath

ConfigurableFileCollection

auto-configured

The full classpath including compiled entity classes, JPA provider binaries, and the H2 driver.

The H2 JDBC driver (com.h2database:h2:2.2.224) is transparently injected into the task classpath — no manual dependency declaration is needed.
The task is automatically skipped when no active persistence unit names are present.

2.6.3. generateJPAGraalVMMetadata

Group: build
Type: GenerateJPAGraalVMMetadata

Generates a GraalVM native image reflect-config.json file containing all discovered JPA entity classes to support AOT reflection in native images.

The generated JSON follows the GraalVM reachability metadata format and registers each entity class with allDeclaredConstructors, allDeclaredFields, and allDeclaredMethods set to true.

Property Type Default Description

includedClasses

ListProperty<String>

auto-discovered

Fully qualified class names of discovered JPA entity classes.

outputFile

RegularFileProperty

build/generated/graalvm-resources/main/META-INF/native-image/<group>/<name>/reflect-config.json

The location where the reflect-config.json is written. The path follows GraalVM standard conventions using the project group and name.

The generated resource directory is automatically added to the source set resources, ensuring the JSON file is indexed by IDEs and packaged into the final JAR.

2.6.4. lintNamedQueries

Since 1.6.0

Group: verification
Type: LintNamedQueries

Performs a static, compile-time AST verification pass over all @NamedQuery and @NamedStoredProcedureQuery definitions discovered in the compiled source set output. The task uses ASM bytecode scanning to locate query annotations, then validates JPQL/HQL syntax and parameter naming conventions using an ANTLR4-based parser loaded via SPI. Processing runs inside an isolated Gradle Worker classloader.

Property Type Default Description

jpaVersion

Property<String>

"3.0"

The JPA specification version used to determine the annotation namespace (jakarta.persistence vs javax.persistence) during bytecode scanning.

failOnError

Property<Boolean>

true

Whether discovering a syntax error or metamodel mismatch immediately fails the build.

ignoreWarnings

Property<Boolean>

false

Whether sub-critical semantic validation warnings should be muted.

sourceFiles

ConfigurableFileCollection

from source set

The Java source files tracked for incremental change detection. Modified sources are mapped to their compiled class counterparts for delta analysis.

compiledClassesDir

DirectoryProperty

from source set output

The directory containing compiled .class files to scan.

classpath

ConfigurableFileCollection

auto-configured

The classpath including compiled classes and the lint persistence libraries.

lintReportFile

RegularFileProperty

build/reports/lint-named-queries/<sourceSet>.json

The output JSON file containing execution metrics (processed files, skipped files, error counts) from the lint analysis pass.

The task is automatically skipped when the linter is disabled via persistence.main.linter.enabled = false.

3. Hibernate Plugin

Plugin ID: io.github.jpersist.hibernate-persistence

The io.github.jpersist.hibernate-persistence plugin provides a complete Hibernate persistence pipeline out-of-the-box. It automatically applies the core io.github.jpersist.jpa plugin (see Jakarta Persistence Plugin), the Hibernate JPA static metamodel generator, and compile-time bytecode enhancement for Hibernate-based projects.

3.1. Applying the Plugin

Groovy
plugins {
    id 'io.github.jpersist.hibernate-persistence' version '1.7.0'
}

dependencies {
    jpa platform('org.hibernate.orm:hibernate-platform:6.6.56.Final')

    implementation 'org.hibernate.orm:hibernate-core'
}
Kotlin
plugins {
    id("io.github.jpersist.hibernate-persistence") version "1.7.0"
}

dependencies {
    jpa(platform("org.hibernate.orm:hibernate-platform:6.6.56.Final"))

    implementation("org.hibernate.orm:hibernate-core")
}
The jpa configuration is provided by the core Jakarta Persistence plugin (applied transitively). Use it to declare a Hibernate platform BOM so that all Hibernate module versions are aligned automatically.

3.2. Sub-Plugins

The aggregate io.github.jpersist.hibernate-persistence plugin is a convenience macro that applies the following three plugins:

Plugin ID Description

io.github.jpersist.jpa

The core Jakarta Persistence plugin — registers the persistence DSL extension, generates or merges persistence.xml descriptors, validates persistence schema, and generates GraalVM native image metadata. See Jakarta Persistence Plugin.

io.github.jpersist.hibernate-jpamodelgen

Configures Hibernate’s JPA static metamodel generator (hibernate-jpamodelgen) as an annotation processor for every source set, enabling type-safe Criteria API queries.

io.github.jpersist.hibernate-enhancement

Registers the hibernate DSL extension and creates a bytecode enhancement task for every source set whose Java source directories physically exist on disk, enabling compile-time lazy initialization, dirty tracking, and association management.

You can apply sub-plugins individually if you only need a subset of the functionality:

Groovy
plugins {
    id 'io.github.jpersist.hibernate-enhancement' version '1.7.0'
}
Kotlin
plugins {
    id("io.github.jpersist.hibernate-enhancement") version "1.7.0"
}

3.3. JPA Static Metamodel Generation

The io.github.jpersist.hibernate-jpamodelgen sub-plugin automatically:

  • Applies the java plugin.

  • Adds org.hibernate.orm:hibernate-jpamodelgen to the unified global modelgenProcessor configuration container (registered by the io.github.jpersist.jpa plugin), but only if the user has not declared any custom dependencies in the modelgenProcessor configuration. This allows user overrides inside modelgenProcessor to propagate cleanly and safely skip the built-in default. (Since 1.7.0, previously targeted annotationProcessor directly since 1.5.2)

  • Registers the annotation processor generated source directory (build/generated/sources/annotationProcessor/java/<sourceSet>) into the source set’s Java source directories for seamless IDE indexing.

No additional configuration is needed — the annotation processor version is resolved from the Hibernate platform BOM declared through the jpa configuration.

For each JPA entity class annotated with @Entity, @Embeddable, or @MappedSuperclass, Hibernate generates a corresponding static metamodel class (e.g. Person_) that provides compile-time-safe attribute references for Criteria API queries.

3.4. DSL Extension: hibernate

The io.github.jpersist.hibernate-enhancement sub-plugin registers a hibernate DSL extension block at the project level. It exposes a nested enhancement sub-block to control compile-time bytecode transformation behavior.

Groovy
hibernate {
    enhancement {
        enableLazyInitialization = true
        enableDirtyTracking = true
        enableAssociationManagement = true
        enableExtendedEnhancement = false
    }
}
Kotlin
hibernate {
    enhancement {
        enableLazyInitialization.set(true)
        enableDirtyTracking.set(true)
        enableAssociationManagement.set(true)
        enableExtendedEnhancement.set(false)
    }
}

3.4.1. HibernateExtension Properties

Property Type Default Description

enhancement

EnhancementExtension

see below

Nested configuration block controlling Hibernate compile-time bytecode enhancement options.

3.4.2. EnhancementExtension Properties

Property Type Default Description

enableLazyInitialization

Property<Boolean>

true

Enhances entity bytecode to support field-level lazy initialization. When enabled, fields or relationships annotated for lazy fetching can be loaded individually on-demand via their getters, instead of initializing the entire containing entity.

enableDirtyTracking

Property<Boolean>

true

Enhances entities to actively track their own internal state mutations. This allows Hibernate to discover which fields changed during flush, avoiding heavy reflection-based state array snapshot comparisons.

enableAssociationManagement

Property<Boolean>

true

Automatically manages bidirectional associations — setting one side of a relationship updates the other side in memory (e.g. adding an item to a child collection updates the parent reference).

enableExtendedEnhancement

Property<Boolean>

false

Expands the bytecode enhancement scope beyond simple entity definitions to intercept non-proxy boundaries or customized orchestration scenarios.

Example enabling only dirty tracking and lazy initialization:

Groovy
hibernate {
    enhancement {
        enableLazyInitialization = true
        enableDirtyTracking = true
        enableAssociationManagement = false
        enableExtendedEnhancement = false
    }
}
Kotlin
hibernate {
    enhancement {
        enableLazyInitialization.set(true)
        enableDirtyTracking.set(true)
        enableAssociationManagement.set(false)
        enableExtendedEnhancement.set(false)
    }
}

3.5. Tasks

The plugin registers the following task per Java source set. For the main source set the task name is hibernateEnhanceClasses; for other source sets (e.g. test) the source set name is used (e.g. hibernateEnhanceTestClasses).

(Since 1.7.0) The enhancement task is only registered for source sets whose java.srcDirs contain at least one directory that physically exists on disk. Source sets with no on-disk Java source directories are silently skipped, preventing clean IDE workspaces from being cluttered with empty tasks (e.g. hibernateEnhanceTestClasses).

In addition, all tasks inherited from the core io.github.jpersist.jpa plugin (processPersistenceDescriptor, validatePersistenceSchema, generateJPAGraalVMMetadata, lintNamedQueries) are also available. See Jakarta Persistence Plugin for their documentation.

3.5.1. hibernateEnhanceClasses

Group: build
Type: HibernateEnhancementTask

Performs compile-time bytecode enhancement on Hibernate entity classes using Hibernate’s internal Enhancer engine. The task reads raw compiled .class files from the Java compilation output directory, runs multi-pass bytecode transformation (type discovery and byte-level rewriting), and writes the enhanced classes to an isolated output directory.

The enhanced classes are automatically included in the final JAR with higher priority than the original unenhanced classes (using DuplicatesStrategy.EXCLUDE), so no additional packaging configuration is needed.

Property Type Default Description

sourceClassesDir

DirectoryProperty

from compileJava output

The input directory containing the raw, unenhanced compiled Java class files. Bound from the Java compilation task’s destination directory.

targetClassesDir

DirectoryProperty

build/enhanced/classes/java/<sourceSet>

The isolated output directory where enhanced class files are written. Keeping this separate from the compile output preserves Gradle’s incremental build and UP-TO-DATE checking.

compileClasspath

ConfigurableFileCollection

from source set

The full compilation classpath necessary for Hibernate to inspect, resolve, and validate complex relationships, types, or embedded enums during the bytecode analysis phase.

lazyInitializationEnabled

Property<Boolean>

true

Whether to enhance entities for field-level lazy initialization. Bound from hibernate.enhancement.enableLazyInitialization.

dirtyTrackingEnabled

Property<Boolean>

true

Whether to inject inline dirty tracking code into entity fields. Bound from hibernate.enhancement.enableDirtyTracking.

associationManagementEnabled

Property<Boolean>

true

Whether to automatically manage bidirectional associations. Bound from hibernate.enhancement.enableAssociationManagement.

extendedEnhancementEnabled

Property<Boolean>

false

Whether to enable extended bytecode enhancement beyond standard entity boundaries. Bound from hibernate.enhancement.enableExtendedEnhancement.

The task is annotated with @DisableCachingByDefault because enhancement modifies class bytecode in place. It is automatically skipped with a NO-SOURCE outcome when no compiled classes are present in the source directory.
The task is wired into the build lifecycle automatically — it runs after compileJava and before classes, so the enhanced bytecode is ready for both testing and packaging without manual task ordering.

Plugin ID: io.github.jpersist.eclipse-persistence

The io.github.jpersist.eclipse-persistence plugin provides a complete EclipseLink persistence pipeline out-of-the-box. It is the core implementation of the JPersist plugin suite for EclipseLink and facilitates the integration of provider platform capabilities such as JPA static metamodel generation and compile-time static bytecode weaving. It automatically applies the core io.github.jpersist.jpa plugin (see Jakarta Persistence Plugin), the EclipseLink canonical metamodel generator, and compile-time static weaving for EclipseLink-based projects.

4.1. Applying the Plugin

Groovy
plugins {
    id 'io.github.jpersist.eclipse-persistence' version '1.7.0'
}

dependencies {
    jpa platform('org.eclipse.persistence:org.eclipse.persistence.parent:4.0.9')

    compileOnly 'jakarta.persistence:jakarta.persistence-api'
    implementation 'org.eclipse.persistence:org.eclipse.persistence.core'
}
Kotlin
plugins {
    id("io.github.jpersist.eclipse-persistence") version "1.7.0"
}

dependencies {
    jpa(platform("org.eclipse.persistence:org.eclipse.persistence.parent:4.0.9"))

    compileOnly("jakarta.persistence:jakarta.persistence-api")
    implementation("org.eclipse.persistence:org.eclipse.persistence.core")
}
The jpa configuration is provided by the core Jakarta Persistence plugin (applied transitively). Use it to declare an EclipseLink platform BOM so that all EclipseLink module versions are aligned automatically.

4.2. Sub-Plugins

The aggregate io.github.jpersist.eclipse-persistence plugin is a convenience macro that applies the following three plugins:

Plugin ID Description

io.github.jpersist.jpa

The core Jakarta Persistence plugin — registers the persistence DSL extension, generates or merges persistence.xml descriptors, validates persistence schema, and generates GraalVM native image metadata. See Jakarta Persistence Plugin.

io.github.jpersist.eclipse-jpa-modelgen

Configures EclipseLink’s canonical metamodel generator (org.eclipse.persistence.jpa.modelgen.processor) as an annotation processor for every source set, enabling type-safe Criteria API queries.

io.github.jpersist.eclipse-static-weave

Registers the weave configuration and creates a static weaving task for every source set whose Java source directories physically exist on disk, enabling compile-time lazy loading, fetch graph optimizations, and inline dirty tracking without a runtime -javaagent.

You can apply sub-plugins individually if you only need a subset of the functionality:

Groovy
plugins {
    id 'io.github.jpersist.eclipse-static-weave' version '1.7.0'
}
Kotlin
plugins {
    id("io.github.jpersist.eclipse-static-weave") version "1.7.0"
}

4.3. JPA Static Metamodel Generation

The io.github.jpersist.eclipse-jpa-modelgen sub-plugin automatically:

  • Applies the java plugin.

  • Creates the eclipselink DSL extension — a NamedDomainObjectContainer scoped per source set (see DSL Extension: eclipselink).

  • Adds org.eclipse.persistence:org.eclipse.persistence.jpa.modelgen.processor to the unified global modelgenProcessor configuration container (registered by the io.github.jpersist.jpa plugin), but only if the user has not declared any custom dependencies in the modelgenProcessor configuration. This allows user overrides inside modelgenProcessor to propagate cleanly and safely skip the built-in default. (Since 1.7.0, previously targeted annotationProcessor directly since 1.5.2)

  • Injects the -Aeclipselink.persistencexml=<path> compiler argument pointing to the configured persistence.xml location.

  • Detects localized ORM mapping descriptors (META-INF/orm.xml and META-INF/eclipselink-orm.xml) relative to the configured persistence.xml location and passes them to the annotation processor via the -Aeclipselink.ormxml.location and -Aeclipselink.eclipselink-ormxml.location compiler arguments. (Since 1.5.1, compiler argument keys corrected in 1.5.2)

  • Registers the annotation processor generated source directory (build/generated/sources/annotationProcessor/java/<sourceSet>) into the source set’s Java source directories for seamless IDE indexing.

For each JPA entity class annotated with @Entity, @Embeddable, or @MappedSuperclass, EclipseLink generates a corresponding static metamodel class (e.g. Person_) that provides compile-time-safe attribute references for Criteria API queries.

While it is possible to work without a user-provided persistence.xml and rely only on the persistence DSL extension, the io.github.jpersist.eclipse-jpa-modelgen sub-plugin may not work properly. This is because in this scenario, the persistence.xml will be generated after the compileJava task and without static metamodel classes. For this reason, the user must provide a persistence.xml template with at least the persistence unit name (mandatory) and the full list of entity classes to include.
Example minimal persistence.xml template for metamodel generation
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence
             https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
             version="3.0">

    <persistence-unit name="example-unit">
        <class>com.example.entity.Person</class>
    </persistence-unit>
</persistence>

The io.github.jpersist.eclipse-jpa-modelgen sub-plugin registers an eclipselink DSL extension block at the project level. It is a NamedDomainObjectContainer<EclipselinkExtension>, meaning an entry is automatically created for each source set (e.g. main, test). Each entry exposes a nested jpaModelgen sub-block to control the canonical metamodel generation parameters.

Groovy
eclipselink {
    main {
        jpaModelgen {
            persistenceXml = 'src/main/resources/META-INF/persistence.xml'
        }
    }
}
Kotlin
eclipselink {
    named("main") {
        jpaModelgen {
            persistenceXml.set(layout.projectDirectory.file("src/main/resources/META-INF/persistence.xml"))
        }
    }
}

4.4.1. EclipselinkExtension Properties

Property Type Default Description

name

String

source set name

The name of the source set associated with this configuration block. Populated automatically by Gradle’s container instantiation engine.

jpaModelgen

JpaModelgenExtension

see below

Nested configuration block controlling the EclipseLink canonical metamodel generator options for this source set.

4.4.2. JpaModelgenExtension Properties

Property Type Default Description

persistenceXml

RegularFileProperty

src/<sourceSet>/resources/META-INF/persistence.xml

Path to the persistence.xml file used by the EclipseLink canonical metamodel generator. Passed to the annotation processor via the -Aeclipselink.persistencexml compiler argument. Accepts a RegularFileProperty or a String path relative to the project directory.

Example overriding the persistence.xml location for a custom source set:

Groovy
eclipselink {
    integrationTest {
        jpaModelgen {
            persistenceXml = 'src/integrationTest/resources/META-INF/persistence.xml'
        }
    }
}
Kotlin
eclipselink {
    named("integrationTest") {
        jpaModelgen {
            persistenceXml.set(layout.projectDirectory.file("src/integrationTest/resources/META-INF/persistence.xml"))
        }
    }
}

4.5. Tasks

The plugin registers the following task per Java source set.

(Since 1.7.0) The weaving task is only registered for source sets whose java.srcDirs contain at least one directory that physically exists on disk. Source sets with no on-disk Java source directories are silently skipped, preventing clean IDE workspaces from being cluttered with empty tasks (e.g. eclipseWeaveTestClasses).

In addition, all tasks inherited from the core io.github.jpersist.jpa plugin (processPersistenceDescriptor, validatePersistenceSchema, generateJPAGraalVMMetadata, lintNamedQueries) are also available. See Jakarta Persistence Plugin for their documentation.

4.5.1. eclipseWeaveClasses

Group: build
Type: EclipseWeaveTask

Performs compile-time static bytecode weaving on EclipseLink entity classes using the official EclipseLink StaticWeave command-line processor in an isolated JVM process. The task reads raw compiled .class files from the Java compilation output directory, executes the weaving process, and writes the woven classes to an isolated output directory. The task is automatically skipped if no META-INF/persistence.xml is found in the processed resources output directory, preventing unnecessary failures in modules that do not define a persistence unit. (Since 1.5.1)

For the main source set the task name is eclipseWeaveClasses; for other source sets (e.g. test) the source set name is used (e.g. eclipseWeaveTestClasses).

The woven classes are automatically included in the final JAR with higher priority than the original unwoven classes (using DuplicatesStrategy.EXCLUDE), so no additional packaging configuration is needed.

Property Type Default Description

sourceClassesDir

DirectoryProperty

from compileJava output

The input directory containing the raw, unwoven compiled Java class files. Bound from the Java compilation task’s destination directory.

targetClassesDir

DirectoryProperty

build/woven/classes/java/<sourceSet>

The isolated output directory where woven class files are written. Keeping this separate from the compile output preserves Gradle’s incremental build and UP-TO-DATE checking.

resourcesDir

DirectoryProperty

from processResources output

The root directory containing persistence configuration metadata files (e.g. META-INF/persistence.xml). Passed to the StaticWeave processor via the -persistenceinfo argument.

weaveClasspath

ConfigurableFileCollection

from weavingClasspath configuration

The classpath carrying the EclipseLink core libraries and tool binaries required to execute the StaticWeave main class. Since 1.7.0, the task reads from an isolated, source-set-specific internal weavingClasspath configuration (e.g. weavingClasspath for main, testWeavingClasspath for test) rather than directly from the global weave configuration, ensuring full compatibility with the Gradle Configuration Cache.

compileClasspath

ConfigurableFileCollection

from source set

The full compilation classpath necessary for EclipseLink to inspect, map, and validate structural relationship models while modifying entity classes.

jarFileClasspath

ConfigurableFileCollection

from jarFile configuration

The collection of resolved JAR file dependencies declared via <jar-file> entries in persistence.xml. These JARs are matched by name and staged into a temporary sandbox directory at their expected relative paths before weaving, enabling correct resolution of cross-module entity references in multi-module projects. Fed from a source-set-specific configuration (e.g. jarFile for main, testJarFile for test). (Since 1.5.1)

The task is annotated with @DisableCachingByDefault because weaving modifies class bytecode in place. It is automatically skipped with a NO-SOURCE outcome when no compiled classes are present in the source directory.
During execution, the task creates a temporary staging sandbox, copies processed resources into it, and dynamically parses persistence.xml to discover <jar-file> entries. Matching JARs from the jarFileClasspath are resolved by name and copied into their expected relative paths within the sandbox before the StaticWeave processor is invoked. (Since 1.5.1)
The task is wired into the build lifecycle automatically — it runs after compileJava and before classes, so the woven bytecode is ready for both testing and packaging without manual task ordering.

4.6. The weave Configuration

The io.github.jpersist.eclipse-static-weave sub-plugin creates a weave dependency configuration that carries the EclipseLink runtime libraries needed by the StaticWeave processor.

  • If the jpa configuration exists (e.g. when the core io.github.jpersist.jpa plugin is applied), the weave configuration automatically extends from it, inheriting all platform version constraints.

  • The plugin adds org.eclipse.persistence:org.eclipse.persistence.jpa to the weave configuration by default, but only if the user has not declared any custom dependencies in the weave configuration. This allows projects to substitute or override the default weave dependency without conflicts. (Since 1.5.4)

  • For each source set, the plugin registers an internal weavingClasspath configuration (e.g. weavingClasspath for main, testWeavingClasspath for test) with canBeConsumed = false and canBeResolved = true. This configuration lazily extends from the global weave configuration, isolating the weaving task execution graph and protecting task property resolution states for full Gradle Configuration Cache compatibility. (Since 1.7.0)

Groovy
dependencies {
    jpa platform('org.eclipse.persistence:org.eclipse.persistence.parent:4.0.9')
    // The 'weave' configuration automatically inherits from 'jpa'
}
Kotlin
dependencies {
    jpa(platform("org.eclipse.persistence:org.eclipse.persistence.parent:4.0.9"))
    // The 'weave' configuration automatically inherits from 'jpa'
}

5. Configuration

This section covers advanced configuration topics for JPersist plugins.

5.1. Multi-Module Projects

In multi-module Gradle projects, declare the provider-specific plugin once in the root build file with apply false, then apply it individually in each module that contains JPA entities. Use the jarFile dependency configuration together with DSL jar-file mappings to declare cross-module entity dependencies so that <jar-file> entries are correctly generated in persistence.xml.

5.1.1. Root build.gradle

Groovy
plugins {
    id 'base'
    id 'io.github.jpersist.hibernate-persistence' version '1.7.0' apply false
}

subprojects {
    repositories {
        mavenCentral()
    }
}
Kotlin
plugins {
    base
    id("io.github.jpersist.hibernate-persistence") version "1.7.0" apply false
}

subprojects {
    repositories {
        mavenCentral()
    }
}
Declaring the plugin with apply false in the root project makes the plugin available to subprojects without applying it at the root level. Each subproject then opts in explicitly.

5.1.2. Entity Module build.gradle

The entity module defines JPA entity classes and applies both java-library and the Hibernate persistence plugin. Because the plugin version is already declared in the root build.gradle, the subproject does not need to repeat it.

Groovy
plugins {
    id 'java-library'
    id 'io.github.jpersist.hibernate-persistence'
}

dependencies {
    jpa platform('org.hibernate.orm:hibernate-platform:6.6.56.Final')
    implementation 'org.hibernate.orm:hibernate-core'
}
Kotlin
plugins {
    `java-library`
    id("io.github.jpersist.hibernate-persistence")
}

dependencies {
    jpa(platform("org.hibernate.orm:hibernate-platform:6.6.56.Final"))
    implementation("org.hibernate.orm:hibernate-core")
}

5.1.3. Service Module build.gradle

The service module depends on the entity module. It declares a jarFile project dependency and maps the jar-file location directly inside the persistence unit DSL block.

Groovy
plugins {
    id 'java-library'
    id 'io.github.jpersist.hibernate-persistence'
}

dependencies {
    jpa platform('org.hibernate.orm:hibernate-platform:6.6.56.Final')
    implementation 'org.hibernate.orm:hibernate-core'

    jarFile project(':entity-module')
}

persistence {
    main {
        persistenceUnits {
            'service-persistence-unit' {
                jarFile(project(':entity-module')) { jarTask ->
                    "lib/${jarTask.archiveFileName.get()}"
                }
            }
        }
    }
}
Kotlin
plugins {
    `java-library`
    id("io.github.jpersist.hibernate-persistence")
}

dependencies {
    jpa(platform("org.hibernate.orm:hibernate-platform:6.6.56.Final"))
    implementation("org.hibernate.orm:hibernate-core")

    jarFile(project(":entity-module"))
}

persistence {
    create("main") {
        persistenceUnits {
            create("service-persistence-unit") {
                jarFileMappings.put(":entity-module", "lib/entity-module.jar")
            }
        }
    }
}

The jarFile dependency ensures that the entity module’s JAR is resolved at build time. The DSL jarFile mapping inside persistenceUnits controls the exact <jar-file> path written to persistence.xml. See Jakarta Persistence Plugin for the full documentation on the jarFile dependency routing and DSL jar-file mappings.

5.2. JPA Version Selection

The persistence extension defaults to JPA 3.0. To target a different specification version, set the version property:

Groovy
persistence {
    main {
        version = '2.1' // JPA 2.1
    }
}
Kotlin
persistence {
    create("main") {
        version.set("2.1") // JPA 2.1
    }
}

Supported versions: 2.0, 2.1, 2.2, 3.0, 3.1 and 3.2.

5.3. Gradle Configuration Cache

All JPersist plugins are fully compatible with Gradle’s Configuration Cache. No special configuration is required — the plugins use lazy Property and Provider APIs throughout to ensure safe serialization of the build configuration.

5.4. IDE Integration

JPersist automatically hooks into Buildship (Eclipse) and IntelliJ IDEA project synchronization. Generated source directories for metamodel classes are registered as source roots, so IDE indexing works out of the box.

6. Examples

Complete runnable examples are available in the examples/ directory of the repository. Each example demonstrates a minimal JPA project using one of the supported plugins.

6.1. Hibernate Example

This example applies the io.github.jpersist.hibernate-persistence aggregator plugin to generate persistence.xml descriptors and perform compile-time bytecode enhancement via Hibernate.

Groovy
plugins {
    id 'java-library'
    id 'io.github.jpersist.hibernate-persistence' version '1.7.0'
}

dependencies {
    jpa platform('org.hibernate.orm:hibernate-platform:6.6.56.Final')

    implementation 'org.hibernate.orm:hibernate-core'
}

repositories {
    mavenCentral()
}
Kotlin
plugins {
    `java-library`
    id("io.github.jpersist.hibernate-persistence") version "1.7.0"
}

dependencies {
    jpa(platform("org.hibernate.orm:hibernate-platform:6.6.56.Final"))

    implementation("org.hibernate.orm:hibernate-core")
}

repositories {
    mavenCentral()
}

See Hibernate Plugin for the full list of extension properties and tasks.

This example applies the io.github.jpersist.eclipse-persistence aggregator plugin to generate persistence.xml descriptors and perform compile-time static weaving via EclipseLink.

Groovy
plugins {
    id 'java-library'
    id 'io.github.jpersist.eclipse-persistence' version '1.7.0'
}

dependencies {
    jpa platform('org.eclipse.persistence:org.eclipse.persistence.parent:4.0.9')

    compileOnly 'jakarta.persistence:jakarta.persistence-api'

    implementation 'org.eclipse.persistence:org.eclipse.persistence.core'
}

repositories {
    mavenCentral()
}
Kotlin
plugins {
    `java-library`
    id("io.github.jpersist.eclipse-persistence") version "1.7.0"
}

dependencies {
    jpa(platform("org.eclipse.persistence:org.eclipse.persistence.parent:4.0.9"))

    compileOnly("jakarta.persistence:jakarta.persistence-api")

    implementation("org.eclipse.persistence:org.eclipse.persistence.core")
}

repositories {
    mavenCentral()
}

See EclipseLink Plugin for the full list of extension properties and tasks.

6.3. Jakarta Persistence Example

This example demonstrates standalone descriptor generation using the core io.github.jpersist.jpa plugin without a specific JPA provider aggregator. It explicitly configures a persistence unit with a provider class and custom properties via the persistence DSL extension.

Groovy
plugins {
    id 'java-library'
    id 'io.github.jpersist.jpa' version '1.7.0'
}

dependencies {
    compileOnly 'jakarta.persistence:jakarta.persistence-api:3.1.0'
}

persistence {
    main {
        persistenceUnits {
            'example-persistence-unit' {
                provider = 'org.hibernate.jpa.HibernatePersistenceProvider'

                properties {
                    property 'hibernate.show_sql', 'true'
                }
            }
        }
    }
}

repositories {
    mavenCentral()
}
Kotlin
plugins {
    `java-library`
    id("io.github.jpersist.jpa") version "1.7.0"
}

dependencies {
    compileOnly("jakarta.persistence:jakarta.persistence-api:3.1.0")
}

persistence {
    named("main") {
        persistenceUnits {
            create("example-persistence-unit") {
                provider.set("org.hibernate.jpa.HibernatePersistenceProvider")

                properties {
                    property("hibernate.show_sql", "true")
                }
            }
        }
    }
}

repositories {
    mavenCentral()
}

See Jakarta Persistence Plugin for the full documentation on the persistence DSL extension.

6.4. Entity Class

Each example uses a simple Person entity annotated with standard Jakarta Persistence annotations:

package com.example.entity;

import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.Objects;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;

@Entity
public class Person implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    @Id
    private Long id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "birth_date")
    private LocalDate birthDate;

    @Enumerated
    private Gender gender;

    public Person() {
        // Default no-arg constructor
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public LocalDate getBirthDate() {
        return birthDate;
    }

    public void setBirthDate(LocalDate birthDate) {
        this.birthDate = birthDate;
    }

    public Gender getGender() {
        return gender;
    }

    public void setGender(Gender gender) {
        this.gender = gender;
    }

    @Override
    public int hashCode() {
        return Objects.hash(birthDate, firstName, gender, id, lastName);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        return Objects.equals(birthDate, other.birthDate) && Objects.equals(firstName, other.firstName)
                && gender == other.gender && Objects.equals(id, other.id) && Objects.equals(lastName, other.lastName);
    }

    public enum Gender {
        FEMALE, MALE
    }

}

6.5. Persistence Descriptor Template

Each example includes a persistence.xml template in src/main/resources/META-INF/. The plugin merges auto-detected entity classes with the entries defined in this template.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="3.0"
             xmlns="https://jakarta.ee/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence
                                 https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd">
        <persistence-unit name="example-persistence-unit" transaction-type="RESOURCE_LOCAL">
                <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
                <class>com.example.entity.Person</class>
        </persistence-unit>
</persistence>
Providing a persistence.xml template is optional when using the Hibernate or core JPA plugin. However, it is required when applying the io.github.jpersist.eclipse-jpa-modelgen sub-plugin. See EclipseLink Plugin for details.

7. FAQ

7.1. 1. Do I need to write a persistence.xml manually?

No. The plugin automatically scans your compiled classes for JPA entity annotations and generates a complete persistence.xml. If you provide a template persistence.xml in src/main/resources/META-INF/, the plugin merges your entries with the auto-detected entities.

When applying the io.github.jpersist.eclipse-jpa-modelgen sub-plugin, you must provide a persistence.xml template with at least the persistence unit name and the full list of entity classes. Without it, metamodel generation may not work correctly because the persistence.xml is generated after the compileJava task. See EclipseLink Plugin — JPA Static Metamodel Generation for details and a minimal template example.

Each module should use only one provider plugin. However, different modules within a multi-module project can use different providers.

It is also possible to combine sub-plugins from different providers within the same module. For example, instead of applying one of the aggregator plugins (io.github.jpersist.hibernate-persistence or io.github.jpersist.eclipse-persistence), you can manually apply the core io.github.jpersist.jpa plugin first, then cherry-pick individual sub-plugins:

Groovy
plugins {
    id 'io.github.jpersist.jpa' version '1.7.0'
    id 'io.github.jpersist.hibernate-jpamodelgen' version '1.7.0'
    id 'io.github.jpersist.eclipse-static-weave' version '1.7.0'
}
Kotlin
plugins {
    id("io.github.jpersist.jpa") version "1.7.0"
    id("io.github.jpersist.hibernate-jpamodelgen") version "1.7.0"
    id("io.github.jpersist.eclipse-static-weave") version "1.7.0"
}

In this example, JPA static metamodel generation is handled by Hibernate’s annotation processor while compile-time bytecode weaving is performed by EclipseLink’s static weaver. Note that in this scenario, the target JPA platform is EclipseLink — the static weaving step produces EclipseLink-enhanced bytecode, so the runtime persistence provider must be EclipseLink.

7.3. 3. Which JPA specification versions are supported?

The plugin supports JPA 2.0, 2.1, 2.2, 3.0, 3.1, and 3.2. The default version is 3.0 (Jakarta Persistence 3.0).

See Configuration — JPA Version Selection for how to change the target version.

7.4. 4. Is the Gradle Configuration Cache supported?

Yes. All JPersist plugins are fully compatible with Gradle’s Configuration Cache and Isolated Projects features.

7.5. 5. Do I need a runtime -javaagent for bytecode enhancement?

No. Both the Hibernate enhancement and EclipseLink static weaving plugins perform bytecode modification at compile time. No runtime agent is required.

7.6. 6. Where can I find the API documentation?

The full Groovydoc API reference is published at jpersist.github.io/persistence/api/latest. The User Guide is available at jpersist.github.io/persistence/guide/latest.