Persistence Tools Libraries API

Persistence Tools Libraries

The Persistence Tools Libraries (group io.github.jpersist.tools) provide build-time validation and bytecode enhancement of JPA persistence artifacts — named JPQL queries, stored procedure declarations, database schemas, and entity classes — without deploying the application. By compiling query strings against the entity metamodel, comparing the metamodel with a live database schema, and enhancing entity bytecode at build time, syntax errors, unknown entity references, invalid property paths, schema mismatches, and missing runtime instrumentation are caught early.

Architecture

The library is organised into two complementary SPI hierarchies:

Persistence Linting

Rooted in PersistenceLinter (the marker interface for all linting operations) and PersistenceLinterFactory (the base factory with ServiceLoader-based discovery):

Hibernate Bytecode Enhancement

Rooted in HibernateEnhancer (the bytecode transformation contract) and HibernateEnhancerProvider (the ServiceLoader-based provider):

  • HibernateEnhancer — transforms compiled entity class bytes to add Hibernate-specific instrumentation such as lazy-loading proxies, inline dirty tracking, bi-directional association management, and extended enhancement.
  • HibernateEnhancerProvider — discovers and creates namespace-specific enhancer instances for a given JPA specification version.

Both hierarchies share a common root through PersistenceServiceProvider, which maps a JPA specification version string (e.g. "3.1" or "2.2") to a persistence namespace ("jakarta" for JPA 3.x, "javax" for JPA 2.x) and locates the matching provider via the ServiceLoader mechanism. Provider implementations for each JPA namespace are shipped in separate modules.

What's New

Version 3.0.0

Version 3.0.0 relocates all published artifacts to the io.github.jpersist.tools group and introduces the following changes:

Version 2.1.0

Version 2.1.0 introduced the unified linter hierarchy:

Version 2.0.0

Version 2.0.0 introduced the NamedObjectParser and NamedObjectParserFactory APIs with support for validating named stored procedures alongside named queries, returning rich NamedObjectDescriptor results containing parameter metadata.

Modules

persistence-tools-api
Defines the Service Provider Interfaces (SPIs): PersistenceServiceProvider, PersistenceLinter, PersistenceLinterFactory, NamedObjectParser, NamedObjectParserFactory, SchemaValidator, SchemaValidatorFactory, HibernateEnhancer, and HibernateEnhancerProvider. This module contains no implementation; provider modules are discovered at runtime through the ServiceLoader mechanism. It also hosts the shared model types NamedObjectDescriptor and NamedObjectType, as well as the enhancement option enum HibernateEnhancer.Option.
persistence-tools-jakarta
Jakarta Persistence (JPA 3.x) provider. Uses Hibernate ORM 6 to compile JPQL queries into Semantic Query Model (SQM) trees, validate database schemas, and enhance entity bytecode.
Key classes: JakartaNamedObjectParserFactory, JakartaNamedObjectParser, JakartaSchemaValidatorFactory, JakartaSchemaValidator, JakartaHibernateEnhancerProvider, and JakartaHibernateEnhancer.
persistence-tools-legacy
Legacy javax.persistence (JPA 2.x) provider. Uses Hibernate 5 and its AST-based query translator to validate JPQL queries and database schemas, and to enhance entity bytecode.
Key classes: LegacyNamedObjectParserFactory, LegacyNamedObjectParser, LegacySchemaValidatorFactory, LegacySchemaValidator, LegacyHibernateEnhancerProvider, and LegacyHibernateEnhancer.
persistence-tools-bom
Bill of Materials (BOM) for convenient dependency management of all Persistence Tools modules.

Getting Started

Enhancing Entity Bytecode

Use HibernateEnhancerProvider.getHibernateEnhancerProvider(String) to obtain the appropriate provider for a given JPA specification version, then create a HibernateEnhancer to transform entity classes at build time:


    HibernateEnhancerProvider provider =
        HibernateEnhancerProvider.getHibernateEnhancerProvider("3.1");

    HibernateEnhancer enhancer = provider.getEnhancer(
        classesDir,
        classpathFiles,
        Map.of(
            HibernateEnhancer.Option.LAZY_INITIALIZATION, true,
            HibernateEnhancer.Option.DIRTY_TRACKING, true));

    byte[] enhancedBytes = enhancer.enhance(
        "com.example.Order", originalClassBytes);

Validating Named Queries and Stored Procedures

Use NamedObjectParserFactory.newNamedObjectParserFactory(String) to obtain the appropriate factory for a given JPA specification version, then create a NamedObjectParser to validate named queries and stored procedures:


    NamedObjectParserFactory factory =
        NamedObjectParserFactory.newNamedObjectParserFactory("3.1");

    try (NamedObjectParser parser = factory.newNamedObjectParser(entityClassNames)) {

        // Validate a named query
        NamedObjectDescriptor queryDescriptor = parser.parseQuery(
            "Order.findByStatus",
            "SELECT o FROM Order o WHERE o.status = :status");

        // Validate a named stored procedure
        NamedObjectDescriptor procDescriptor = parser.parseStoredProcedure(
            "Order.archiveOldOrders",
            "sp_archive_orders",
            Set.of("cutoffDate", "archiveTable"));
    }

Validating Database Schemas

Use newSchemaValidatorFactory(String) to obtain a schema validator factory, then create a SchemaValidator and validate the entity metamodel against a live database:


    SchemaValidatorFactory factory =
        SchemaValidatorFactory.newSchemaValidatorFactory("3.1");
    SchemaValidator validator = factory.newSchemaValidator(entityClassNames);

    validator.validateSchema(Map.of(
        "driver",   "org.h2.Driver",
        "url",      "jdbc:h2:mem:testdb",
        "username", "sa",
        "password", ""));

Generic Factory Discovery

The PersistenceLinterFactory.newPersistenceLinterFactory(String, Class) method provides a generic way to discover any linter factory subtype for a given JPA version:


    // Equivalent to NamedObjectParserFactory.newNamedObjectParserFactory("3.1")
    NamedObjectParserFactory parserFactory =
        PersistenceLinterFactory.newPersistenceLinterFactory(
            "3.1", NamedObjectParserFactory.class);

    // Equivalent to SchemaValidatorFactory.newSchemaValidatorFactory("3.1")
    SchemaValidatorFactory schemaFactory =
        PersistenceLinterFactory.newPersistenceLinterFactory(
            "3.1", SchemaValidatorFactory.class);
Packages
Package
Description
Root Service Provider Interface (SPI) for persistence tool providers.
Jakarta Persistence Hibernate bytecode enhancement implementation.
Legacy (javax) Persistence Hibernate bytecode enhancement implementation.
SPI for Hibernate bytecode enhancement of JPA entity classes.
Base service-provider support for the Jakarta Persistence namespace.
Base service-provider support for the legacy javax Persistence namespace.
Core data types for the Lint Persistence build-time validation API.
Service Provider Interface (SPI) for build-time persistence validation.
Jakarta Persistence linter implementation.
Legacy (javax) Persistence linter implementation.