Skip to content

Expand Hibernate 7 functional coverage and query parity#15731

Open
jamesfredley wants to merge 44 commits into
8.0.x-hibernate7from
test/h7-functional-coverage
Open

Expand Hibernate 7 functional coverage and query parity#15731
jamesfredley wants to merge 44 commits into
8.0.x-hibernate7from
test/h7-functional-coverage

Conversation

@jamesfredley

@jamesfredley jamesfredley commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR expands the Hibernate 7 functional-test path and closes several parity gaps found while running the functional applications against Hibernate 7. The branch targets 8.0.x-hibernate7 and includes the functional matrix work plus follow-up fixes, documentation, Hibernate ORM 7.4 alignment, and review-gate cleanup.

The main outcome is that Hibernate 5 and Hibernate 7 functional lanes can run from the same workflow while known H7-incompatible general projects remain explicitly excluded until their association-rendering, unique-constraint, and datasource gaps are fixed.

Spring Boot 4.1 now manages Hibernate ORM 7.4, and Hibernate ORM 7.4 is the current stable Hibernate 7 line. Hibernate ORM 7.3 and 7.2 are limited-support lines, so this PR updates the Hibernate 7 path to Hibernate ORM 7.4.1.Final while keeping Hibernate Tools on 7.3.8.Final because no Hibernate Tools 7.4 artifact is published.

Detailed issue coverage

