Skip to content

Hibernate 7 - Step 2#15568

Open
jdaugherty wants to merge 1247 commits into
8.0.x-stage-hibernate7from
8.0.x-hibernate7
Open

Hibernate 7 - Step 2#15568
jdaugherty wants to merge 1247 commits into
8.0.x-stage-hibernate7from
8.0.x-hibernate7

Conversation

@jdaugherty
Copy link
Copy Markdown
Contributor

@jdaugherty jdaugherty commented Apr 10, 2026

Reopening. This PR replaces #15530

Please note that I split off a prerequisite PR #15654

This allows us to better see what changed between hibernate 5 & 7 - otherwise the hibernate 7 code looks like it was just added instead of changed. Commit a47d8cb is the original commit prior to this split if we need to compare this branch to that for any reason (mistakes, etc).

borinquenkid and others added 30 commits April 7, 2026 12:02
- PropertyDefinitionDelegateSpec: added 3 tests covering throw on missing name,
  all optional attributes, and minimal-args defaults
- SimpleIdBinderSpec: added MappingException throw path (non-HibernateSimpleIdentityProperty)
  and getMetadataBuildingContext() getter test
- JACOCO_COVERAGE_VIOLATIONS.md: marked X for PropertyDefinitionDelegate and SimpleIdBinder

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…overage

- HibernateToManyPropertySpec: added 10 new tests covering isBasic, isOneToMany,
  isManyToMany, hasSort, getSort/getOrder, getLazy, getIgnoreNotFound, getCacheUsage
  (both non-null and null paths); added HTMPAuthorSorted, HTMPAuthorLazy,
  HTMPAuthorCached fixture entities
- NamespaceNameExtractorSpec: verified all 10 existing tests pass (spec already
  fully covers both getCatalogName and getSchemaName null-chain paths)
- JACOCO_COVERAGE_VIOLATIONS.md: marked X for HibernateToManyProperty,
  NamespaceNameExtractor

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eForManyCalculator as covered in JACOCO violations

All existing specs confirmed passing with current test suite.
JaCoCo reports were stale from a previous run.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…violations as done

- ByteBuddyGroovyProxyFactorySpec: added postInstantiate and getProxy error-path
  tests; ClassCastException from String proxy triggers HibernateException catch block
- JACOCO_COVERAGE_VIOLATIONS.md: marked X for IdentityEnumType.BidiEnumMap,
  GrailsPropertyBinder, ByteBuddyGroovyProxyFactory, GrailsSequenceStyleGenerator,
  UniqueKeyForColumnsCreator, HibernateHqlQuery, PropertyConfig, CriteriaMethodInvoker
  (all confirmed covered by existing tests; JaCoCo reports were stale)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…OneToOneProperty, DefaultColumnNameFetcher, ClassPropertiesBinder as covered

- DefaultColumnNameFetcherSpec: add single-arg constructor test
- HibernateOneToOnePropertySpec: 14 tests all passing (validateAssociation
  unidirectional-hasOne path is untestable in isolation — Hibernate rejects
  the entity at datastore setup time)
- ClassPropertiesBinderSpec: 1 test passing

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Verified by running existing specs - all pass. Covered:
ColumnConfig, HibernateAssociationQuery, RootPersistentClassCommonValuesBinder,
NamingStrategyProvider, HibernatePagedResultList, CacheConfig, PropertyBinder,
GrailsEntityDirtinessStrategy, GrailsEnumType, HibernateMappingBuilder,
UniqueNameGenerator, HibernateEntityTransformation, GroovyProxyInterceptorLogic,
HibernateRuntimeUtils, EnumTypeBinder, HibernatePersistentEntity, HibernateGormEnhancer,
HibernateAssociation, HibernateQuery, NaturalId, UnidirectionalOneToManyBinder,
GrailsSequenceGeneratorEnum, GrailsHibernatePersistentEntity, ComponentBinder,
GrailsDomainBinder, HibernateGormValidationApi, NamingStrategyWrapper,
HibernateMappingContext, GrailsHibernateTransactionManager, LogCascadeMapping,
MultiTenantFilterBinder, HibernateDatastoreConnectionSourcesRegistrar,
MappingBuilder, ProjectionPredicate, HibernateQueryArgument, BasicValueCreator,
ColumnConfigToColumnBinder, JpaCriteriaQueryCreator, JpaFromProvider,
CriteriaMethods, OrderByClauseBuilder, HqlQueryContext, ClosureEventListener,
and related closures/inner classes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
GrailsSessionContextSpec exists and passes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add 2 new tests:
- createSession() sets FlushMode.MANUAL when transaction is read-only
- currentSession() with already-synchronized SessionHolder skips re-registration

