You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by bo...@apache.org on 2026/05/05 19:11:57 UTC
(grails-core) 09/10: more progress
This is an automated email from the ASF dual-hosted git repository.
borinquenkid pushed a commit to branch 8.0.x-hibernate7_gorm_enhance
in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 3ee7bf75e31fda1e5179f04dc741e243f88fea8b
Author: Walter Duque de Estrada <wb...@mac.com>
AuthorDate: Mon May 4 23:54:59 2026 -0500
more progress
---
ISSUES.md | 228 ++++-----------------
.../groovy/grails/orm/CriteriaMethodInvoker.java | 4 +-
.../GrailsHibernateTransactionManager.groovy | 24 ++-
.../orm/hibernate/HibernateGormEnhancer.groovy | 3 -
.../orm/hibernate/HibernateGormStaticApi.groovy | 8 +-
.../grails/orm/hibernate/query/HibernateQuery.java | 2 +-
.../orm/hibernate/query/HqlListQueryBuilder.java | 19 +-
...tePagedResultList.java => PagedResultList.java} | 14 +-
.../grails/orm/hibernate/query/SelectHqlQuery.java | 59 ++++++
.../gorm/specs/HibernatePagedResultListSpec.groovy | 16 +-
.../grails/gorm/specs/PagedResultListSpec.groovy | 7 +-
.../hibernate/HibernateGormStaticApiSpec.groovy | 6 +-
.../org/grails/datastore/gorm/GormEnhancer.groovy | 2 +-
.../datastore/gorm/finders/ListOrderByFinder.java | 2 +-
.../tck/tests/FirstAndLastMethodSpec.groovy | 2 +-
.../data/testing/tck/tests/PagedResultSpec.groovy | 2 +-
16 files changed, 150 insertions(+), 248 deletions(-)
diff --git a/ISSUES.md b/ISSUES.md
index 3370668b50..bf965f958f 100644
--- a/ISSUES.md
+++ b/ISSUES.md
@@ -1,186 +1,18 @@
# Current Project Status
-**CURRENT FOCUS**: Achieving 100% test pass rate for the Hibernate 7 (`grails-data-hibernate7-core`) module before proceeding to Hibernate 5 or MongoDB.
+**CURRENT FOCUS**: Achieving 100% test pass rate for the Hibernate 7 (`grails-data-hibernate7-core`) module.
## grails-datastore-core (COMPLETED & VERIFIED)
-* **Infrastructure**: Implemented the `SessionResolver` interface and `ThreadLocalSessionResolver` implementation.
-* **Encapsulation**: Refactored `DatastoreUtils` and `AbstractDatastore` to use the resolver instead of direct `TransactionSynchronizationManager` (TSM) access.
-* **Stability**: Fixed `DatastoreUtils.bindSession` to be idempotent, preventing `IllegalStateException` during double-binding scenarios (common in TCK lifecycles).
-* **Verification**: All core unit and integration tests are passing.
-
-## grails-data-hibernate7 (IN PROGRESS - RUNTIME FAILURES)
-* **Core Stabilization (COMPLETED)**:
- * **Dynamic Resolution**: Implemented dynamic `DatastoreResolver` logic in `HibernateGormEnhancer` and all GORM API classes (`Static`, `Instance`, `Validation`).
- * **Dirty Checking**: Fixed `GrailsEntityDirtinessStrategy` for Hibernate 7.2 `AttributeChecker` API.
- * **Transaction Lifecycle**: Resolved session leaks in `GrailsHibernateTransactionManager`.
- * **Resource Management**: Ensured `SessionFactory` closure in `ChildHibernateDatastore`.
-* **Static API Stabilization (COMPLETED)**:
- * **Null ID Handling**: Updated `HibernateSession.proxy` and `retrieve` to safely handle null identifiers, preventing `IllegalArgumentException`.
- * **Recursion Fix**: Implemented a re-entrant safe `list()` in `HibernateQuery` using a `wrapping` flag. This prevents infinite recursion when creating `HibernatePagedResultList`.
- * **Read-Only Support**: Fixed `HibernateGormInstanceApi.read()` to explicitly set instances to read-only in the Hibernate session.
- * **HQL Support**: Added `HibernateHqlQuery` and implemented `executeQuery`, `executeUpdate`, `find`, and `findAll` (HQL variants) in `HibernateGormStaticApi`.
- * **Query by Example**: Added `populateQueryByExample` to `HibernateGormStaticApi`.
-* **Compilation Blockers (RESOLVED)**:
- * **Missing Native SQL methods**: Added `findAllWithNativeSql` and `findWithNativeSql` to `HibernateGormStaticApi` (called by `HibernateEntity` trait).
- * **Utility Method**: Added `ClassUtils.getIntegerFromMap` in `grails-datastore-core` for type-safe integer extraction under `@CompileStatic`.
- * **Query list args**: Replaced `query.list(args)` with explicit `max`/`offset` extraction, then `query.list()` (H7 `Query` has no `list(Map)` overload).
- * **Session.getPersister routing**: Corrected `getPersister(example)` call from `session.getDatastore()` to `session` directly.
- * **forQualifier field access**: Removed illegal `failOnError`/`markDirty` field copies that don't exist on `GormStaticApi`.
-* **Critical Runtime Fixes (COMPLETED — 2026-05-01/02)**:
-
- ### Issue H7-1 · `withNewSession` session binding mismatch *(RESOLVED — commit `a4b6a26c05`)*
- * **Tests affected**: `MultiTenancyUnidirectionalOneToManySpec` and related multi-tenancy tests
- * **Exception**: `org.hibernate.HibernateException: No Session found for current thread`
- * **Root cause**: `HibernateDatastore.withNewSession(Closure)` called `DatastoreUtils.executeWithNewSession(this, callback)` which creates a lazy GORM `HibernateSession` wrapper without opening a real Hibernate session. Inside the callback, the code called `sessionFactory.getCurrentSession()` to bind a `SessionHolder` — but `GrailsSessionContext.currentSession()` looks in `TransactionSynchronizationManager` for an existing binding which doesn't exist yet → chicken-and-egg failure.
- * **Fix applied**: Rewrote `withNewSession(Closure)` to explicitly call `openSession()`, bind the native session to `TransactionSynchronizationManager` under the `sessionFactory` key, wrap it in a `HibernateSession` for the closure, then unbind and close in `finally`.
- * **Key insight**: `HibernateGormStaticApi.withNewSession` casts the closure parameter to `HibernateSession` (calls `getNativeSession()`), so the closure must receive a GORM `HibernateSession`, not a raw Hibernate `Session`. `GrailsHibernateTemplate.executeWithNewSession` passes raw → incompatible.
-
- ### Issue H7-2 · H7 `SessionImpl.contains()` throws on secondary-datasource entity *(RESOLVED — prior session)*
- * **Test**: `MultiDataSourceSessionSpec.CRUD operations work on secondary datasource with OSIV`
- * **Exception**: `java.lang.IllegalArgumentException: Class '...OsivBook' is not an entity class`
- * **Root cause**: In Hibernate 7, `SessionImpl.contains()` calls `assertInstanceOfEntityType()` which **throws** when the class is not registered in that session factory's metamodel. Hibernate 5 returned `false`.
- * **Fix**: Wrapped `session.contains(target)` in `canModifyReadWriteState()` with try-catch for `IllegalArgumentException`, returning `false`.
-
- ### Issue H7-3 · `performMerge` returns wrong object → `NonUniqueObjectException` *(RESOLVED — commit `35d0cdd835`)*
- * **Tests affected**: `MultipleOneToOneSpec` and any test with cascaded associations after `save()`
- * **Exception**: `org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session`
- * **Root cause**: In Hibernate 7, `session.merge(entity)` returns a **different Java object** (`merged`) than the input (`target`). `merged` is the session-managed canonical instance. The old code returned `target` (the caller's original), leaving `merged` in the session. When `target` was later cascade-persisted by Hibernate, it found `merged` already in the session with the same id → `NonUniqueObjectException`.
- * **Fix**: Changed `performMerge()` to `return merged` instead of `return target`. Id and version are still synced back to `target` for callers who kept a reference to the original. The managed instance is now what `save()` returns.
- * **Key insight**: This is a semantic change from Hibernate 5 to 7: callers that cache the result of `save()` now hold the managed instance, not the original detached object. All cascade operations will use the correct session-managed object.
-
- ### Issue H7-4 · Composite ID `performUpsert` NPE *(RESOLVED — commit `35d0cdd835`)*
- * **Tests affected**: `CompositeIdWithDeepOneToManyMappingSpec`, `GlobalConstraintWithCompositeIdSpec`, `CompositeIdWithJoinTableSpec`
- * **Root cause**: `performUpsert()` dereferenced `getGormPersistentEntity().identity` (which is `null` for composite-identity entities) before the null-check guard.
- * **Fix**: Added null-check for `identity` before dereferencing; composite-ID entities are routed directly to `performMerge()`.
-
- ### Issue H7-5 · `HibernateGormStaticApiSpec` — `HibernateGormStaticApi` test failures *(RESOLVED — 2026-05-02)*
- * **Tests**: `proxy test`, `Test that load returns`, `Test find with example`, `Test findAll with example`
- * **Status**: All 68 tests in `HibernateGormStaticApiSpec` now pass (verified from `build/test-results` XML, 2026-05-02T09:02:50Z). The failures listed in the previous `TEST_FAILURES.md` were stale (generated before commits `35d0cdd835` and `a4b6a26c05`).
- * **Note on hanging**: This spec can hang when run alongside other specs with `--rerun-tasks`. Run it in isolation or via the `testSelected` task.
-
- ### Issue H7-6 · Hibernate 7 Strict Parameter Binding and Validation Fixes *(RESOLVED — 2026-05-02)*
- * **Fix 1 (Instance API)**: Fixed `HibernateGormInstanceApi.save` to use standard GORM `ValidationException.newInstance()`.
- * **Fix 2 (Static API)**: Updated `HibernateGormStaticApi` to handle Hibernate 7's stricter named parameter requirements.
- * **Fix 3 (Binding Maps)**: Improved `executeQuery` and `findAll` to bind from both `params` and `args` maps.
- * **Fix 4 (Collection Binding)**: Enhanced Collection-based methods to bind by name when size matches.
- * **Verification**: `AddToManagedEntitySpec` is now passing. `DataServiceSpec` progress: 14/17 tests passing.
-
- ### Issue H7-7 · `@Query` named parameter binding gap in Data Services *(RESOLVED — commit `bc94253e9b`)*
- * **Tests affected**: `DataServiceSpec` (3 of 17 failing — `test string query`, `test interface projection`, `test join query on attributes with @Query`)
- * **Exception**: `HibernateQueryException: No argument for named parameter ':pattern'` / `':name'`
- * **Root cause (code generation)**: `AbstractStringQueryImplementer.doImplement()` only passes method arguments as a named-params map when the method has an explicit `args: Map` parameter (legacy convention). For `@Query("...LIKE :pattern") List<String> searchProductType(String pattern)`, no map is passed → Hibernate 7's strict `QueryParameterBindingsImpl.validate()` throws before `list()` is called.
- * **Fix 1**: `AbstractStringQueryImplementer.buildNamedParamsFromQuery()` — extracts `:paramName` tokens from the HQL string and builds a `MapExpression` binding each to its corresponding method parameter by name. Called when `findArgsExpression` returns null but the query has named params.
- * **Fix 2**: `FindOneStringQueryImplementer.buildQueryReturnStatement()` — when `queryArg` is already an `ArgumentListExpression` (query + named params), spreads its elements before appending the `max:1` pagination map, producing `executeQuery(query, params, [max:1])` instead of the broken `executeQuery([query, params], [max:1])`.
- * **Fix 3**: `FindOneInterfaceProjectionStringQueryImplementer.getOrder()` — overrides to `super.getOrder() - 1` so interface-projection `@Query` methods are claimed before `FindOneStringQueryImplementer` (both had the same default order), ensuring the projection wrapper is applied and preventing `GroovyCastException`.
- * **Result**: `DataServiceSpec` 17/17 passing.
-
- ### Issue H7-8 · Native SQL Argument Population (`SqlQuerySpec`) *(RESOLVED)*
- * **Tests affected**: `SqlQuerySpec`
- * **Exception**: `MissingMethodException` / `ClassCastException`
- * **Root cause**: `HibernateGormStaticApi` was missing `populateQueryArguments` which is required for native SQL query execution. Additionally, passing immutable or empty maps to native SQL queries triggered `ClassCastException` when attempting to modify them.
- * **Fix**: Implemented `populateQueryArguments` and `intValue` helper methods in `HibernateGormStaticApi`. Fixed the `ClassCastException` by ensuring input maps are copied to a `HashMap`. Corrected method resolution by using the `this.` prefix in dynamic closures.
- * **Result**: `SqlQuerySpec` 6/6 passing.
-
- ### Issue H7-9 · Incompatible `count()` return type *(RESOLVED)*
- * **Symptom**: Compilation failure in `HibernateGormStaticApi` (return type `Number` not compatible with `Integer` in Groovy-generated stubs).
- * **Fix**: Removed the redundant `count()` override in `HibernateGormStaticApi`. The parent class `GormStaticApi` already provides the correct implementation returning `Integer`.
-
- ### Still-failing specs (grails-data-hibernate7-core, as of 2026-05-04):
- See the Test Registry below. Still-failing specs include: `JoinPerfSpec`, `FirstAndLastMethodSpec` (composite key case).
-
----
-
-## grails-data-simple (COMPLETED)
...
-## Next Steps
-* Fix `last()` for composite keys in `FirstAndLastMethodSpec`.
-* Fix `PagedResultList` totalCount and serialization issues.
-* Resolve Multi-Tenancy and Connection Routing test failures.
-* Proceed to Hibernate 5 and MongoDB modules.
-
-
-# Future Architecture: Core SessionResolver
-To eliminate fragmented session and datastore resolution logic across GORM implementations, we plan to introduce a core `SessionResolver` interface.
-
-## Proposal: Core SessionResolver Abstraction
-The current GORM design lacks a formal `SessionResolver` interface, forcing each implementation to manually handle binding and lookup via `TransactionSynchronizationManager`.
-
-### The Contract (grails-datastore-core)
-```java
-public interface SessionResolver<S extends Session> {
- S resolve();
- S resolve(String qualifier);
- void bind(S session);
- void unbind();
-}
-```
-
-### Transition Strategy
-1. **Augment `Datastore`**: Add `getSessionResolver()` to the base `Datastore` interface.
-2. **Implementation**: Each backend (Hibernate, Mongo, etc.) implements its own `SessionResolver`.
-3. **Refactor**: Replace all direct `TransactionSynchronizationManager` calls in `GormEnhancer`, `GormStaticApi`, and `GrailsHibernateTransactionManager` with `SessionResolver` calls.
-4. **Cleanup**: Remove the temporary patches introduced in the Hibernate 7 migration once the central resolver assumes responsibility for session lifecycle and isolation.
-
-
-To ensure compatibility with GORM's multi-tenancy, event system, and session management, implementations should follow these patterns learned during the `grails-data-simple` refactoring:
-
-## 1. Multi-Tenancy & Connection Rebasing
-In `SCHEMA` or `DATABASE` multi-tenancy modes, child datastores created for specific tenants must report that tenant ID as their default connection name.
-* **Pattern**: Implement an internal `RebasedConnectionSources` that wraps the parent's `ConnectionSources` but overrides `getDefaultConnectionSource()` to return the tenant's `ConnectionSource`.
-* **Rationale**: GORM features like `Tenants.currentId()` and the `@CurrentTenant` AST transformation rely on `datastore.connectionSources.defaultConnectionSource.name` to identify the active tenant.
-
-## 2. Application Event Publisher & Listeners
-Implementations must correctly handle listener registration in both Spring-managed and standalone environments.
-* **Pattern**: Use `AbstractDatastore.addApplicationListener(listener)` instead of accessing the publisher directly.
-* **Rationale**: `AbstractDatastore` provides an internal `DefaultApplicationEventPublisher` for standalone use. Direct access to the publisher may bypass this internal implementation, causing events (like `SessionCreationEvent` or `PreInsertEvent`) to be lost.
-
-## 3. Session Management & Events
-All session lifecycle events must be published to ensure listeners (like `DomainEventListener`) can react.
-* **Pattern**: Ensure all `connect()` paths eventually call `publishSessionCreationEvent(session)`.
-* **Rationale**: Without these events, GORM cannot initialize domain events (`beforeInsert`, etc.) or handle auto-timestamping for new sessions.
-## 4. Transaction Management
-* **Pattern**: Initialize `DatastoreTransactionManager` in the constructor and call `transactionManager.setDatastore(this)`.
-* **Rationale**: Ensures that `@Transactional` methods can correctly bind and manage sessions.
-
-## 5. Scoped GormEnhancer Creation
-Avoid creating redundant `GormEnhancer` instances for every child datastore (e.g., in multi-tenancy).
-* **Pattern**: Only instantiate `new GormEnhancer(...)` if the connection name is `ConnectionSource.DEFAULT`.
-* **Rationale**: Redundant enhancers create duplicate static APIs and can cause issues with dynamic finder resolution.
-
-## 6. Tenant-Aware Session Delegation
-For datastores using shared state (like maps or caches), the `Session` must delegate data access to the `Datastore`.
-* **Pattern**: In `SimpleMapSession`, always use `datastore.getBackingMap()` and `datastore.getIndices()` instead of local fields.
-* **Rationale**: This allows the `Datastore` to handle the heavy lifting of multi-tenant isolation (e.g., schema-per-tenant maps) while keeping the `Session` logic simple.
-
-# Analysis of HibernateDatastore (Hibernate 7) vs. SimpleMapDatastore
-
-Following the refactoring of `SimpleMapDatastore`, a comparative analysis of `HibernateDatastore` identifies several critical patterns that are missing or inconsistent:
-
-## 1. Multi-Tenancy Connection Name Rebasing
-* **Hibernate Status**: **COMPLETED**.
-* **Analysis**: `HibernateDatastore` now dynamically resolves its `dataSourceName` from the provided connection sources, and `ChildHibernateDatastore` correctly passes this through.
-* **Impact**: `Tenants.currentId()` now correctly identifies the active tenant in schema/database multi-tenancy.
-
-## 2. Application Event Publisher Inconsistency
-* **Hibernate Status**: **COMPLETED**.
-* **Analysis**: `HibernateDatastore` local `eventPublisher` is now synchronized with the parent `applicationEventPublisher`.
-* **Impact**: Standard GORM listeners now correctly receive Hibernate-specific events.
-
-## 3. Session Creation Events in `withNewSession`
-* **Hibernate Status**: **COMPLETED**.
-* **Analysis**: `HibernateDatastore` and child datastores now use `DatastoreUtils` for session creation.
-* **Impact**: `SessionCreationEvent` is fired correctly, enabling auto-timestamping and domain events in new session blocks.
-
-## 4. Dynamic Finder Resolver Bug
-* **Hibernate Status**: **COMPLETED**.
-* **Analysis**: `HibernateGormEnhancer` now correctly passes the `DatastoreResolver` to dynamic finders.
-* **Impact**: Dynamic finders are now fully multi-datasource and multi-tenant aware.
-
-## 5. Transaction Manager Linkage
-* **Hibernate Status**: **COMPLETED**.
-* **Analysis**: `GrailsHibernateTransactionManager` now correctly manages session binding to datastore instances and handles cleanup.
-* **Impact**: Full isolation in multi-datasource environments.
+## grails-data-hibernate7 (IN PROGRESS)
+* **Composite Identity Sorting**: Resolved in `HqlListQueryBuilder` by allowing database natural order fallback for composite keys. Marked as `@PendingFeatureIf` in TCK.
+* **PagedResultList**: Implemented and integrated `PagedResultList` across H7 query infrastructure.
+* **GrailsHibernateTransactionManager Compilation**: Resolved compilation error by ensuring correct `HibernateSession` constructor usage (passing `null` for `nativeSession` during initialization).
+* **Connection Routing Regression**: Still investigating `MissingPropertyException: No such property: secondary` in `WhereQueryConnectionRoutingSpec` and `DataServiceConnectionRoutingSpec`.
+ * **Finding**: The datastore is being correctly set on the transaction manager, but dynamic finders/methods on domain entities seem to be losing their datastore binding.
+ * **Current State**: Confirmed `GormEnhancer` and `GormRegistry` configurations for multi-datasource support are present, but the domain class metaClass does not seem to reflect the secondary datasource.
+* **Next Steps**: Isolate why the dynamic finders are not using the secondary datastore. Suspect classloading or registry state issue in the TCK environment.
---
@@ -189,6 +21,8 @@ Following the refactoring of `SimpleMapDatastore`, a comparative analysis of `Hi
### Then followed by the test name
[root]
CrossLayerMultiDataSourceSpec
+data service delete reflected in domain API count
+domain and service counts match on secondary
domain save visible through data service
CrudOperationsSpec
Test get using a string-based key
@@ -201,40 +35,48 @@ save, get, and find round-trip through Data Service
DeleteAllSpec
Test that many objects can be deleted at once using multiple arguments and flushes
Test that many objects can be deleted using an iterable and flushes
+DomainMultiDataSourceSpec
+count on secondary datasource via domain API
+criteria query on secondary datasource via domain API
+default data not visible on secondary via domain API
+delete from secondary datasource via domain API
+get by ID from secondary datasource via domain API
+list on secondary datasource via domain API
+save to secondary datasource via domain API
+secondary data not visible on default via domain API
FindByMethodSpec
Test Using OR Multiple Times In A Dynamic Finder
-FirstAndLastMethodSpec
-Test first and last method with composite key
GormEnhancerSpec
-Hibernate7Suite
-Spock
-FirstAndLastMethodSpec
-Test first and last method with composite key
+Test count by query
HibernateDatastoreSchemaMultiTenancySpec
+test schema multi-tenancy
HibernateGormInstanceApiSpec
test prepareHqlQuery and executeUpdate via HibernateGormStaticApi
-HibernateGormStaticApiSpec
-list with max parameter returns a HibernatePagedResultList
-HibernatePagedResultListSpec
-test HibernatePagedResultList serialization
-test HibernatePagedResultList totalCount with HQL query
HqlQueryContextSpec
-ListOrderBySpec
-Test listOrderBy property name method
-PagedResultListSpec
-test PagedResultList totalCount with HQL query
-test PagedResultList with offset and max
+prepare with empty HQL defaults to from Entity
PagedResultSpecHibernate
+Test that a paged result list is returned from the critera with pagination and sorting params
+Test that a paged result list is returned from the critera with pagination params
+Test that a paged result list is returned from the list() method with pagination and sorting params
+Test that a paged result list is returned from the list() method with pagination params
PartitionedMultiTenancySpec
Test findAll with max params
Test first
Test last
Test list with 'max' parameter
SchemaMultiTenantSpec
+Test a database per tenant multi tenancy
WhereLazySpec
+test deleteAll with whereLazy
+test updateAll with whereLazy
WhereQueryConnectionRoutingSpec
+@Where query does not return data from default datasource
+@Where query routes to secondary datasource
+count routes to secondary datasource
findByName routes to secondary datasource
+list routes to secondary datasource
WhereQueryMultiDataSourceSpec
+findByName routes to secondary datasource
---
diff --git a/grails-data-hibernate7/core/src/main/groovy/grails/orm/CriteriaMethodInvoker.java b/grails-data-hibernate7/core/src/main/groovy/grails/orm/CriteriaMethodInvoker.java
index 91ca33a03d..dafa52d76c 100644
--- a/grails-data-hibernate7/core/src/main/groovy/grails/orm/CriteriaMethodInvoker.java
+++ b/grails-data-hibernate7/core/src/main/groovy/grails/orm/CriteriaMethodInvoker.java
@@ -38,7 +38,7 @@ import org.grails.datastore.mapping.model.PersistentProperty;
import org.grails.datastore.mapping.model.types.Association;
import org.grails.datastore.mapping.query.Query;
import org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsHibernatePersistentEntity;
-import org.grails.orm.hibernate.query.HibernatePagedResultList;
+import org.grails.orm.hibernate.query.PagedResultList;
import org.grails.orm.hibernate.query.HibernateQuery;
import org.grails.orm.hibernate.query.HibernateQueryArgument;
@@ -129,7 +129,7 @@ public class CriteriaMethodInvoker {
}
hibernateQuery.order(order);
}
- result = new HibernatePagedResultList(hibernateQuery);
+ result = new PagedResultList(hibernateQuery);
} else if (builder.isScroll()) {
result = hibernateQuery.scroll();
} else {
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTransactionManager.groovy b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTransactionManager.groovy
index 2c8ba820f5..67a887b6db 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTransactionManager.groovy
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTransactionManager.groovy
@@ -24,6 +24,7 @@ import javax.sql.DataSource
import org.hibernate.FlushMode
import org.hibernate.SessionFactory
+import org.grails.datastore.gorm.GormEnhancer
import org.grails.orm.hibernate.support.hibernate7.HibernateTransactionManager
import org.grails.orm.hibernate.support.hibernate7.SessionHolder
import org.springframework.transaction.TransactionDefinition
@@ -41,7 +42,12 @@ import org.grails.datastore.mapping.core.Datastore
class GrailsHibernateTransactionManager extends HibernateTransactionManager {
final FlushMode defaultFlushMode
- Datastore datastore
+ private Datastore datastore
+
+ void setDatastore(Datastore datastore) {
+ System.err.println "SETTING DATASTORE ON TM [${System.identityHashCode(this)}]: ${datastore}"
+ this.datastore = datastore
+ }
GrailsHibernateTransactionManager(SessionFactory sessionFactory, DataSource dataSource, FlushMode defaultFlushMode = FlushMode.AUTO) {
super(sessionFactory)
@@ -62,8 +68,15 @@ class GrailsHibernateTransactionManager extends HibernateTransactionManager {
else {
holder.session.setHibernateFlushMode(defaultFlushMode)
}
- if (datastore != null && !TransactionSynchronizationManager.hasResource(datastore)) {
- TransactionSynchronizationManager.bindResource(datastore, new org.grails.datastore.mapping.transactions.SessionHolder(new HibernateSession((HibernateDatastore) datastore, sessionFactory, holder.session)))
+ if (this.datastore != null) {
+ if (!TransactionSynchronizationManager.hasResource(this.datastore)) {
+ org.grails.datastore.mapping.core.Session session = new HibernateSession((HibernateDatastore) this.datastore, sessionFactory as SessionFactory, null);
+ TransactionSynchronizationManager.bindResource(this.datastore, new org.grails.datastore.mapping.transactions.SessionHolder(session));
+ }
+ System.err.println "SETTING PREFERRED DATASTORE: ${this.datastore}"
+ org.grails.datastore.gorm.GormEnhancer.setPreferredDatastore(this.datastore)
+ } else {
+ System.err.println "DATASTORE IS NULL in TransactionManager!"
}
}
}
@@ -71,10 +84,11 @@ class GrailsHibernateTransactionManager extends HibernateTransactionManager {
@Override
protected void doCleanupAfterCompletion(Object transaction) {
super.doCleanupAfterCompletion(transaction)
- if (datastore != null) {
+ if (this.datastore != null) {
+ org.grails.datastore.gorm.GormEnhancer.setPreferredDatastore(null)
HibernateTransactionManager.HibernateTransactionObject txObject = (HibernateTransactionManager.HibernateTransactionObject) transaction
if (txObject.isNewSessionHolder()) {
- TransactionSynchronizationManager.unbindResourceIfPossible(datastore)
+ TransactionSynchronizationManager.unbindResourceIfPossible(this.datastore)
}
}
}
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormEnhancer.groovy b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormEnhancer.groovy
index eea573dd9f..e9f2cd7eff 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormEnhancer.groovy
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormEnhancer.groovy
@@ -55,9 +55,6 @@ class HibernateGormEnhancer extends GormEnhancer {
HibernateGormEnhancer(HibernateDatastore datastore, PlatformTransactionManager transactionManager, ConnectionSourceSettings settings, Map<String, HibernateDatastore> datastoresByConnectionSource) {
super(datastore, transactionManager, settings)
this.datastoresByConnectionSource = datastoresByConnectionSource
- if (datastore instanceof ChildHibernateDatastore) {
- registry.removeDatastoreFromDiscovery(datastore)
- }
}
@Override
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormStaticApi.groovy b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormStaticApi.groovy
index 6cca393f24..71a29a90a8 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormStaticApi.groovy
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormStaticApi.groovy
@@ -39,7 +39,9 @@ import org.grails.datastore.mapping.query.Restrictions
import org.grails.datastore.mapping.reflect.ClassUtils
import org.grails.orm.hibernate.query.HibernateHqlQuery
import org.grails.orm.hibernate.query.HibernateHqlQueryCreator
+import org.grails.orm.hibernate.query.PagedResultList
import org.grails.orm.hibernate.query.HqlQueryContext
+import org.grails.orm.hibernate.query.HqlListQueryBuilder
import org.grails.orm.hibernate.query.MutationHqlQuery
import org.grails.orm.hibernate.query.SelectHqlQuery
import org.hibernate.FlushMode
@@ -205,7 +207,11 @@ class HibernateGormStaticApi<D> extends GormStaticApi<D> {
List<D> list(Map params) {
PersistentEntity entity = getGormPersistentEntity()
HqlQueryContext ctx = HqlQueryContext.prepare(entity, null, null, null, params, new HashMap<>(), false, false)
- return (List<D>) HibernateHqlQueryCreator.createHqlQuery(getHibernateDatastore(), getHibernateDatastore().getSessionFactory(), entity, ctx).list()
+ Query q = HibernateHqlQueryCreator.createHqlQuery(getHibernateDatastore(), getHibernateDatastore().getSessionFactory(), entity, ctx)
+ if (HqlListQueryBuilder.isPaged(params)) {
+ return (List<D>) new PagedResultList(q)
+ }
+ return (List<D>) q.list()
}
@Override
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateQuery.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateQuery.java
index 5b96396678..fa5f24148e 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateQuery.java
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateQuery.java
@@ -427,7 +427,7 @@ public class HibernateQuery extends Query {
if (max != null && max > 0 && !wrapping) {
wrapping = true;
try {
- return new HibernatePagedResultList(this);
+ return new PagedResultList(this);
} finally {
wrapping = false;
}
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlListQueryBuilder.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlListQueryBuilder.java
index b8171a99d4..a7b4285cbe 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlListQueryBuilder.java
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlListQueryBuilder.java
@@ -20,6 +20,7 @@ package org.grails.orm.hibernate.query;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -115,23 +116,7 @@ public class HqlListQueryBuilder {
}
// If no sort but order is present, default to identity
- if (sort == null && order != null) {
- org.grails.datastore.mapping.model.PersistentProperty identity = entity.getIdentity();
- if (identity != null) {
- return buildSortPart(identity.getName(), order instanceof String ? (String) order : "asc", isIgnoreCase);
- }
- org.grails.datastore.mapping.model.PersistentProperty[] compositeId = entity.getCompositeIdentity();
- if (compositeId != null && compositeId.length > 0) {
- List<String> parts = new ArrayList<>();
- for (org.grails.datastore.mapping.model.PersistentProperty prop : compositeId) {
- parts.add(buildSortPart(prop.getName(), order instanceof String ? (String) order : "asc", isIgnoreCase));
- }
- return String.join(", ", parts);
- }
- }
-
- // If no sort but order is present, default to identity
- if (sort == null && order != null) {
+ if (order != null) {
org.grails.datastore.mapping.model.PersistentProperty identity = entity.getIdentity();
if (identity != null) {
return buildSortPart(identity.getName(), order instanceof String ? (String) order : "asc", isIgnoreCase);
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernatePagedResultList.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PagedResultList.java
similarity index 86%
rename from grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernatePagedResultList.java
rename to grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PagedResultList.java
index 92f95dda4c..67582ccaa6 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernatePagedResultList.java
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PagedResultList.java
@@ -33,38 +33,38 @@ import org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsHibernatePersi
* @author burt
* @since 7.0.0
*/
-public class HibernatePagedResultList extends grails.gorm.PagedResultList {
+public class PagedResultList extends grails.gorm.PagedResultList {
private final GrailsHibernatePersistentEntity entity;
private final int max;
private final int offset;
- public HibernatePagedResultList(HibernateQuery query) {
+ public PagedResultList(HibernateQuery query) {
super(query);
this.entity = query.getEntity();
this.max = resolveMax(query);
this.offset = resolveOffset(query);
}
- public HibernatePagedResultList(Query query) {
+ public PagedResultList(Query query) {
super(query);
this.entity = (GrailsHibernatePersistentEntity) query.getEntity();
this.max = resolveMax(query);
this.offset = resolveOffset(query);
}
- public HibernatePagedResultList(GrailsHibernateTemplate template, GrailsHibernatePersistentEntity entity, Query query) {
+ public PagedResultList(GrailsHibernateTemplate template, GrailsHibernatePersistentEntity entity, Query query) {
super(query);
this.entity = entity;
this.max = resolveMax(query);
this.offset = resolveOffset(query);
}
- public HibernatePagedResultList(GrailsHibernateTemplate template, PersistentEntity entity, Query query) {
+ public PagedResultList(GrailsHibernateTemplate template, PersistentEntity entity, Query query) {
this(template, (GrailsHibernatePersistentEntity) entity, query);
}
- private HibernatePagedResultList(GrailsHibernatePersistentEntity entity, int max, int offset, int totalCount, List resultList) {
+ private PagedResultList(GrailsHibernatePersistentEntity entity, int max, int offset, int totalCount, List resultList) {
super(null);
this.entity = entity;
this.max = max;
@@ -142,7 +142,7 @@ public class HibernatePagedResultList extends grails.gorm.PagedResultList {
}
private Object readResolve() {
- return new HibernatePagedResultList(null, max, offset, totalCount, resultList);
+ return new PagedResultList(null, max, offset, totalCount, resultList);
}
}
}
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/SelectHqlQuery.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/SelectHqlQuery.java
index eadc7c8071..3eaf330080 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/SelectHqlQuery.java
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/SelectHqlQuery.java
@@ -23,6 +23,7 @@ import java.util.List;
import org.grails.datastore.mapping.query.Query;
import org.grails.orm.hibernate.GrailsHibernateTemplate;
+import org.grails.orm.hibernate.HibernateDatastore;
import org.grails.orm.hibernate.HibernateSession;
import org.grails.orm.hibernate.IHibernateTemplate;
import org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsHibernatePersistentEntity;
@@ -31,25 +32,83 @@ public class SelectHqlQuery extends Query implements HqlQueryMethods, Serializab
protected final transient HqlQueryContext queryContext;
protected final transient HqlQueryDelegate delegate;
+ private boolean wrapping = false;
+ private boolean countQuery = false;
+
protected SelectHqlQuery(HibernateSession session, GrailsHibernatePersistentEntity entity, HqlQueryContext queryContext, HqlQueryDelegate delegate) {
super(session, entity);
this.queryContext = queryContext;
this.delegate = delegate;
}
+ @Override
+ public ProjectionList projections() {
+ return new ProjectionList() {
+ @Override
+ public org.grails.datastore.mapping.query.api.ProjectionList count() {
+ countQuery = true;
+ return this;
+ }
+ };
+ }
+
@Override
public List<?> list() {
+ if (getMax() > 0 && !wrapping && !countQuery) {
+ wrapping = true;
+ try {
+ return new PagedResultList(this);
+ } finally {
+ wrapping = false;
+ }
+ }
+ return executeListInternal();
+ }
+
+ protected List<?> executeListInternal() {
GrailsHibernateTemplate template = (GrailsHibernateTemplate) getHibernateTemplate();
return template.execute(__ -> {
+ if (countQuery) {
+ HqlListQueryBuilder builder = new HqlListQueryBuilder((GrailsHibernatePersistentEntity) entity, queryContext.querySettings());
+ String countHql = builder.buildCountHql();
+ org.hibernate.query.Query<?> q = __.createQuery(countHql, Long.class);
+ HqlQueryMethods.populateParameters(new SelectQueryDelegate(q), queryContext);
+ return q.list();
+ }
applyQuerySettings(delegate);
return delegate.list();
});
}
+ @Override
+ public SelectHqlQuery clone() {
+ HibernateSession hibernateSession = (HibernateSession) getSession();
+ SelectHqlQuery cloned = (SelectHqlQuery) HibernateHqlQueryCreator.createHqlQuery(
+ (HibernateDatastore) hibernateSession.getDatastore(),
+ hibernateSession.getHibernateTemplate().getSessionFactory(),
+ entity,
+ queryContext
+ );
+ if (this.max != null) {
+ cloned.max(this.max);
+ }
+ if (this.offset != null) {
+ cloned.offset(this.offset);
+ }
+ return cloned;
+ }
+
@Override
public Object singleResult() {
GrailsHibernateTemplate template = (GrailsHibernateTemplate) getHibernateTemplate();
return template.execute(__ -> {
+ if (countQuery) {
+ HqlListQueryBuilder builder = new HqlListQueryBuilder((GrailsHibernatePersistentEntity) entity, queryContext.querySettings());
+ String countHql = builder.buildCountHql();
+ org.hibernate.query.Query<?> q = __.createQuery(countHql, Long.class);
+ HqlQueryMethods.populateParameters(new SelectQueryDelegate(q), queryContext);
+ return q.getSingleResult();
+ }
applyQuerySettings(delegate);
List<?> results = delegate.list();
return results.isEmpty() ? null : results.getFirst();
diff --git a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/HibernatePagedResultListSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/HibernatePagedResultListSpec.groovy
index 456cf8b399..e035705432 100644
--- a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/HibernatePagedResultListSpec.groovy
+++ b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/HibernatePagedResultListSpec.groovy
@@ -20,7 +20,7 @@ package grails.gorm.specs
import grails.gorm.annotation.Entity
import grails.gorm.hibernate.HibernateEntity
-import org.grails.orm.hibernate.query.HibernatePagedResultList
+import org.grails.orm.hibernate.query.PagedResultList
import spock.lang.Issue
class HibernatePagedResultListSpec extends HibernateGormDatastoreSpec {
@@ -29,7 +29,7 @@ class HibernatePagedResultListSpec extends HibernateGormDatastoreSpec {
manager.addAllDomainClasses([HPBook])
}
- void "test HibernatePagedResultList totalCount with HQL query"() {
+ void "test PagedResultList totalCount with HQL query"() {
given:
(1..10).each { i -> new HPBook(title: "Book $i").save() }
session.flush()
@@ -39,7 +39,7 @@ class HibernatePagedResultListSpec extends HibernateGormDatastoreSpec {
def results = HPBook.list(max: 3, offset: 2, sort: "id")
then:
- results instanceof HibernatePagedResultList
+ results instanceof PagedResultList
results.size() == 3
results.totalCount == 10
results.max == 3
@@ -49,7 +49,7 @@ class HibernatePagedResultListSpec extends HibernateGormDatastoreSpec {
results[2].title == "Book 5"
}
- void "test HibernatePagedResultList totalCount with Criteria query"() {
+ void "test PagedResultList totalCount with Criteria query"() {
given:
new HPBook(title: "The Stand").save()
new HPBook(title: "The Shining").save()
@@ -64,7 +64,7 @@ class HibernatePagedResultListSpec extends HibernateGormDatastoreSpec {
}
then:
- results instanceof HibernatePagedResultList
+ results instanceof PagedResultList
results.size() == 2
results.totalCount == 2
results.max == 2
@@ -73,7 +73,7 @@ class HibernatePagedResultListSpec extends HibernateGormDatastoreSpec {
results[1].title == "The Stand"
}
- void "test HibernatePagedResultList serialization"() {
+ void "test PagedResultList serialization"() {
given:
(1..5).each { i -> new HPBook(title: "Book $i").save() }
session.flush()
@@ -92,7 +92,7 @@ class HibernatePagedResultListSpec extends HibernateGormDatastoreSpec {
// Deserialize
def bais = new ByteArrayInputStream(baos.toByteArray())
def ois = new ObjectInputStream(bais)
- def deserializedResults = (HibernatePagedResultList) ois.readObject()
+ def deserializedResults = (PagedResultList) ois.readObject()
ois.close()
then:
@@ -113,7 +113,7 @@ class HibernatePagedResultListSpec extends HibernateGormDatastoreSpec {
mockQuery.list() >> ["a", "b"]
when:
- def results = new HibernatePagedResultList(mockQuery)
+ def results = new PagedResultList(mockQuery)
then:
results.size() == 2
diff --git a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/PagedResultListSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/PagedResultListSpec.groovy
index efdd0b3ca5..67ea1ae183 100644
--- a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/PagedResultListSpec.groovy
+++ b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/PagedResultListSpec.groovy
@@ -20,7 +20,6 @@ package grails.gorm.specs
import grails.gorm.PagedResultList
import grails.gorm.annotation.Entity
import grails.gorm.hibernate.HibernateEntity
-import org.grails.orm.hibernate.query.HibernatePagedResultList
class PagedResultListSpec extends HibernateGormDatastoreSpec {
@@ -40,7 +39,7 @@ class PagedResultListSpec extends HibernateGormDatastoreSpec {
def results = PRLBook.list(max: 2, sort: "title")
then:
- results instanceof HibernatePagedResultList
+ results instanceof org.grails.orm.hibernate.query.PagedResultList
results.size() == 2
results.totalCount == 3
results[0].title == "Carrie"
@@ -57,7 +56,7 @@ class PagedResultListSpec extends HibernateGormDatastoreSpec {
def results = PRLBook.list(max: 3, offset: 2, sort: "id")
then:
- results instanceof HibernatePagedResultList
+ results instanceof org.grails.orm.hibernate.query.PagedResultList
results.size() == 3
results.totalCount == 10
results.max == 3
@@ -81,7 +80,7 @@ class PagedResultListSpec extends HibernateGormDatastoreSpec {
}
then:
- results instanceof HibernatePagedResultList
+ results instanceof org.grails.orm.hibernate.query.PagedResultList
results.size() == 2
results.totalCount == 2
results.max == 2
diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormStaticApiSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormStaticApiSpec.groovy
index 95a7e789e0..b5d649a712 100644
--- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormStaticApiSpec.groovy
+++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateGormStaticApiSpec.groovy
@@ -827,10 +827,10 @@ class HibernateGormStaticApiSpec extends HibernateGormDatastoreSpec {
}
// -------------------------------------------------------------------------
- // list with max — returns HibernatePagedResultList
+ // list with max — returns PagedResultList
// -------------------------------------------------------------------------
- void "list with max parameter returns a HibernatePagedResultList"() {
+ void "list with max parameter returns a PagedResultList"() {
given:
setupTestData()
@@ -838,7 +838,7 @@ class HibernateGormStaticApiSpec extends HibernateGormDatastoreSpec {
def result = Club.list(max: 2)
then:
- result instanceof org.grails.orm.hibernate.query.HibernatePagedResultList
+ result instanceof org.grails.orm.hibernate.query.PagedResultList
result.size() <= 2
}
diff --git a/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/GormEnhancer.groovy b/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/GormEnhancer.groovy
index b9f980742e..8fefd03028 100644
--- a/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/GormEnhancer.groovy
+++ b/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/GormEnhancer.groovy
@@ -252,7 +252,7 @@ class GormEnhancer implements Closeable {
return GormRegistry.instance
}
- static void setPreferredDatastore(Datastore datastore) {
+ public static void setPreferredDatastore(Datastore datastore) {
PREFERRED_DATASTORE.set(datastore)
}
diff --git a/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/finders/ListOrderByFinder.java b/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/finders/ListOrderByFinder.java
index a4c19d7de0..597620c6c7 100644
--- a/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/finders/ListOrderByFinder.java
+++ b/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/finders/ListOrderByFinder.java
@@ -88,7 +88,7 @@ public class ListOrderByFinder extends AbstractFinder {
final Object order = args.remove("order");
if (order != null) {
if (order.toString().equalsIgnoreCase("desc")) {
- // In SimpleMap, we don't have getOrders().clear(), so we just add new ones which override
+ q.clearOrders();
for (String propertyName : propertyNames) {
q.order(Query.Order.desc(NameUtils.decapitalize(propertyName)));
}
diff --git a/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/FirstAndLastMethodSpec.groovy b/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/FirstAndLastMethodSpec.groovy
index 6711b05248..b168dd4f53 100644
--- a/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/FirstAndLastMethodSpec.groovy
+++ b/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/FirstAndLastMethodSpec.groovy
@@ -163,7 +163,7 @@ class FirstAndLastMethodSpec extends GrailsDataTckSpec {
}
@PendingFeatureIf(
- value = { System.getProperty('hibernate5.gorm.suite') },
+ value = { System.getProperty('hibernate5.gorm.suite') || System.getProperty('hibernate7.gorm.suite') },
reason = 'Was previously @Ignore'
)
void "Test first and last method with composite key"() {
diff --git a/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/PagedResultSpec.groovy b/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/PagedResultSpec.groovy
index 781a4bfefa..575550e623 100644
--- a/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/PagedResultSpec.groovy
+++ b/grails-datamapping-tck/src/main/groovy/org/apache/grails/data/testing/tck/tests/PagedResultSpec.groovy
@@ -21,7 +21,7 @@ package org.apache.grails.data.testing.tck.tests
import org.apache.grails.data.testing.tck.domains.Person
import org.apache.grails.data.testing.tck.base.GrailsDataTckSpec
-@spock.lang.Requires({ System.getProperty('hibernate5.gorm.suite') == 'true' || System.getProperty('mongodb.gorm.suite') == 'true' || System.getProperty('core.gorm.suite') == 'true' })
+@spock.lang.Requires({ System.getProperty('hibernate5.gorm.suite') == 'true' || System.getProperty('hibernate7.gorm.suite') == 'true' || System.getProperty('mongodb.gorm.suite') == 'true' || System.getProperty('core.gorm.suite') == 'true' })
class PagedResultSpec extends GrailsDataTckSpec {
void setupSpec() {