Area Issue Why it is an issue How it manifests Fix in this PR
Functional CI matrix General functional tests were not consistently exercised against both Hibernate 5 and Hibernate 7. Hibernate 7 regressions could be hidden because the broad application test suite mostly validated the Hibernate 5 dependency path. CI could publish artifacts even when the H7 functional lane was not part of the publish dependency chain. Adds the H5 and H7 functional jobs to the publish dependency gate and wires the functional-test configuration so H7 can substitute the Hibernate 7 BOM where appropriate.
H7 dependency routing General test applications need Hibernate 7 constraints when -PhibernateVersion=7 is selected. Without BOM substitution, applications can still resolve Hibernate 5 aligned constraints or incompatible dependency combinations. H7 functional runs fail during dependency resolution or boot with mismatched Hibernate and Micronaut platform dependencies. Redirects the default BOM to grails-hibernate7-bom for eligible general functional tests and aligns the H7 Hibernate version to 7.4.1.Final.
Hibernate 7 support line The branch previously targeted Hibernate ORM 7.2 even though Spring Boot 4.1 manages Hibernate ORM 7.4. Hibernate ORM 7.3 and 7.2 are limited-support lines, so new H7 work should target the actively maintained Hibernate 7 line. Grails could appear to certify a limited-support Hibernate line while Boot-based applications resolve a newer ORM line. Moves the Hibernate 7 path to Hibernate ORM 7.4.1.Final and documents that Hibernate 7.4 is the target line.
Hibernate Tools alignment Hibernate Tools does not currently publish a 7.4 artifact matching Hibernate ORM 7.4. Reusing the ORM version for Tools would resolve a non-existent artifact. Dependency resolution can fail for org.hibernate.tool:hibernate-tools-orm:7.4.1.Final or hibernate-tools-utils:7.4.1.Final. Adds a separate hibernate-tools.version and pins Hibernate Tools to 7.3.8.Final while ORM uses 7.4.1.Final.
Hibernate 7.4 metadata API Hibernate 7.4 adds an isView argument to InFlightMetadataCollector.addTable(...). Existing Grails domain binding code and tests called the older six-argument method. Compilation fails in collection, root, joined-subclass, and second-pass binding tests. Updates production binding calls and Spock mocks to pass isView=false.
Database migration bootstrap API Hibernate 7.4 eliminates raw or string-only map typing in JPA bootstrap contracts. The database migration integration used Map<String, String> for settings that Hibernate now accepts as Map<String, Object>. grails-data-hibernate7-dbmigration-core can fail Java compilation against Hibernate 7.4. Widens the bootstrap settings map to Map<String, Object>.
Hibernate proxy interception The H7 proxy interceptor carried a fallback workaround for older ByteBuddy proxy behavior. The workaround duplicated Hibernate 7.4 proxy invocation behavior and touched proxy internals that are no longer needed. Proxy method interception could diverge from the Hibernate 7.4 ByteBuddyInterceptor path. Removes the obsolete fallback and delegates to Hibernate's current invocation path after the Grails uninitialized-proxy guards run.
Simple identifier primary keys SimpleIdBinder installed an empty PrimaryKey before Hibernate created the table primary key. Hibernate 7.4 expects RootClass.createPrimaryKey() to build the populated primary key from the bound identifier columns. Schema metadata can end up with an empty or incorrect primary key. Stops pre-installing the empty primary key and adds coverage that Hibernate creates a one-column table primary key after identifier binding.
Composite identifier associations Composite-id many-to-one and dependent collection keys needed stricter column ordering under Hibernate 7.4. Hibernate 7.4 validates composite key and foreign-key column ordering more strictly. Composite-id specs can fail with mismatched FK columns, sequence/composite interactions, or unstable dependent key ordering. Sorts referenced component identifiers, sorts or indexes local FK columns consistently, creates FK metadata with matching referenced columns, sorts bidirectional one-to-many keys, and avoids marking dependent component keys sorted too early.
Identity generator tests Hibernate 7.4 generator creation needs type information from the generator context. The spec mocks did not provide the type metadata used by the current generator path. GrailsIdentityGeneratorSpec fails even though production generator behavior is valid. Stubs GeneratorCreationContext.getType().getReturnedClass() in the affected specs.
Event listener tests Hibernate 7.4 event/session access calls EventSource.asEventSource() and getFactory() in this path. The event listener spec mock did not behave like a current Hibernate event source. HibernateEventListenerSpec fails during listener invocation. Updates the mock event source to return itself from asEventSource() and the mocked session factory from getFactory().
Known H7-incompatible apps datasources, views-functional-tests, and scaffolding-fields are not safe to run as generic H7 substitution projects yet. Enabling them would turn known uncovered behavior into noisy CI failures instead of actionable coverage. Datasources still needs explicit H7 duplicates for some coverage; views/scaffolding boot with substitution but fail on association rendering and unique-constraint behavior. Keeps those projects in h7IncompatibleProjects and documents the reason for each exclusion directly in gradle/functional-test-config.gradle.
Forge analytics dependencies Forge analytics Postgres was using the old Micronaut BOM coordinate. The old coordinate does not match the platform coordinate used by current Micronaut dependency management. H7 functional/Forge dependency resolution can fail or pull inconsistent dependency constraints. Switches to io.micronaut.platform:micronaut-platform and centralizes the Testcontainers version used by the Forge H7 path.
H7 application boot Some functional test apps still carried Hibernate 5 specific configuration. H5-specific cache/autoconfiguration prevents the same app from proving H7 behavior. H7 app boot fails before specs can exercise GORM behavior. Registers H7 autoconfiguration, removes H5-specific Ehcache assumptions, and updates H7 functional app configuration.
Safe HQL usage Some functional specs used ambiguous plain String HQL forms where the H7 API expects parameterized or safer overloads. Hibernate 7 query construction is stricter and the GORM API intentionally steers callers away from unsafe interpolation patterns. executeQuery or related calls fail with unsupported or unsafe String HQL usage. Updates affected specs to use safe HQL overloads and correct application class setup.
DetachedCriteria single-result behavior Hibernate 7 throws when getSingleResult() returns more than one row. GORM's historical behavior is to return the first matching row for single-result helpers where multiple rows can match. DetachedCriteria.get() can throw NonUniqueResultException in H7 where H5 returned one result. Adjusts H7 query handling so single-result paths limit to one row or otherwise match the GORM contract.
Managed collection identity Hibernate 7 is stricter about multiple representations of the same collection. GORM add-to/save flows must not leave duplicate collection wrappers in the session. Cascade/add-to functional specs can fail with Found two representations of same collection. Fixes the H7 managed-entity add-to/save path so the bidirectional collection state remains consistent.
Aggregate query result typing H7 enforces selected result type more strictly than H5. Aggregate HQL like avg, max, min, and sum does not return the domain entity type. Data service aggregate queries fail with incorrect result type errors. Routes aggregate/projection HQL through query creation that lets Hibernate return the correct scalar type.
Cross-property arithmetic H7 SQM typing is stricter for numeric property comparisons. GORM where queries comparing differently typed numeric expressions need explicit type handling. Expressions such as pageCount > price * 10 can fail with coercion errors. Updates the H7 where/query handling so cross-property arithmetic comparisons work under H7.
findWhere result limiting H7 findWhere did not reliably limit duplicate matches to a single row. findWhere is a single-result convenience API and should not allow duplicate matches to produce multiple-row failures. Duplicate rows matching the property map can throw or behave differently from H5. Forces findWhere to set max: 1 internally and adds SQL-capture coverage proving the generated query includes the row limit.
Null values in findWhere and findAllWhere The generated HQL treated null map values as named parameters. In SQL/HQL, = null does not match null rows; it must be is null. findWhere(nullableProperty: null) and findAllWhere(nullableProperty: null) fail to find rows with null values. Generates is null for null values and removes those values from named parameters.
Property-map query safety Property names from findWhere and findAllWhere were interpolated into HQL without validation. Property-map keys are caller input at the API boundary and should not become arbitrary HQL fragments. Invalid or malicious keys could produce malformed HQL or unsafe generated query text. Validates every key against the persistent entity before building HQL and tests invalid property names.
getAll ordering with convertible ids H7 converted ids before querying but reconstructed results with the original id values. When callers pass string ids for numeric identifiers, the returned row map is keyed by converted ids. getAll(["3", "1", "2"]) can return nulls or the wrong order even though those rows exist. Reconstructs the result list using converted ids and documents that existing ids preserve caller order.
HQL query settings H7 HQL helpers only partially applied common GORM query settings. Users expect settings such as fetchSize, timeout, readOnly, cache, max, offset, flushMode, and lock to behave consistently. String values for max or offset can fail casts, cache might not be applied, and lock was not filtered from named parameters. Converts string/number/boolean setting values, applies all supported settings, maps lock: true to pessimistic write locking, disables query cache for locked queries, and filters lock from query parameters.
TCK spec migration Some migrated H7 TCK specs had missing imports or stale registration code. The H7 TCK specs must compile and exercise the same public behavior as the source TCK specs. Specs fail at compile time or register the wrong domain set. Restores required HibernateGormDatastoreSpec imports, removes duplicate setup, and narrows Spock imports.
H7 has-many support class Something.groovy referenced Book without the required imported package. Test support classes must compile in isolation under the H7 module. Compilation can fail because Book is in grails.gorm.tests.hasmany, not the support class package. Adds the explicit Book import.
Multitenancy package scanning The multitenancy spec scanned the spec package instead of the package containing the support domain and services. The datastore only discovers classes in the package it scans. Services or domain classes can be missing when the spec starts the datastore. Imports the support classes explicitly and scans Department.getPackage().
Public documentation The H7 behavior changes were not reflected in the user-facing docs. Users need documented contracts for query settings, finder null handling, property validation, lock behavior, getAll ordering, and remaining Hibernate 7.4 migration differences. The reference pages understate supported settings or omit the new null/order behavior and remaining Hibernate 7.4 migration checks. Updates the Hibernate 7 guide and Grails reference docs for HQL settings, lock, findWhere, findAllWhere, getAll, and the remaining Hibernate 7.4 migration checklist.
Historical bug report H7_GORM_BUG_REPORT.md was useful triage context but lacked an Apache header and read like current expected failure status. New source files need ASF licensing, and stale present-tense failure statements mislead reviewers. RAT/compliance review would fail, and readers could think fixed failures are still expected. Adds the Apache/SPDX Markdown header, frames the report as historical triage rationale, and normalizes dash typography.

