borinquenkid opened a new pull request, #16568: URL: https://github.com/apache/grails-core/pull/16568
> **Depends on #16351** (the Java-to-Groovy migration): this branch is based on `9.0.x-java-to-groovy`, so until #16351 merges the diff shown here includes it. Once it merges, the diff shrinks to the 127 commits of this PR. Opened as a draft for that reason. The two follow-ups are stacked on it: native binding as the default, then the deletion of the classic binder. ## What GORM for Hibernate 7 gains **native domain binding**: a `GrailsDomainGenerator` turns an already-built GORM `PersistentEntity` into a JPA/Hibernate-annotated carrier class, and Hibernate's own annotation binder binds it. Sessions, queries and proxies keep using the real domain classes (the carrier's entity name, cache regions and class-loader lookups all resolve to the real class). In this PR it is **opt-in** (`hibernate.generatedDomainClasses: true`); the next PR in the stack makes it the default, and the last one deletes the hand-built `GrailsDomainBinder`. ## Why The classic binder re-implements Hibernate's boot model by hand (~5,800 lines) and has been the source of a steady stream of mapping defects (seven of them fixed on `8.0.x` during this work: #16520, #16522, #16523, #16524, #16531, #16532, #16533, #16539). Letting Hibernate bind the entities removes that layer; the GORM mapping DSL stays the public surface. ## Scope * `grails-data-hibernate7/core`, package `org.grails.orm.hibernate.cfg.domainbinding.jpa`: `GrailsDomainGenerator` (ByteBuddy; every mapping option the classic binder honours, incl. composite identifiers via `@IdClass`, embedded types, all three inheritance strategies, multi-tenancy, natural ids, caches, custom and converting types, custom collection types), `GeneratedDomainClassBinder` (`AdditionalMappingContributor` plus an aligner that reproduces the classic binder's naming and DDL decisions where Hibernate's defaults differ), `GeneratedDomainClassLoader[Service]`. * `ManyToManyOwnerValidator`: a bidirectional many-to-many with `belongsTo` on neither side now **fails at startup** (`MappingException`) instead of silently never being written; on `8.0.x` the same case logs a warning (#16532). * Envers: a generated entity carries a JPA `@Version`, which Envers would skip; the optimistic-lock column is audited as before unless the application sets `org.hibernate.envers.do_not_audit_optimistic_locking_field` itself. * Tests: 26 both-modes specs under `grails.gorm.tests.generated`, the whole core suite runnable through the generated classes (`-Pgrails.test.generatedDomainClasses=true`), and two differentials that compare native binding with the classic binder over every scanned test domain class (1,169 entities, 3,381 properties: **0 mismatches**; DDL: **85 known differences, 0 unknown, 0 refused**). The classic side of both differentials is **frozen** as recorded data (`src/test/resources/classic-oracle/`), so they survive the deletion of the classic binder. * Docs: new chapter *Native Domain Binding* in the GORM for Hibernate 7 manual (what stays the same, what changes in behaviour and schema, switching an existing database, Envers, the one unsupported mapping and its workaround), configuration reference, Hibernate 7 migration checklist, and the Grails 8 → 9 upgrade notes (`upgrading90x.adoc` §1). Also in this PR, because the branch has to pass the repository's CodeNarc rules: the `grails-startup-progress` sources that arrived from upstream in Java are converted to Groovy, and intentionally empty catch parameters are named `ignored` in seven modules. ## Behaviour changes for applications (all documented in the upgrade notes) * A many-to-many without an owning side fails at startup. * With native binding on: a custom `UserCollectionType` on a `hasMany` of entities takes effect (the classic binder ignored it); a shared embedded collection gets a table per owner; an embedded object as a part of a composite identifier is refused with a message pointing at the documented flattening workaround; a handful of schema differences listed in the manual (for example `check (idx >= 0)` on list index columns). ## Verification Every module of `grails-data-hibernate7` in both modes at the tip of this PR: core 4,813 tests (classic default) and 4,523 (generated), dbmigration-core 40, dbmigration 110 + 93 CLI, plugin 39 + 2, spring-boot 2, all green; both differentials as above; `codeStyle` clean; docs built. 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