JTA paths (jtaSessionContext, registerJtaSynchronization with active JTA tx,
getJtaTransactionManager with real TM) remain uncovered — require a JTA container.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…estability and expand coverage

Production changes (GrailsSessionContext):
- Extract resolveJtaTransactionManager() - isolates JtaPlatform service lookup
- Extract buildJtaSessionContext() - isolates SpringJtaSessionContext creation
- Extract lookupJtaTransactionManager(sf) - isolates ServiceBinding registry lookup
  from the null-safety branching in getJtaTransactionManager(Session)

Test changes (GrailsSessionContextSpec, 10 → 18 tests):
- initJta sets jtaSessionContext when resolveJtaTransactionManager returns non-null
- initJta leaves jtaSessionContext null when resolveJtaTransactionManager returns null
- currentSession() delegates to jtaSessionContext when set
- currentSession() registers SpringFlushSynchronization when jtaSessionContext + sync active
- registerJtaSynchronization registers sync with active JTA transaction (mockTm override)
- registerJtaSynchronization uses existing SessionHolder when provided
- registerJtaSynchronization skips when JTA transaction is not active (STATUS_COMMITTED)
- lookupJtaTransactionManager returns null when no JTA service binding (H2 env)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…HibernateSession spec

- Bug: retrieveAll(Class, Iterable) wrapped root.get(id).in(keys) inside
  criteriaBuilder.in(), creating an empty IN clause that always returned 0 rows.
  Fix: use root.get(id).in(keys) directly as the WHERE predicate.
- Created HibernateSessionSpec.groovy with 31 tests covering: persist, merge,
  refresh, delete, lock, flush, clear, contains, getObjectIdentifier,
  deleteAll/updateAll criteria queries, retrieveAll (varargs and Iterable),
  createQuery, setFlushMode/getFlushMode round-trip, getNativeInterface,
  and transaction guard paths.
- Marked HibernateSession as covered in JACOCO_COVERAGE_VIOLATIONS.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…expand HibernateDatastore coverage

- Extracted protected closeConnectionSources() and closeGormEnhancer() from
  destroy() to allow mock-based testing of IOException error paths.
- Added 12 new tests to HibernateDatastoreSpec covering: getHibernateTemplate,
  openSession (flush mode), hasCurrentSession true path, withFlushMode exception
  path (mode not restored), setApplicationContext with non-Configurable context,
  getDatastoreForTenantId non-DATABASE mode, addTenantForSchema non-SCHEMA mode
  (ConfigurationException), destroy idempotency, destroy IOException logging for
  both closeConnectionSources and closeGormEnhancer, isAutoFlush/getDefaultFlushModeName,
  boolean accessors, and getMetadata.
- Marked HibernateDatastore as covered in JACOCO_COVERAGE_VIOLATIONS.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Added 11 new tests covering: getBytecodeProvider, setHibernateEventListeners,
setInterceptor, setDataSourceConnectionSourceFactory, getConnectionSourcesConfigurationKey,
setApplicationContext (stores context as both applicationContext and messageSource),
buildRuntimeSettings, buildSettings (isDefaultDataSource true and false branches),
buildConfiguration with naming strategy, buildConfiguration with interceptor applied.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…(168 tests total)