Verification

  • git diff --check origin/8.0.x-hibernate7...HEAD completed with no output.
  • Dash typography search in H7_GORM_BUG_REPORT.md completed with no output.
  • Markdown LSP diagnostics for H7_GORM_BUG_REPORT.md found no diagnostics.
  • Java LSP diagnostics for HqlQueryMethods.java and SelectHqlQuery.java found no diagnostics.
  • Groovy/AsciiDoc LSP diagnostics are not authoritative in this workspace because the Groovy server does not have the Gradle classpath and there is no AsciiDoc LSP configured.
  • ./gradlew --no-daemon --no-parallel :grails-data-hibernate7-core:test --tests "org.grails.orm.hibernate.HibernateGormStaticApiFindWhereSpec" --tests "org.grails.orm.hibernate.HibernateGormStaticApiSpec" --tests "org.grails.orm.hibernate.query.HqlQueryMethodsSpec" --tests "org.grails.orm.hibernate.query.SelectHqlQuerySpec" passed after cleaning :grails-core: 130 tests, 130 successes, 0 failures.
  • ./gradlew :grails-data-hibernate7-core:test --rerun-tasks --stacktrace passed: 2921 tests, 0 failures.
  • ./gradlew :grails-data-hibernate7-dbmigration-core:compileJava passed.
  • ./gradlew :grails-data-hibernate7-dbmigration-core:test --rerun-tasks --stacktrace passed.
  • ./gradlew aggregateViolations --continue passed.
  • ./gradlew :grails-data-hibernate7-docs:asciidoctor passed after adding the Hibernate 7.4 migration checklist. Existing AsciiDoctor warnings remain in unrelated pre-existing docs.
  • ./gradlew --no-daemon --no-parallel :grails-data-hibernate7-docs:asciidoctor :grails-doc:publishGuide -x aggregateGroovydoc passed and built the user manual before the final Hibernate 7.4 checklist expansion.

Known follow-up work not included here

Project Current state Follow-up needed
grails-test-examples-datasources Partial H7 coverage exists in grails-test-examples/hibernate7/grails-multiple-datasources, but not all datasource-switching and OSIV coverage has an H7 duplicate. Add explicit H7 duplicate specs before enabling the general project under H7 substitution.
grails-test-examples-views-functional-tests Boots with H7 substitution but has functional failures around association rendering. Fix the rendering behavior or add H7-specific coverage before removing it from h7IncompatibleProjects.
grails-test-examples-scaffolding-fields Boots with H7 substitution but has Geb failures around association rendering and unique-constraint behavior. Fix those H7 behavior gaps before enabling the general project under H7 substitution.

Hibernate 7.4 vs Hibernate 5.6 end-application breaking-change checklist

This table is the migration checklist for application code. It calls out the places where Hibernate 7.4 is stricter or behaves differently than Hibernate 5.6, what can break in real applications, whether this PR resolves the Grails-facing issue, and what application owners should change or verify.

