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, and generates JPA GraalVM native image metadata (reflect-config.json)

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.5.0'
}
Kotlin
plugins {
    id("io.github.jpersist.hibernate-persistence") version "1.5.0"
}
Groovy
plugins {
    id 'io.github.jpersist.eclipse-persistence' version '1.5.0'
}
Kotlin
plugins {
    id("io.github.jpersist.eclipse-persistence") version "1.5.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, and GraalVM native image metadata generation.

2.1. Applying the Plugin

Groovy
plugins {
    id 'io.github.jpersist.jpa' version '1.5.0'
}
Kotlin
plugins {
    id("io.github.jpersist.jpa") version "1.5.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.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.

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.

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("")
        }
    }
}

2.4. 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.4.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.4.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.5. 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).

2.5.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.5.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. Each persistence unit is validated using the standard JPA Persistence.createEntityManagerFactory API with the validate schema generation action against an in-memory H2 database.

Property Type Default Description

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).

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.5.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.

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.5.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.5.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, 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.5.0'
}
Kotlin
plugins {
    id("io.github.jpersist.hibernate-enhancement") version "1.5.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 as an annotationProcessor dependency for every source set.

  • 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).

In addition, all tasks inherited from the core io.github.jpersist.jpa plugin (processPersistenceDescriptor, validatePersistenceSchema, generateJPAGraalVMMetadata) 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.5.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.5.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, 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.5.0'
}
Kotlin
plugins {
    id("io.github.jpersist.eclipse-static-weave") version "1.5.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 as an annotationProcessor dependency for every source set.

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

  • 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.

In addition, all tasks inherited from the core io.github.jpersist.jpa plugin (processPersistenceDescriptor, validatePersistenceSchema, generateJPAGraalVMMetadata) 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.

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 weave configuration

The classpath carrying the EclipseLink core libraries and tool binaries required to execute the StaticWeave main class.

compileClasspath

ConfigurableFileCollection

from source set

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

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.
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.

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.5.0' apply false
}

subprojects {
    repositories {
        mavenCentral()
    }
}
Kotlin
plugins {
    base
    id("io.github.jpersist.hibernate-persistence") version "1.5.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.5.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.5.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.5.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.5.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.5.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.5.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.5.0'
    id 'io.github.jpersist.hibernate-jpamodelgen' version '1.5.0'
    id 'io.github.jpersist.eclipse-static-weave' version '1.5.0'
}
Kotlin
plugins {
    id("io.github.jpersist.jpa") version "1.5.0"
    id("io.github.jpersist.hibernate-jpamodelgen") version "1.5.0"
    id("io.github.jpersist.eclipse-static-weave") version "1.5.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.