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):
-
NamedObjectParser/NamedObjectParserFactory— parses and validates named JPQL queries and stored procedure declarations, returningNamedObjectDescriptorresults with parameter metadata. -
SchemaValidator/SchemaValidatorFactory— validates the entity metamodel against a live database schema via JDBC.
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:
-
Group relocation — all Maven coordinates now use
the
io.github.jpersist.toolsgroup identifier. -
PersistenceServiceProvider— new root service-provider interface shared by both the linting and enhancement hierarchies, with version-to-namespace mapping and genericServiceLoaderdiscovery viaPersistenceServiceProvider.getServiceProvider(String, Class). -
HibernateEnhancerandHibernateEnhancerProvider— new SPI for build-time Hibernate bytecode enhancement of entity classes, with configurable options for lazy initialisation, dirty tracking, association management, and extended enhancement.
Version 2.1.0
Version 2.1.0 introduced the unified linter hierarchy:
-
PersistenceLinter— marker interface that serves as the root type for all linting operations. -
PersistenceLinterFactory— base factory with generic discovery viaPersistenceLinterFactory.newPersistenceLinterFactory(String, Class). -
SchemaValidatorandSchemaValidatorFactory— SPI for build-time database schema validation against the entity metamodel.
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, andHibernateEnhancerProvider. This module contains no implementation; provider modules are discovered at runtime through theServiceLoadermechanism. It also hosts the shared model typesNamedObjectDescriptorandNamedObjectType, as well as the enhancement option enumHibernateEnhancer.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, andJakartaHibernateEnhancer. 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, andLegacyHibernateEnhancer. 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);