Status Area Hibernate 5.6 behavior Hibernate 7.4 behavior What can break in applications Application migration action
Remaining app migration item Hibernate module dependencies Applications commonly depend on Hibernate 5 aligned Grails artifacts and constraints. Applications must resolve the Hibernate 7 aligned artifacts and constraints together. Mixing grails-data-hibernate5, H5 BOM constraints, or H5-only transitive dependencies with the H7 runtime can fail dependency resolution or application boot. Use the Hibernate 7 BOM/artifacts consistently. Do not mix H5 and H7 GORM/Hibernate artifacts in the same application runtime.
Remaining app migration item H5-specific cache setup H5 applications may rely on Ehcache/Hibernate 5 cache integration and related configuration. H7 no longer supports the same H5-specific cache integration path. Boot can fail before application code runs when H5 cache classes or region-factory settings are still configured. Remove H5-specific cache dependencies and configuration. Reintroduce caching only with H7-compatible cache providers and settings.
Intentional behavior change Plain String HQL in executeQuery and executeUpdate H5-era code often used plain string HQL without an explicit params map. The H7 GORM path is stricter and expects safe parameterized usage. Calls such as Book.executeQuery("from Book where inStock = true") can be rejected or fail in tests that previously passed. Use an explicit params overload, for example executeQuery("from Book where inStock = true", [:]), positional params, named params, or a GString path where parameters are deliberately bound.
Partly resolved by this PR for GORM APIs Single-result queries with multiple rows H5 paths often returned the first row for GORM single-result helpers when multiple rows matched. Hibernate 7.4 inherits the Hibernate 7.3 getSingleResult() strictness and throws when more than one row matches. Direct Hibernate/JPA calls can throw NonUniqueResultException where H5 returned one row. GORM helpers fixed by this PR preserve expected first-row behavior. Direct Hibernate/JPA usage should add maxResults(1) or use a list query and take the first result intentionally.
Resolved by this PR findWhere duplicate matches H5 findWhere behaves as a first-match helper. The H7 implementation needs an explicit one-row limit to avoid strict single-result failures. Duplicate property-map matches can fail instead of returning one instance. No app change is needed when using the fixed GORM API from this PR. Direct custom single-result HQL should still add an explicit limit.
Resolved by this PR Null property-map values H5 GORM property-map queries treat findWhere(prop: null) and findAllWhere(prop: null) as null checks. HQL requires is null; passing null as a named value does not match null rows. Null-valued property-map lookups can return no rows or behave differently if generated as = :param with a null value. Use the fixed GORM APIs from this PR. In custom HQL, write is null or is not null explicitly rather than = :param with a null parameter.
Intentional behavior change Property-map query keys H5-era code could accidentally rely on permissive interpolation of property-map keys. The H7 path validates keys against real domain properties before generating HQL. Code that passes computed, misspelled, or HQL-fragment-like keys to findWhere or findAllWhere now fails fast. Pass only real domain property names as map keys. Move dynamic predicates to criteria, where queries, or explicit HQL with bound parameters.
Resolved by this PR getAll order with converted ids H5 GORM preserves caller id order, including common string-to-number id conversion cases. H7 must compare results against converted identifiers, not the original raw id values. getAll(["3", "1", "2"]) can return null entries or wrong ordering if id conversion is not considered. Use the fixed GORM API from this PR. For custom in (:ids) queries, remember SQL does not preserve input order unless you reorder results yourself.
Partly resolved by this PR for GORM query construction Aggregate HQL result typing H5 was more permissive about query result type mismatch. H7 validates the selected result type strictly. Queries like select avg(price) or select max(pageCount) can fail if they are created as typed entity queries or mapped to the wrong return type. GORM aggregate/projection HQL paths fixed by this PR avoid entity-typed query creation where appropriate. Direct Hibernate queries should use scalar-compatible return types.
Partly resolved by this PR for data-service aggregate paths Data service aggregate methods H5 often tolerated loose aggregate method return typing. H7's stricter result typing makes mismatches visible. Data service methods returning a type that does not match the aggregate result can fail at runtime. Review @Query aggregate return types. avg generally returns Double; max and min follow the selected expression type; count returns Long.
Partly resolved by this PR for GORM where queries Cross-property numeric arithmetic H5 allowed more implicit numeric coercion in where/HQL predicates. H7 SQM typing is stricter about comparing different numeric expression types. Queries such as where { pageCount > price * 10 } can fail when operands resolve to incompatible numeric types. GORM where-query comparison handling is fixed by this PR. Direct HQL should align domain numeric types, cast explicitly where needed, or adjust expressions so both sides have compatible types.
Partly resolved by this PR for GORM add-to/save paths Managed collection identity H5 tolerated some duplicate representations of the same collection in a session. H7 detects duplicate managed collection wrappers more aggressively. addTo*, cascade saves, detached graph merges, or replacing collection instances can throw Found two representations of same collection. Prefer mutating the managed collection instance instead of replacing it. Be careful when merging detached graphs; reload managed parents and apply changes to the managed association.
Partly resolved by this PR for GORM helper paths Bidirectional association synchronization H5 could be more forgiving when only one side of an association was updated. H7 is less tolerant of inconsistent managed association state during flush. Saves involving parent/child associations can fail or leave stale collection snapshots. Keep both sides of bidirectional associations synchronized. Use GORM addTo* and removeFrom* helpers where possible.
Documented behavior change Locking and query cache H5-era code may combine cacheable query settings with lock settings. H7 locked queries are not query-cacheable; this PR disables query caching when lock: true is used. Code expecting a locked query to use the query cache will behave differently. Do not rely on query cache for pessimistically locked queries. Treat locked queries as database reads requiring fresh row state.
Resolved by this PR Query setting value types H5/GORM paths were often permissive about string values for settings. H7 query APIs expect typed values, and the GORM adapter must coerce supported strings. Settings such as max: "10", offset: "5", readOnly: "true", fetchSize: "50", or timeout: "30" can fail if passed directly to strict Hibernate APIs. With the fixed GORM APIs, common string settings are coerced. In direct Hibernate usage, pass typed int and boolean values.
Resolved by this PR Query setting names as parameters H5 paths may have been more permissive when internal setting names appeared beside named params. H7 must filter internal GORM settings before binding named parameters. Settings like lock, max, or offset can be mistaken for named HQL parameters if not filtered. Use the documented GORM settings map position. The fixed GORM APIs filter execution settings before parameter binding.
Remaining app migration item Read-only entity collections H5 could allow collection mutation even when the owning entity was loaded read-only. H7.3 and later mark collections owned by read-only entities as read-only too. Mutating a collection on a read-only entity can now fail. Reload the entity in a writable session before changing its collections. Do not mutate associations on read-only entities.
Remaining app migration item Timeout exception type H5 and earlier H7 lines commonly exposed QueryTimeoutException or LockTimeoutException for query and lock timeout paths. H7.3 and later may throw PersistenceException when the database marks the transaction for rollback. Timeout handling that catches only the narrower exception types can miss rollback-producing timeout failures. Catch PersistenceException around direct Hibernate/JPA timeout-sensitive code and inspect the cause when necessary.
Remaining app migration item Native SQL temporal values H5 native queries commonly returned java.sql temporal values. Hibernate 7 native SQL queries return java.time temporal values by default. Native SQL result handling can fail if it casts to java.sql.Date, Time, or Timestamp. Update result handling to java.time types, or set hibernate.query.native.prefer_jdbc_datetime_types=true during migration.
Remaining app migration item Version-column DDL H5 schema export did not necessarily declare version columns not null by default. H7.3 declares @Version columns not null by default. Schema validation or generated migration diffs can show new not-null constraints on version columns. Validate generated DDL against existing schemas before using dbCreate=update, especially for legacy nullable version columns.
Remaining app migration item General DDL generation H5 generated different column definitions for several mappings. H7 changes generated DDL for mappings including char/Character, Oracle floating point, @ElementCollection sets, @CreationTimestamp, @UpdateTimestamp, and Oracle 23c LOB columns. Automatic schema update can propose or apply unexpected column, constraint, or LOB storage changes. Prefer explicit database migrations for production schemas. Compare generated DDL in staging before using schema update tooling.
Remaining app migration item Schema actions and import.sql Schema actions could be skipped when no entities were mapped. H7.3 and later process schema actions even when no entities are mapped. An accidental import.sql on the classpath can run where it was previously ignored. Remove accidental import.sql files from the runtime classpath or make schema-generation settings explicit.
Remaining app migration item MySQL default fetch depth H5 and earlier Hibernate lines could apply a MySQL dialect-level hibernate.max_fetch_depth=2 default. H7.4 removes that MySQL-specific default. Applications relying on the implicit MySQL fetch depth can see different association fetch plans. Set hibernate.max_fetch_depth explicitly if the application relies on that behavior.
Remaining app migration item Fetch joins with limits H5 commonly handled collection fetch-join limits in memory. H7.4 applies pagination or limits with collection fetch joins in SQL. Queries combining max/offset or limits with collection fetch joins can return a different row/window shape. Review those queries and set the org.hibernate.limitInMemory query hint only when the previous in-memory behavior is required.
Remaining app migration item Oracle HQL date expressions Oracle current date and local date could preserve a time component because Oracle has no true date-only function. H7.4 translates them to trunc(current_date). Oracle HQL predicates depending on the time part can behave differently. Review Oracle queries that use current date or local date and change the expression if a timestamp is required.
Remaining app migration item Eager @Any mappings Eager @Any mappings were loaded by a separate select. H7.4 join-fetches eager @Any associations when loading an entity by id. Direct Hibernate @Any mappings can produce different SQL shape and row width. Review direct Hibernate @Any mappings for performance and row duplication implications.
Remaining app migration item Spanner PostgreSQL dialect Spanner PostgreSQL dialect lived in hibernate-community-dialects under org.hibernate.community.dialect. H7.4 moves it into hibernate-core under org.hibernate.dialect. Explicit dialect configuration can reference a class that is no longer correct. Use org.hibernate.dialect.SpannerPostgreSQLDialect or rely on automatic dialect resolution.
Remaining app migration item Envers NOT_AUDITED associations H5-era Envers behavior could read the associated target from its audit table even when NOT_AUDITED was requested. H7.3 respects RelationTargetAuditMode.NOT_AUDITED. Historic audit reads can return the current associated entity instead of a historic row. Verify Envers audit queries that use RelationTargetAuditMode.NOT_AUDITED.
Remaining follow-up Multiple datasources and OSIV H5 datasources and OSIV coverage is mature in the general functional app. H7 has partial duplicate coverage and OSIV behavior still needs explicit H7 validation. Multi-datasource switching, transactions, or GSP rendering under OSIV can behave differently after migration. End applications with multiple datasources or OSIV should run targeted H7 regression tests before migration. Do not assume H5 datasource/OSIV behavior is fully covered by the current H7 suite.
Remaining follow-up Views and scaffolding association rendering H5 functional apps currently cover association rendering and scaffolding-field behavior. H7 substitution boots those apps, but known functional failures remain around association rendering and unique constraints. Apps relying on generated scaffolding or fields rendering can see different association display or validation behavior. Treat views/scaffolding under H7 as a required migration test area. Keep custom templates and unique constraints under regression coverage until the H7 gaps are fixed.
Remaining app migration item Programmatic datastore package scanning H5 test/application setups may accidentally scan a package that still found needed classes. H7 tests exposed that the datastore must scan the package containing the actual support domains/services. Programmatic HibernateDatastore setup can miss domain or service classes if the scanned package is wrong. When constructing datastores manually, pass the package that contains the domain/service classes, not merely the spec or caller package.