HibernateCriteriaBuilderDirectSpec — added 48 new tests covering:
- eqAll/gtAll/ltAll/geAll/leAll (both QueryableCriteria and Closure variants)
- gtSome/geSome/ltSome/leSome (both variants)
- in/inList/notIn via QueryableCriteria and Closure subqueries
- exists/notExists with QueryableCriteria
- and/not Closure combinators
- count(String), count(String,String) void projection methods
- Alias projections: countDistinct, groupProperty, max, min, sum with alias
- convertFromInt (LEFT=1, RIGHT=2, INNER=default)
- isParticipate() getter
- fetchMode with FetchMode.SELECT branch
- getClassForAssociationType (PluralAttribute and SingularAttribute)
- throwRuntimeException disconnects session and rethrows

HibernateCriteriaBuilderSpec — added 'not combinator excludes matching rows' DSL test

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rcept coverage

Created ByteBuddyGroovyInterceptorSpec with 8 tests exercising all reachable branches
of ByteBuddyGroovyInterceptor.intercept() using real Hibernate lazy proxies obtained
via hibernateSession.getReference():

- ident() on uninitialized proxy — IDENT_METHOD handleUninitialized path (no init)
- toString() on uninitialized proxy — TO_STRING handleUninitialized path (no init)
- isDirty() on uninitialized proxy — IS_DIRTY handleUninitialized path (no init)
- metaClass on uninitialized proxy — getMetaClass handleUninitialized path (no init)
- proxy.name access — initializes proxy via super.intercept (regular method path)
- getProperty('name') on initialized proxy — isGroovyMethod + initialized reflection path
- invokeMethod('namedAndCode') on initialized proxy — isGroovyMethod + initialized path
- proxy.id on uninitialized proxy — identifier short-circuit, returns id without init

Note: the method==null branch calls super.intercept which NPEs in Hibernate's
BasicLazyInitializer; it is unreachable defensive dead code and not tested.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ibernateTemplate coverage to 67 tests

- Introduce TransactionResources interface wrapping all
  TransactionSynchronizationManager static calls
- Add DefaultTransactionResources as the production delegation impl
- Replace all 20 direct TSM static calls in GrailsHibernateTemplate
  with txResources field calls, enabling full unit-test controllability
- Expand GrailsHibernateTemplateSpec from 18 to 67 tests covering:
  * hibernateFlushModeToConstant all 4 branches
  * 2-arg and 3-arg constructors
  * refresh(entity, LockMode) non-null lock mode path
  * deleteAll and getIterableAsCollection (Collection + raw Iterable)
  * executeFind list and non-list (InvalidDataAccessApiUsageException)
  * executeWithExistingOrCreateNewSession both branches
  * shouldPassReadOnlyToHibernate all 5 branches via stubbed TransactionResources
  * applyFlushMode all 14 branches via Mock(Session)
  * doExecute exception paths: HibernateException, PersistenceException
    with/without HibernateException cause, SQLException (23000 state)
  * createSessionProxy JDK proxy path (exposeNativeSession=false)
  * flushIfNecessary FLUSH_EAGER path

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add ConstrainedPerson entity with blank:false constraint for
  validation path coverage
- New tests covering:
  * lock(instance) pessimistic write lock
  * save(validate:false) skips validation path
  * save(deepValidate:false) hits deepValidate argument branch
  * validation error returns null and sets errors (failOnError=false)
  * validation error with failOnError:true throws exception
  * save without flush: arg — shouldFlush falls back to autoFlush
  * isDirty/getDirtyPropertyNames return false/empty for transient instance
  * getPersistentValue returns null for unknown field and non-attached instance
  * autoRetrieveAssociations: null propValue branch, already-contained
    branch, and detached author full-fetch path

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…astoreForConnection branches

- Add import for Settings and ConfigurationException
- Cover SETTING_DATASOURCE branch (returns parent)
- Cover unknown connection name branch (throws ConfigurationException)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Added 12 new tests covering:
- null-id guard branches: get, read, load, proxy, exists all return null/false
- first/last on empty table returns null
- findWhere/findAllWhere with empty map returns null/empty
- list with max parameter returns HibernatePagedResultList
- convertIdentifier non-parseable String -> null
- getQualifier returns explicit qualifier set in constructor

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Production changes (visibility only, no behaviour change):
- activateDirtyChecking: private -> protected
- synchronizeHibernateState(EntityPersister, Object[], Map): private -> protected
- Extract resolvePersistentEntity(Class<?>) protected hook (used by onPreInsert and onPreUpdate)

