jamesfredley commented on PR #15510:
URL: https://github.com/apache/grails-core/pull/15510#issuecomment-4087153676
I pushed commits addressing
1. several functional tests were added for hibernate 5 and not copied to the
hibernate 7 -
2. we need to diff the hibernate 5 functional tests with hibernate 7 to see
if any were subsequently changed -
3. grails-datamapping-core changes need to be looked at closer; I might have
merged these the wrong way. - Implements an H5 and H7 solution for
DetachedCriteria.count(), the merge looked right
Known issues after these commits:
## H7 Test Gaps - Detailed Analysis
### 1. ByteBuddy Proxy Initialization (5 tests)
**Root cause:** Hibernate 7's `ByteBuddyInterceptor.intercept()` doesn't
distinguish Groovy's `getMetaClass()` call from a real property access. Any
method call on a proxy - including `getId()`, truthiness checks (`if (proxy)`),
and `isDirty()` - triggers proxy initialization via the interceptor.
**Stack trace path:**
`team.getId()` -> `ByteBuddyInterceptor.intercept()` ->
`BasicLazyInitializer.invoke()` -> initializes proxy ->
`Hibernate.isInitialized(team)` returns `true`
**Why H5 worked (partially):** In H5, `@CompileStatic` `getId()` and
`isDirty()` didn't trigger initialization because H5's `ByteBuddyInterceptor`
had slightly different interception logic. The 3 dynamic Groovy tests (truthy,
id, association id) failed in H5 too unless yakworks was present.
**Why yakworks 1.1 can't fix H7:** The yakworks `ByteBuddyGroovyInterceptor`
extends `ByteBuddyInterceptor` but its constructor takes `java.io.Serializable
id` while H7's takes `java.lang.Object id` - binary incompatible. The library
hasn't been updated since September 2022.
**Fix path:** Write a Hibernate 7-compatible Groovy interceptor that
overrides `intercept()` to return `null` for `getMetaClass()` and intercept
`toString()` to avoid hydration. Roughly 50 lines of Java. Could live in
`grails-data-hibernate7` directly rather than as an external library.
**Affected tests:**
- `getId and id property checks dont initialize proxy if in a CompileStatic
method`
- `getId and id dont initialize proxy`
- `truthy check on instance should not initialize proxy`
- `id checks on association should not initialize its proxy`
- `isDirty should not intialize the association proxy`
---
### 2. JPA @OneToMany Unidirectional Join Table (1 test)
**Root cause:** Hibernate 7 generates a single join table
`EcmMaskJpa_JpaUser` for **both** `@OneToMany` associations (`createdUsers` and
`updatedUsers`). The DDL creates columns `(EcmMaskJpa_id, createdUsers_id,
updatedUsers_id)` where ALL columns are non-nullable. When inserting a
`createdUsers` row, `updatedUsers_id` is NULL, violating the constraint.
**SQL generated:**
```sql
insert into EcmMaskJpa_JpaUser (EcmMaskJpa_id, createdUsers_id) values (?, ?)
-- Fails: NULL not allowed for column "UPDATEDUSERS_ID"
```
**Why:** Hibernate 7 merges the two `@OneToMany` sets into one join table by
default when both target the same entity type. H5 created separate join tables.
This is a Hibernate 7 behavior change for entities with multiple
`@OneToMany(cascade=ALL)` to the same target type.
**Fix path:** Add `@JoinTable` annotations to specify separate tables:
```java
@OneToMany(cascade = CascadeType.ALL)
@JoinTable(name = "ecm_mask_created_users")
Set<JpaUser> createdUsers = []
@OneToMany(cascade = CascadeType.ALL)
@JoinTable(name = "ecm_mask_updated_users")
Set<JpaUser> updatedUsers = []
```
**Affected test:**
- `test two JPA unidirectional one to many references`
---
### 3. executeQuery Named Parameters on Multi-Datasource Entity (1 test)
**Root cause:** `Book.executeQuery("from Book where name = :name", [name:
uniqueName])` throws `QueryParameterException: No argument for named parameter
':name'`. The parameter map IS passed, but the H7 HQL query execution path
doesn't bind it correctly when the entity is routed to a non-default datasource.
**Stack trace path:**
```
GormEntity.executeQuery()
-> HibernateGormStaticApi.executeQuery()
-> doListInternal()
-> HibernateHqlQuery.executeQuery()
-> SelectQueryDelegate.list()
-> AbstractSelectionQuery.list()
-> QueryParameterBindingsImpl.validate()
-> throws QueryParameterException
```
**Why:** The `HibernateHqlQuery` in H7 creates the Hibernate `Query` object
and passes parameters, but when routing through a non-default datasource
connection, the parameter binding happens on a different session than expected.
The `SelectQueryDelegate` creates the native Hibernate query but the parameters
from the GORM map aren't being forwarded to it properly.
**Fix path:** Debug `HibernateHqlQuery.executeQuery()` and
`SelectQueryDelegate.list()` to verify parameter binding when the session comes
from a non-default datasource. Likely a session/query mismatch in the
multi-datasource routing code.
**Affected test:**
- `static GORM operations use first non-default datasource for multi
datasource entity`
--
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]