matrei opened a new issue, #16423:
URL: https://github.com/apache/grails-core/issues/16423
With `grails-data-hibernate7` 8.0.0-RC1, saving a new instance of a domain
class annotated with `@ManagedEntity` fails with an `AssertionError` whenever
JVM assertions are enabled (`-ea`). Gradle's `Test` tasks turn assertions on by
default, so any integration test that boots the application and saves such an
entity (e.g. in `BootStrap`) fails to load the application context.
`HibernateEntityTransformation` adds the `$$_hibernate_instanceId` field
with an initial value of `-1`:
```groovy
//
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/compiler/HibernateEntityTransformation.groovy:187
FieldNode instanceIdField = classNode.addField(instanceIdFieldName,
Modifier.PRIVATE | Modifier.TRANSIENT, ClassHelper.int_TYPE, constX(-1))
```
Hibernate 7 expects an entity that is not yet associated with a persistence
context to have an instance id of `0`:
```java
// org.hibernate.engine.internal.EntityEntryContext#addEntityEntry
(hibernate-core 7.4.10.Final, line 98)
if ( isManagedEntity( entity ) ) {
final var managed = asManagedEntity( entity );
assert managed.$$_hibernate_getInstanceId() == 0;
```
Hibernate's own bytecode enhancer
(`EnhancerImpl#addFieldWithGetterAndSetter`) defines this field without an
initializer, so enhanced entities start at `0`.
When assertions are disabled, the value is overwritten through
`$$_hibernate_setPersistenceInfo(...)` as soon as the entity is associated, so
production behavior appears unaffected. The mismatch still violates Hibernate's
contract, and it breaks any test run with assertions enabled.
The issue is still present on the `8.0.x` and `8.1.x` branches.
### Expected Behavior
The entity is saved.
### Actual Behaviour
```
Caused by: java.lang.AssertionError
at
org.hibernate.engine.internal.EntityEntryContext.addEntityEntry(EntityEntryContext.java:98)
at
org.hibernate.engine.internal.StatefulPersistenceContext.addEntry(StatefulPersistenceContext.java:675)
at
org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:280)
...
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:692)
at
org.grails.orm.hibernate.HibernateGormInstanceApi$_performPersist_closure6.doCall(HibernateGormInstanceApi.groovy:400)
```
### Steps To Reproduce
1. Create a Grails 8.0.0-RC1 app using `grails-hibernate7-bom` /
`grails-data-hibernate7`.
2. Annotate a domain class with
`@grails.gorm.hibernate.annotation.ManagedEntity`.
3. Save a new instance, e.g. in `BootStrap`: `new Role(authority:
'ROLE_USER').save(failOnError: true)`.
4. Run with assertions enabled, e.g. `./gradlew integrationTest`.
### Suggested Fix
Initialize the field to `0` (or add it without an initial expression),
matching Hibernate's enhancer:
```diff
-FieldNode instanceIdField = classNode.addField(instanceIdFieldName,
Modifier.PRIVATE | Modifier.TRANSIENT, ClassHelper.int_TYPE, constX(-1))
+FieldNode instanceIdField = classNode.addField(instanceIdFieldName,
Modifier.PRIVATE | Modifier.TRANSIENT, ClassHelper.int_TYPE, constX(0))
```
It would also help to have a test in `HibernateEntityTransformationSpec`
asserting that a new instance returns `0` from `$$_hibernate_getInstanceId()`,
and to run the hibernate7 test suite with assertions enabled.
### Workaround
Disable assertions for that Hibernate class in the test JVMs. A
class-specific `-da:` switch takes precedence over a global `-ea`:
```groovy
tasks.withType(Test).configureEach {
jvmArgs('-da:org.hibernate.engine.internal.EntityEntryContext')
}
```
### Environment Information
- Hibernate ORM 7.4.10.Final
- Groovy 5.1.3, Spring Boot 4.1.1
- JDK 21, Gradle 9.7.1
### Example Application
_No response_
### Version
8.0.0-RC1
--
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]