New tests added (6 tests, up from 13):
- setApplicationContext with non-ConfigurableApplicationContext leaves eventPublisher null
- activateDirtyChecking fast-exits for non-DirtyCheckable entity
- activateDirtyChecking is idempotent when entity is already tracking (dirtyCheckingState != null)
- synchronizeHibernateState skips entries whose attributeMapping is null
- onPreInsert falls back to entity-only PreInsertEvent when resolvePersistentEntity returns null
- injectCallbackRegistry delegates to persistEventListener without throwing

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
File is listed in .gitignore and should never have been force-added.
Remove from index; local copy is preserved.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…pSecondPassBinder coverage

GrailsHibernateUtil (9 new tests, 24 total):
- isDomainClass: Closure→false, Enum→false, POJO with id+version fields→true
- ensureCorrectGroovyMetaClass: already-matching metaclass no-op, non-GroovyObject no-op
- setObjectToReadyOnly: entity not in session within tx
- setObjectToReadWrite: transient entity (EntityEntry null) branch
- setObjectToReadyOnly + setObjectToReadWrite full round-trip

SchemaTenantGormEnhancer (1 new test, 7 total):
- allQualifiers via schemaHandler path (tenantResolver NOT AllTenantsResolver)
  triggers resolveSchemaNames() and filters INFORMATION_SCHEMA/PUBLIC

MapSecondPassBinder (3 new tests, 7 total):
- getSingleColumnConfig: null propertyConfig → null
- getSingleColumnConfig: empty columns list → null
- getSingleColumnConfig: non-empty list → returns first column

Production visibility changes (no behaviour change):
- CollectionBinder.mapSecondPassBinder: private → package-protected
  (fixes Groovy 4 module-system reflection block preventing coverage)
- MapSecondPassBinder.getSingleColumnConfig: private → package-protected
  (enables direct unit testing of null-path branches)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Added 7 new tests covering previously uncovered branches:
- buildConfiguration applies applicationContext when set (L184)
- buildConfiguration uses factory-level hibernateEventListeners over settings (L209)
- extractDataSourceFallback: HibernateConnectionSourceSettings branch (L136) via buildSettings with HCS fallback
- extractDataSourceFallback: DataSourceSettings branch (L139) via buildRuntimeSettings with DS fallback
- applyResources IOException catch → ConfigurationException (L106-110) via mock Resource
- configureNamingStrategy Throwable catch → ConfigurationException (L123-124) via BrokenNamingStrategy
- buildSettings datasources.dataSource qualified config non-empty branch (L303-304)

Added BrokenNamingStrategy helper class (no-arg constructor missing) to trigger
BeanUtils.instantiateClass Throwable path in configureNamingStrategy.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ssBinder and HibernateCompositeIdentity coverage

- Add getElementTypeName branch tests (componentType path + Object fallback) to HibernateToManyPropertySpec
- Enable SingleTableSubclassBinder debug logging in simplelogger.properties to cover the debug log branch
- Add getHibernateProperties empty-array MappingException test to CompositeIdentitySpec (8 tests total)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- EntityProxy branches: isInitialized, unwrap (getTarget), getIdentifier (getProxyKey), initialize
- GroovyProxy branch: initialize calls proxyMc.getProxyTarget
- GroovyProxy branch: getIdentifier returns id via GroovyProxyInterceptorLogic
- getAssociationProxy catch(RuntimeException) → returns null

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add GormValidationEvent import
- Add CancellingHibernateEventListener helper that returns true for Pre events
- Tests: event.cancel() for PreInsert/PreUpdate/PreDelete when handler returns true
- Tests: Validation event dispatch (onValidate), default case throws IllegalStateException
- Tests: getDatastore() returns HibernateDatastore, getTimestampProvider() returns DefaultTimestampProvider

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix PredicateGenerator instantiation to use ConversionService from mappingContext
- Fix NotIn test to use DetachedCriteria (QueryableCriteria) as required by Query.NotIn constructor
- Cover: HibernateAlias, Negation, invalid property, NotEquals, IdEquals,
  GreaterThan/GreaterThanEquals/LessThan/LessThanEquals, null numeric value,
  normalizeValue (CharSequence), RLike, NotIn subquery

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add test for string 'true' index value triggering generated index name,
covering the remaining L44 branch alongside existing Boolean and string paths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add tests for:
- createTenantId produces HibernateTenantIdProperty
- createCustom falls back to Enum base marshaller for enum type
- createBasicCollection sets custom marshaller for enum hasMany
- createBasicCollection uses Enum base marshaller for enum collection type
- createIdentityMapping throws DatastoreConfigurationException for bad generator
- createIdentityMapping returns AUTO for composite identity entity

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tityNamingStrategy coverage