jamesfredley and others added 30 commits April 7, 2026 11:01
…5 and 7

Replace the separate functional and hibernate5Functional CI jobs with a
single functional job that uses a hibernate-version matrix (['5', '7']).
This ensures all 20+ general functional tests run against both Hibernate
versions without duplicating test projects.

Changes:
- functional-test-config.gradle: Add -PhibernateVersion property that
  uses Gradle dependency substitution to redirect grails-data-hibernate5
  to grails-data-hibernate7 for general (non-labeled) test projects.
  Excludes h5-only runtime deps (hibernate-ehcache, jboss-transaction-api)
  when testing with Hibernate 7. Add skipHibernate5Tests and
  skipHibernate7Tests properties to the onlyIf block.
- gradle.yml: Merge functional and hibernate5Functional into one job
  with hibernate-version matrix. Each matrix slot skips the opposite
  version's labeled projects. Update publish job dependencies.

Assisted-by: Claude Code <Claude@Claude.ai>
The h7 boot-plugin AutoConfiguration.imports was empty, preventing
Spring Boot from discovering HibernateGormAutoConfiguration when
grails-data-hibernate7 is on the classpath. This caused GORM has not
been initialized correctly errors in functional tests running with
Hibernate 7 via dependency substitution.

Also remove Hibernate 5-specific EhCache region factory configuration
from the gorm and hyphenated functional test application.yml files.
EhCache is not available with Hibernate 7, and the second-level cache
is not needed by these tests.

Assisted-by: Claude Code <Claude@Claude.ai>
…sion=7

Five general functional test projects use Hibernate 5-specific GORM
APIs that changed in Hibernate 7. Skip them when running with
-PhibernateVersion=7 rather than letting them fail. Their h7-compatible
equivalents already exist in grails-test-examples/hibernate7/.

Incompatible projects:
- app1: HibernateSpec unit test domain class detection differs in h7
- datasources: ChainedTransactionManager commit behavior changed in h7
- gorm: executeUpdate(String) requires Map parameter in h7
- views-functional-tests: depends on h5-specific caching config
- scaffolding-fields: integration test context fails under h7

Assisted-by: Claude Code <Claude@Claude.ai>
- Fix 17 plain executeUpdate('...') calls across 7 specs in
  grails-test-examples/gorm to use executeUpdate('...', [:]).
  H7's HibernateGormStaticApi rejects plain CharSequence args
  (requires either a GString with interpolated params or the
  Map overload).

- Add getDomainClasses() override to BookHibernateSpec in app1.
  H7's HibernateSpec uses HibernateDatastoreSpringInitializer
  which requires explicit domain class declaration; H5 auto-detected
  via classpath scanning.

- Remove grails-test-examples-app1 and grails-test-examples-gorm
  from h7IncompatibleProjects list — both now run cleanly under
  Hibernate 7 via dependency substitution.

Remaining excluded: datasources (ChainedTransactionManager),
views-functional-tests (HAL/JSON diffs), scaffolding-fields
(grails-fields rendering diffs).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…urn types, cross-property arithmetic

Bug 2: HibernateQueryExecutor.singleResult() now catches both
org.hibernate.NonUniqueResultException and jakarta.persistence.NonUniqueResultException
(H7 throws the JPA variant; the original catch missed it) and returns the
first result instead of propagating.

Bug 4: HqlQueryContext.aggregateTargetClass() now returns precise types per
function: count() → Long, avg() → Double, sum/min/max() → Number.
Previously all aggregates were bound to Long, causing QueryTypeMismatchException
in H7's strict SQM type checking.

Bug 5: Cross-property arithmetic in where-DSL (e.g. pageCount > price * 10)
was silently dropped — the RHS property reference was coerced to a literal.
Fixed via:
- PropertyReference: Groovy wrapper returned by propertyMissing for numeric
  properties; *, +, -, / operators produce a PropertyArithmetic value object
- PropertyArithmetic: value type carrying (propertyName, Operator, operand)
- HibernateDetachedCriteria: H7-only DetachedCriteria subclass that overrides
  propertyMissing to return PropertyReference for numeric properties, and
  newInstance() to preserve the subtype through cloning
- HibernateGormStaticApi: overrides where/whereLazy/whereAny to use
  HibernateDetachedCriteria as the closure delegate
- PredicateGenerator: resolveNumericExpression() detects PropertyArithmetic
  and builds cb.prod/sum/diff/quot(path, operand) instead of a literal

H5 and MongoDB are unaffected — all new types are confined to grails-data-hibernate7.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ve on managed entities

H7 enforces strict collection identity during flush. GORM's addTo* and
save() flow had two failure modes:

1. When an entity is already managed in the current Hibernate session,
   calling session.merge() causes H7 to create a second PersistentCollection
   for the same role+key alongside the one already tracked in the session
   cache -> 'Found two representations of same collection'.

   Fix (HibernateGormInstanceApi.performMerge): check session.contains(target)
   before merging. If the entity is already managed, skip merge entirely;
   dirty-checking and cascade will handle children on flush.

2. When addTo* is called on a managed entity, GormEntity.addTo uses direct
   field access (reflector.getProperty) which bypasses H7's bytecode-enhanced
   interceptor, sees null, and creates a plain ArrayList on the field. H7's
   session cache already tracks a PersistentBag/Set for that role -> two
   representations on the next save.

   Fix (HibernateEntity.addTo): override addTo in the H7 trait; for managed
   entities (id != null), trigger the H7 interceptor via InvokerHelper.getProperty
   to obtain the live PersistentCollection before delegating to
   GormEntity.super.addTo.

   Fix (HibernateEntityTransformation): re-target the concrete addToXxx
   generated methods so their internal addTo call dispatches through
   HibernateEntity.addTo rather than being hard-wired to GormEntity.addTo.

   Fix (HibernateGormInstanceApi.reconcileCollections): detect stale
   PersistentCollections (session != current session) and replace them with
   plain collections before merge, covering any edge cases where the H7
   interceptor path is not taken.

Adds AddToManagedEntitySpec with 4 tests covering:
- addTo on an already-persisted entity
- multiple addTo on a fresh transient entity
- modify child + save twice
- removeFrom + save

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

- Replace executeQuery(plainString) and executeUpdate(plainString) calls
  with the (String, Map) overloads (empty map for parameterless queries).
  HibernateGormStaticApi intentionally rejects plain String in the
  no-arg overload to prevent HQL injection; parameterless static queries
  must use the Map overload.

- Add applicationClass = Application to @Integration so the spec shares
  the same application context and transaction manager as the other specs
  in this module, preventing test-data bleed between specs.

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

- Validate -PhibernateVersion accepts only '5' or '7' and fail the build fast with a GradleException for any other value (addresses Copilot review on line 31).

- Rename the counter-intuitive isHibernate5/isHibernate7/isMongo booleans in functional-test-config.gradle. The previous names used a leading ! and matched projects that were NOT that version, making the onlyIf conditions confusing. Replace with positive isHibernate5Project / isHibernate7Project / isMongoTaskProject and collapse nested ifs (addresses Copilot and @sanjana2505006 feedback).

- Fix SingleSpaceSeparator checkstyle violations in PredicateGenerator.java switch arms (blocking CI Core Projects check).

Assisted-by: claude-code:claude-opus-4
…ate-matrix-testing

# Conflicts:
#	.github/workflows/gradle.yml
#	gradle/functional-test-config.gradle
#	grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateDetachedCriteria.groovy
…tional tests

When -PhibernateVersion=7 is set, general (non-hibernate-labeled) functional test projects get the grails-data-hibernate5 module substituted with grails-data-hibernate7 via dependency substitution. However, those test projects also import platform(project(':grails-bom')) directly, which ships the Hibernate 5 version constraints.

Extend the dependency substitution to also swap the default grails-bom to grails-hibernate7-bom in the same projects, so the transitive graph gets a consistent set of Hibernate 7 version constraints. This matches the pattern used by the h7-labeled test projects in grails-test-examples/hibernate7/, which import grails-hibernate7-bom directly.

Without this, the H7 matrix slot fails with:

    Could not resolve org.hibernate.orm:hibernate-core.

    Cannot find a version of 'org.hibernate.orm:hibernate-core' that satisfies the version constraints

Assisted-by: claude-code:claude-opus-4
Two fixes to unblock CI after the recent BOM restructure on 8.0.x-hibernate7:

1) grails-forge-core/build.gradle was referencing the old grails-bom/build/publications/... path. The BOM was moved to grails-bom/default/ in the split, so grailsVersionInfo now fails with 'input file expected to be present but it does not exist'. Point the task at the new location.

2) grails-hibernate7-bom pinned hibernate.version = 7.2.5.Final via a strictly constraint, while spring-boot-dependencies:4.0.5 (transitively imported through grails-base-bom) pulls hibernate-core 7.2.7.Final. The conflicting constraints cause 'Cannot find a version of org.hibernate.orm:hibernate-core that satisfies the version constraints' whenever a general test project consumes the Hibernate 7 stack. Bump hibernate.version to 7.2.7.Final to match Spring Boot's managed version.

Assisted-by: claude-code:claude-opus-4
…ge analytics

Two follow-up fixes after the previous commit's CI run still showed missing-version resolution failures:

1) gradle/functional-test-config.gradle: the previous module-level substitution of org.apache.grails:grails-bom -> grails-hibernate7-bom didn't catch direct project references. Test build files (e.g. grails-test-examples-app1) declare 'platform(project(':grails-bom'))' literally, so dependency-substitution by module name does not match. Add a project-level substitution 'project(':grails-bom') -> project(':grails-hibernate7-bom')' that fires for the same general-functional-tests + hibernateVersion=7 condition, ensuring transitive Hibernate 7 constraints (hibernate-models, jandex, hibernate-tools-orm) get versioned.

2) grails-forge/grails-forge-analytics-postgres/build.gradle: was missing platform('io.micronaut:micronaut-bom') across all dependency configurations, so 'org.testcontainers:testcontainers-postgresql' resolved with no version and broke the Forge build. Add the platform import to annotationProcessor / implementation / testAnnotationProcessor / testImplementation to mirror the pattern used by grails-forge-cli.

Assisted-by: claude-code:claude-opus-4
…ency buckets

The previous attempt to substitute project(':grails-bom') -> project(':grails-hibernate7-bom') did not propagate version constraints to consumers because grails-data-hibernate7-core declares 'implementation platform(project(':grails-hibernate7-bom'))', and 'implementation' is not visible to downstream consumers. As a result, general functional test projects still failed with 'Could not find org.hibernate.models:hibernate-models:.' and 'Could not find io.smallrye:jandex:.' when -PhibernateVersion=7.

Drop the project-level substitute (which had no effect) and instead attach the Hibernate 7 BOM directly to the test project's dependency buckets (implementation, compileOnly, runtimeOnly, testImplementation, etc). The H7 BOM brings the version constraints into the test project's runtimeClasspath / compileClasspath where the unversioned transitive dependencies need them.

Assisted-by: claude-code:claude-opus-4
Micronaut BOM 3.10.4 sets a testcontainers.version property but does not actually publish testcontainers entries in dependencyManagement, so 'org.testcontainers:testcontainers-postgresql' kept resolving with no version. Import the testcontainers BOM explicitly to give the test classpath a real version.

Assisted-by: claude-code:claude-opus-4
…ostgresql

The dependency 'org.testcontainers:testcontainers-postgresql' does not exist in Maven Central. The actual artifact published in the testcontainers BOM is 'org.testcontainers:postgresql'. The previous testcontainers BOM import was correct, but the consumer side still used the wrong artifact name.

Assisted-by: claude-code:claude-opus-4
Same root cause as the previous commit for grails-forge-analytics-postgres: 'org.testcontainers:testcontainers-spock' is not a published artifact; the correct id is 'org.testcontainers:spock'. Add the testcontainers BOM so the version is managed centrally.

Assisted-by: claude-code:claude-opus-4
Add testcontainersVersion=1.20.4 to grails-forge/gradle.properties and reference it via the property in both forge build.gradle files instead of the inline literal.

Assisted-by: claude-code:claude-opus-4
Bring the branch up to date with its base (761 commits). Conflicts
resolved to combine both approaches:

- .github/workflows/gradle.yml: keep the base's dedicated
  hibernate5Functional/hibernate7Functional jobs and the static skip
  flags on the main job; the main functional job retains this branch's
  hibernate-version matrix so general functional tests run against both
  Hibernate 5 and 7.
- gradle/functional-test-config.gradle: keep this branch's
  -PhibernateVersion BOM redirection and h7IncompatibleProjects, plus
  the base's doNotCacheTests caching and complete only/skip filter set;
  standardize on the base's isHibernate5/isHibernate7/isMongo naming.
- grails-forge build files: use the base's centrally managed dependency
  versions.
- grails-test-examples/hyphenated application.yml: keep both the base's
  ehcache region.factory_class and this branch's endpoints.jmx config.

Assisted-by: claude-code:claude-opus-4-8
Assisted-by: Hephaestus:openai/gpt-5.5
Assisted-by: Hephaestus:openai/gpt-5.5
Assisted-by: Hephaestus:openai/gpt-5.5
Assisted-by: Hephaestus:openai/gpt-5.5
Assisted-by: Hephaestus:openai/gpt-5.5
Assisted-by: Hephaestus:openai/gpt-5.5
Assisted-by: Hephaestus:openai/gpt-5.5
Assisted-by: Hephaestus:openai/gpt-5.5
Assisted-by: Hephaestus:openai/gpt-5.5
Assisted-by: Hephaestus:openai/gpt-5.5
Assisted-by: Hephaestus:openai/gpt-5.5
@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 50.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 49.0318%. Comparing base (76340d7) to head (3ee18b8).

Files with missing lines Patch % Lines
...ng/tck/tests/DirtyCheckingAfterListenerSpec.groovy 50.0000% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@                     Coverage Diff                     @@
##             8.0.x-hibernate7     #15731         +/-   ##
===========================================================
+ Coverage             19.0184%   49.0318%   +30.0134%     
- Complexity                288      16344      +16056     
===========================================================
  Files                      57       1937       +1880     
  Lines                    3423      91614      +88191     
  Branches                  597      16004      +15407     
===========================================================
+ Hits                      651      44920      +44269     
- Misses                   2642      39703      +37061     
- Partials                  130       6991       +6861     
Files with missing lines Coverage Δ
.../grails/data/testing/tck/tests/OneToOneSpec.groovy 100.0000% <ø> (ø)
...ng/tck/tests/DirtyCheckingAfterListenerSpec.groovy 75.0000% <50.0000%> (ø)

... and 1878 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@borinquenkid borinquenkid left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to use HqlQueryContext it has all the HQL Logic

Route findWhere-generated HQL through shared preparation so query settings and hints are preserved while retaining property validation. Add mapped-column and read-only hint coverage, remove stale EhCache config from H7 sample, and fix H5/TCK style regressions from CI.

Assisted-by: Hephaestus:openai/gpt-5.5 oracle
jamesfredley and others added 4 commits June 11, 2026 19:00
Restore safe same-instance attach semantics without replication, add regression coverage for stale and deleted attach cases, and align the H5/H7 compatibility fixes needed by the functional coverage lane.

Assisted-by: opencode:gpt-5.5 oracle
Update the Hibernate 7 BOM constraints to use hibernate-models 1.1.1 so Spring Dependency Management can select Hibernate ORM 7.4.x without loading an incompatible hibernate-models API.

Assisted-by: opencode:gpt-5.5
@jdaugherty

Copy link
Copy Markdown
Contributor

I am highly against arbitrary substitution of hibernate modules. We should be cloning apps to enhance the coverage. Otherwise we will be dealing with unexpected dependency resolutions

@jamesfredley

Copy link
Copy Markdown
Contributor Author

@jdaugherty please explain why? We were missing a ton of issues and breaking changes due to the missing tests on h7? This is working and tests are not production code for end apps. This is DRY

I think we should run the same tests against both.

Assisted-by: opencode:openai/gpt-5.5
Assisted-by: opencode:openai/gpt-5.5
Assisted-by: opencode:openai/gpt-5.5
Assisted-by: opencode:openai/gpt-5.5
Assisted-by: opencode:openai/gpt-5.5
Assisted-by: opencode:openai/gpt-5.5
@jamesfredley

Copy link
Copy Markdown
Contributor Author

Updated the Hibernate 7 path to Hibernate ORM 7.4 because Spring Boot 4.1 has moved its managed Hibernate version there. Hibernate 7.3 is already in limited-support mode, so staying there would leave Grails targeting a line that is not expected to receive the ongoing updates we need. Hibernate 7.4 is the actively maintained 7.x line, so aligning with Boot 4.1 and 7.4 keeps the Hibernate 7 integration on the version that will continue to get fixes.

Assisted-by: opencode:openai/gpt-5.5
@jamesfredley

jamesfredley commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

Pushed a docs follow-up commit (a5cd019) and updated the PR description. The PR body now targets Hibernate ORM 7.4, expands the fixed-issue table for the 7.4 dependency/API, proxy, identifier, generator, and event-listener fixes, and marks resolved rows in the breaking-change checklist. The Hibernate 7 docs now document the remaining end-application migration items after the PR, including Hibernate 7.3/7.4 behavior and DDL changes that are not resolved by Grails API fixes.

@borinquenkid borinquenkid self-requested a review June 12, 2026 19:27
…perty hierarchy

Extract sortOrIndexColumns, getReferencedColumns, and setSorted dispatch
from CompositeIdentifierToManyToOneBinder into the appropriate abstraction
layers:

- GrailsHibernatePersistentEntity: add sortOrIndexForeignKeyColumns() and
  getReferencedIdentifierColumns() — identifier column knowledge belongs on
  the entity that owns the PersistentClass
- HibernatePersistentProperty: add default markValueSorted(SimpleValue) that
  handles ToOne and DependantValue via value-type dispatch — kept in the
  default (rather than subtype overrides) because DependentKeyValueBinder
  passes a HibernateToManyProperty with a DependantValue key, making
  value-type dispatch the correct strategy
- CompositeIdentifierToManyToOneBinder: remove four private helper methods;
  bindCompositeIdentifierToManyToOne now delegates in three lines
- CompositeIdentifierToManyToOneBinderSpec: revert to original two PR tests
@testlens-app

testlens-app Bot commented Jun 13, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

🏷️ Commit: 3ee18b8
▶️ Tests: 33818 executed
⚪️ Checks: 40/40 completed


Learn more about TestLens at testlens.app.

@jdaugherty

Copy link
Copy Markdown
Contributor

@jdaugherty please explain why? We were missing a ton of issues and breaking changes due to the missing tests on h7? This is working and tests are not production code for end apps. This is DRY

I think we should run the same tests against both.

I previously have explained this on multiple PRs. The issue is it complicates the setup, running locally, and troubleshooting dependency resolution. Any missing coverage we should add tests for, you have already identified the gaps so it should be easy.

@borinquenkid borinquenkid left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made changes to improve the complexity and testability

if (possibleProject.name == 'grails-bom') {
substitute module(substitutedArtifact) using platform(project(':grails-bom'))
def targetBom = redirectBomToH7 ? ':grails-hibernate7-bom' : ':grails-bom'
substitute module(substitutedArtifact) using platform(project(targetBom))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@borinquenkid my issue is this file, specifically this substitution.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Hey @jdaugherty, that makes total sense. In an OSS context, hidden classpath manipulation like this easily rots if left unchecked, and I agree we don't want people troubleshooting brittle IDE syncs locally.

Here is compromise so we can hit our end-of-June release target for Hibernate 7 parity without abandoning your architectural goal:

Fail-Safe Logging: I will add an explicit, loud deprecation warning or a hardcoded TODO block directly above this substitution in functional-test-config.gradle tracking its removal.

Immediate Post-Release Issue: I'll open a tracking issue right now to completely untangle this layer by cloning the apps into a clean directory structure.

Given that I want to completely drop Hibernate 5 support in the near future anyway, duplicating the entire H5 test matrix right this second might end up being throwaway work. Can we use this substitution as a temporary bridge to unblock the June release gate, with the explicit agreement that the cleanup issue is the immediate next priority?"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm strongly a -1 on this. People will just ignore the depreciation and it doesn't solve our actual problem. The majority of the work I've done with Grails is dependency debugging - probably over 50% of my time has been spent on it. This completely breaks that workflow. By substituting arbitrarily, we now have to populate that option throughout our workflows to be able to debug.

@matrei

matrei commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

@jdaugherty please explain why? We were missing a ton of issues and breaking changes due to the missing tests on h7? This is working and tests are not production code for end apps. This is DRY
I think we should run the same tests against both.

I previously have explained this on multiple PRs. The issue is it complicates the setup, running locally, and troubleshooting dependency resolution. Any missing coverage we should add tests for, you have already identified the gaps so it should be easy.

I think we have to switch hibernate modules for functional tests. I don't think it is scalable to duplicate all test apps. It will create a lot of duplication and a heavy maintenance burden. Can we create shell scripts or other solution to easily run both/all versions locally?

@jdaugherty

Copy link
Copy Markdown
Contributor

@jdaugherty please explain why? We were missing a ton of issues and breaking changes due to the missing tests on h7? This is working and tests are not production code for end apps. This is DRY
I think we should run the same tests against both.

I previously have explained this on multiple PRs. The issue is it complicates the setup, running locally, and troubleshooting dependency resolution. Any missing coverage we should add tests for, you have already identified the gaps so it should be easy.

I think we have to switch hibernate modules for functional tests. I don't think it is scalable to duplicate all test apps. It will create a lot of duplication and a heavy maintenance burden. Can we create shell scripts or other solution to easily run both/all versions locally?

We don't need to duplicate the functional apps themself, but rather the test coverage in the TCK or the example apps to ensure proper coverage. The problem with having switches for functionality is the build tools behave differently based on those switches. This means:

  1. Gradle caching is broken when dependencies change (this is huge and made worse by the mono project)
  2. Breaks debugging / troubleshooting since switches have to be populated through every tool (from the CLI to intellij)
  3. Tools like IntelliJ can't easily pass parameters so they will use what ever is the default. If hibernate5 is the default now, and there's a problem with 7 it's not easy to debug. Once we switch, it will be the opposite.
  4. Test coverage reports don't make it clear which version was used. This means anytime we look at code coverage or other tools we can't determine which one was the problem.

We effectively hide behavior behind a switch and Gradle is not designed for that. I'm a strong no for this reason. I believe we can add test coverage, but tests in a functional app for UrlMappings don't need hibernate and shouldn't need to be cloned. We should clone the tests that are relevant or add scenarios for them. We need to do this anyway to prevent regressions.

I realize that substitution is a short cut to getting this, but I view it as a major blocker for regular development & proper project hygiene.

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

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

5 participants