- HibernateMappingContextSpec: add setDefaultConstraints, createPersistentEntity returns null
  for non-GormEntity class, and PersistentEntityNamingStrategy default resolveTableName test
- SortConfigSpec: new spec covering all 3 branches of getNamesAndDirections()
  (namesAndDirections map set / name+direction / empty fallback)
- HibernateEventListenersSpec: already fully covered by existing tests (stale report)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ryKeyValueCreator to 100%

- VersionBinderSpec: add test for OptimisticLockStyle.NONE path (entity with version false)
  + MappingFactoryNoVersionEntity helper class
- IdentityBinder/SimpleIdBinder/PrimaryKeyValueCreator: existing tests already covered all
  branches; stale JaCoCo report confirmed clean after fresh run

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…c & FindByMethodSpec are broken in grails-data-mapping-core
# Conflicts:
#	grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/PagedResultSpec.groovy
# Conflicts:
#	grails-data-hibernate5/core/src/test/groovy/grails/gorm/specs/multitenancy/MultiTenancyBidirectionalManyToManySpec.groovy
#	grails-data-hibernate5/core/src/test/groovy/grails/gorm/specs/multitenancy/MultiTenancyUnidirectionalOneToManySpec.groovy
#	grails-data-hibernate5/core/src/test/groovy/org/grails/orm/hibernate/connections/SchemaMultiTenantSpec.groovy
#	grails-data-hibernate5/core/src/test/groovy/org/grails/orm/hibernate/connections/SingleTenantSpec.groovy
#	grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/multitenancy/MultiTenancyUnidirectionalOneToManySpec.groovy
#	grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/connections/SchemaMultiTenantSpec.groovy
#	grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/connections/SingleTenantSpec.groovy
@jdaugherty
Copy link
Copy Markdown
Contributor Author

I undid the changes to tests with RestoreSystemProperties, we'll see how the memory usage goes and if we need to revert partially for a period.

@jdaugherty
Copy link
Copy Markdown
Contributor Author

I reverted the image removals in the docs, but there are still several documentation that is just blank, I think these are the main ones:

eventsAutoTimestamping.adoc
configurationDefaults.adoc
configuration/index.adoc
constraints/applyingConstraints.adoc
constraints/constraintReference.adoc
constraints/gormConstraints.adoc
constraints/index.adoc
databaseMigration/*
gettingStarted/*
gettingStarted.adoc
multipleDataSources/*
multiTenancy/*
services/*
testing/*
learningMore.adoc

@jdaugherty
Copy link
Copy Markdown
Contributor Author

I still need to extract the customizations to the gradle convention plugins and rework those.

@testlens-app
Copy link
Copy Markdown

testlens-app Bot commented May 14, 2026

✅ All tests passed ✅

🏷️ Commit: 07d176e
▶️ Tests: 27732 executed
⚪️ Checks: 34/34 completed


Learn more about TestLens at testlens.app.

@jdaugherty
Copy link
Copy Markdown
Contributor Author

I made a pass at the documentation with AI referencing the migration guides + previous hibernate 5 information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants