This is an automated email from the ASF dual-hosted git repository.

borinquenkid pushed a commit to branch 8.0.x-hibernate7-dev
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit 1447a0b4dc0ef669b9477453c1fb2e42e065561c
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Mon Mar 23 09:40:55 2026 -0500

    hibernate 7:
      * Solidify PagedResultList
---
 .../orm/hibernate/HibernateGormStaticApi.groovy    |  4 +-
 .../proxy/ByteBuddyGroovyInterceptor.java          | 12 +--
 .../orm/hibernate/query/HibernateHqlQuery.java     | 31 ++++---
 .../orm/hibernate/query/HqlQueryContext.java       | 31 ++++---
 .../orm/hibernate/query/PagedResultList.java       |  2 +-
 .../grails/gorm/specs/PagedResultListSpec.groovy   | 97 ++++++++++++++++++++++
 .../main/groovy/grails/gorm/PagedResultList.java   | 18 ++++
 .../org/grails/datastore/mapping/query/Query.java  | 14 ++++
 8 files changed, 174 insertions(+), 35 deletions(-)

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 4be8cf0e90..dc9ee4c078 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
@@ -391,7 +391,7 @@ class HibernateGormStaticApi<D> extends GormStaticApi<D> {
 
     @SuppressWarnings('GroovyAssignabilityCheck')
     private HibernateHqlQuery prepareHqlQuery(CharSequence hql, boolean 
isNative, boolean isUpdate,
-                                              Map namedParams, Collection 
positionalParams, Map querySettings) {
+                                              Map<String,Object> namedParams, 
Collection<Object> positionalParams, Map<String,Object> querySettings) {
         def ctx = HqlQueryContext.prepare(persistentEntity, hql, namedParams, 
positionalParams, querySettings, isNative, isUpdate)
         return HibernateHqlQuery.createHqlQuery(
                 (HibernateDatastore) datastore,
@@ -441,7 +441,7 @@ class HibernateGormStaticApi<D> extends GormStaticApi<D> {
                 sessionFactory,
                 persistentEntity,
                 ctx,
-                getHibernateTemplate(),
+                getHibernateTemplate(),Ï
                 datastore.mappingContext.conversionService
         )
         if (params.containsKey('max')) {
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/proxy/ByteBuddyGroovyInterceptor.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/proxy/ByteBuddyGroovyInterceptor.java
index 27c9d561aa..7802b054e5 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/proxy/ByteBuddyGroovyInterceptor.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/proxy/ByteBuddyGroovyInterceptor.java
@@ -63,8 +63,7 @@ public class ByteBuddyGroovyInterceptor extends 
ByteBuddyInterceptor {
     @Override
     public Object intercept(Object proxy, Method method, Object[] args) throws 
Throwable {
         String methodName = method.getName();
-        System.out.println("Intercepting method: " + methodName + " on proxy: 
" + getEntityName() + ":"
-                + getIdentifier() + " (Uninitialized: " + isUninitialized() + 
")");
+
 
         // Check these BEFORE calling this.invoke() to avoid premature 
initialization in Hibernate 7
         if ((getIdentifierMethod != null && 
methodName.equals(getIdentifierMethod.getName()))
@@ -79,27 +78,22 @@ public class ByteBuddyGroovyInterceptor extends 
ByteBuddyInterceptor {
                     getEntityName(), getPersistentClass(), getIdentifier());
             Object result = 
GroovyProxyInterceptorLogic.handleUninitialized(state, methodName, args);
             if (result != GroovyProxyInterceptorLogic.INVOKE_IMPLEMENTATION) {
-                System.out.println("Handled uninitialized access for: " + 
methodName);
                 return result;
             }
         }
 
-        System.out.println("Delegating to Hibernate invoke for: " + 
methodName);
         final Object result = this.invoke(method, args, proxy);
         if (result != INVOKE_IMPLEMENTATION) {
             return result;
         }
 
         if (GroovyProxyInterceptorLogic.isGroovyMethod(methodName)) {
-            System.out.println("Handling Groovy method: " + methodName);
             final Object target = getImplementation();
             try {
-                if (isPublic(getPersistentClass(), method)) {
-                    return method.invoke(target, args);
-                } else {
+                if (!isPublic(getPersistentClass(), method)) {
                     method.setAccessible(true);
-                    return method.invoke(target, args);
                 }
+                return method.invoke(target, args);
             } catch (InvocationTargetException ite) {
                 throw ite.getTargetException();
             }
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateHqlQuery.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateHqlQuery.java
index 3683801770..9c29a7ba3d 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateHqlQuery.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateHqlQuery.java
@@ -186,9 +186,16 @@ public class HibernateHqlQuery extends Query {
     }
 
     protected void populateQuerySettings(Map<?, ?> args, ConversionService 
conversionService) {
-        ifPresent(args, HibernateQueryArgument.MAX.value(), v -> 
delegate.setMaxResults(toInt(v, conversionService)));
-        ifPresent(
-                args, HibernateQueryArgument.OFFSET.value(), v -> 
delegate.setFirstResult(toInt(v, conversionService)));
+        ifPresent(args, HibernateQueryArgument.MAX.value(), v -> {
+            int max = toInt(v, conversionService);
+            delegate.setMaxResults(max);
+            max(max);
+        });
+        ifPresent(args, HibernateQueryArgument.OFFSET.value(), v -> {
+            int offset = toInt(v, conversionService);
+            delegate.setFirstResult(offset);
+            offset(offset);
+        });
         ifPresent(args, HibernateQueryArgument.CACHE.value(), v -> 
delegate.setCacheable(toBool(v)));
         ifPresent(
                 args,
@@ -243,14 +250,7 @@ public class HibernateHqlQuery extends Query {
                 throw new GrailsQueryException("Named parameter's name must be 
a String: " + namedArgs);
             }
             String name = key.toString();
-            if (HibernateQueryArgument.MAX.value().equals(name)
-                    || HibernateQueryArgument.OFFSET.value().equals(name)
-                    || HibernateQueryArgument.CACHE.value().equals(name)
-                    || HibernateQueryArgument.FETCH_SIZE.value().equals(name)
-                    || HibernateQueryArgument.TIMEOUT.value().equals(name)
-                    || HibernateQueryArgument.READ_ONLY.value().equals(name)
-                    || HibernateQueryArgument.FLUSH_MODE.value().equals(name)
-                    || HibernateQueryArgument.LOCK.value().equals(name)) {
+            if (isGormArgument(name)) {
                 return;
             }
             if (value == null) {
@@ -267,6 +267,15 @@ public class HibernateHqlQuery extends Query {
         });
     }
 
+    private static boolean isGormArgument(String name) {
+        for (HibernateQueryArgument arg : HibernateQueryArgument.values()) {
+            if (arg.value().equals(name)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     protected void populateQueryWithIndexedArguments(List<?> params) {
         if (params == null) return;
         for (int i = 0; i < params.size(); i++) {
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlQueryContext.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlQueryContext.java
index 5fbf29c98f..de1c0fcc5e 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlQueryContext.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlQueryContext.java
@@ -21,6 +21,7 @@ package org.grails.orm.hibernate.query;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
@@ -54,7 +55,7 @@ public record HqlQueryContext(
         String hql,
         Class<?> targetClass,
         Map<String, Object> namedParams,
-        Collection<?> positionalParams,
+        List<Object> positionalParams,
         Map<String, Object> querySettings,
         boolean isUpdate,
         boolean isNative) {
@@ -65,33 +66,35 @@ public record HqlQueryContext(
      * Resolves the final HQL string, the result target class, and expands any 
{@link GString} into
      * named parameters. No {@code Session} is required.
      */
-    @SuppressWarnings("unchecked")
     public static HqlQueryContext prepare(
             PersistentEntity entity,
             CharSequence queryCharseq,
-            Map<?, ?> namedParams,
-            Collection<?> positionalParams,
-            Map<String, Object> querySettings,
+            Map<String,Object> namedParams,
+            Collection<Object> positionalParams,
+            Map<String,Object> querySettings,
             boolean isNative,
             boolean isUpdate) {
         Map<String, Object> _namedParams =
-                namedParams != null ? new HashMap<>((Map<String, Object>) 
namedParams) : new HashMap<>();
-        Collection<Object> positionalParamsCopy = positionalParams != null ? 
new ArrayList<>(positionalParams) : null;
-        Map<String, Object> querySettingsCopy = querySettings != null ? new 
HashMap<>(querySettings) : null;
+                namedParams != null ? new HashMap<>(namedParams) : new 
HashMap<>();
+        List<Object> positionalParamsCopy = positionalParams != null ? new 
ArrayList<>(positionalParams) : new ArrayList<>();
+        Map<String, Object> querySettingsCopy = querySettings != null ? new 
HashMap<>(querySettings) : new HashMap<>();
+
+        boolean _isNative = toBool(isNative);
+        boolean _isUpdate = toBool(isUpdate);
 
         String hql;
         // Prefer positional resolution only if positional parameters are 
explicitly provided (not null)
         // and named parameters are empty. This preserves legacy 
GString->named parameter behavior
         // while allowing opt-in to positional parameters via methods that 
pass them.
-        if (positionalParamsCopy != null && _namedParams.isEmpty()) {
-            hql = resolveHql(queryCharseq, isNative, positionalParamsCopy);
+        if (_namedParams.isEmpty()) {
+            hql = resolveHql(queryCharseq, _isNative, positionalParamsCopy);
         } else {
-            hql = resolveHql(queryCharseq, isNative, _namedParams);
+            hql = resolveHql(queryCharseq, _isNative, _namedParams);
         }
 
         Class<?> target = getTarget(hql, entity.getJavaClass());
         return new HqlQueryContext(
-                hql, target, _namedParams, positionalParamsCopy, 
querySettingsCopy, isUpdate, isNative);
+                hql, target, _namedParams, positionalParamsCopy, 
querySettingsCopy, _isUpdate, _isNative);
     }
 
     // ─── HQL resolution 
──────────────────────────────────────────────────────
@@ -339,4 +342,8 @@ public record HqlQueryContext(
         }
         return sql.toString();
     }
+
+    private static boolean toBool(Object v) {
+        return v instanceof Boolean b ? b : v != null && 
Boolean.parseBoolean(v.toString());
+    }
 }
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PagedResultList.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PagedResultList.java
index 0283ae881b..55926d5b3d 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PagedResultList.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PagedResultList.java
@@ -31,7 +31,7 @@ import org.hibernate.query.Query;
 import org.grails.datastore.mapping.model.PersistentEntity;
 import org.grails.orm.hibernate.GrailsHibernateTemplate;
 
-public class PagedResultList extends grails.gorm.PagedResultList {
+public class PagedResultList<E> extends grails.gorm.PagedResultList<E> {
 
     private static final long serialVersionUID = 1L;
 
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
new file mode 100644
index 0000000000..7175246be1
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/PagedResultListSpec.groovy
@@ -0,0 +1,97 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package grails.gorm.specs
+
+import grails.gorm.annotation.Entity
+import grails.gorm.hibernate.HibernateEntity
+import org.grails.orm.hibernate.query.PagedResultList
+
+class PagedResultListSpec extends HibernateGormDatastoreSpec {
+
+    void setupSpec() {
+        manager.addAllDomainClasses([PRLBook])
+    }
+
+    void "test PagedResultList totalCount with HQL query"() {
+        given:
+        new PRLBook(title: "The Stand").save()
+        new PRLBook(title: "The Shining").save()
+        new PRLBook(title: "Carrie").save()
+        session.flush()
+        session.clear()
+
+        when:
+        def results = PRLBook.list(max: 2, sort: "title")
+
+        then:
+        results instanceof PagedResultList
+        results.size() == 2
+        results.totalCount == 3
+        results[0].title == "Carrie"
+        results[1].title == "The Shining"
+    }
+
+    void "test PagedResultList with offset and max"() {
+        given:
+        (1..10).each { i -> new PRLBook(title: "Book $i").save() }
+        session.flush()
+        session.clear()
+
+        when:
+        def results = PRLBook.list(max: 3, offset: 2, sort: "id")
+
+        then:
+        results instanceof PagedResultList
+        results.size() == 3
+        results.totalCount == 10
+        results.max == 3
+        results.offset == 2
+        // results[0] should be "Book 3" (offset 2, 0-indexed id assumed here 
for simplicity of logic)
+        results.every { it.title.startsWith("Book ") }
+    }
+
+    void "test PagedResultList totalCount with Criteria query"() {
+        given:
+        new PRLBook(title: "The Stand").save()
+        new PRLBook(title: "The Shining").save()
+        new PRLBook(title: "Carrie").save()
+        session.flush()
+        session.clear()
+
+        when:
+        def results = PRLBook.createCriteria().list(max: 2) {
+            like("title", "The %")
+            order("title")
+        }
+
+        then:
+        results instanceof grails.gorm.PagedResultList
+        results.size() == 2
+        results.totalCount == 2
+        results.max == 2
+        results.offset == 0
+        results[0].title == "The Shining"
+        results[1].title == "The Stand"
+    }
+}
+
+@Entity
+class PRLBook implements HibernateEntity<PRLBook> {
+    Long id
+    String title
+}
diff --git 
a/grails-datamapping-core/src/main/groovy/grails/gorm/PagedResultList.java 
b/grails-datamapping-core/src/main/groovy/grails/gorm/PagedResultList.java
index eeb18a1286..aae01602ed 100644
--- a/grails-datamapping-core/src/main/groovy/grails/gorm/PagedResultList.java
+++ b/grails-datamapping-core/src/main/groovy/grails/gorm/PagedResultList.java
@@ -58,6 +58,24 @@ public class PagedResultList<E> implements Serializable, 
List<E> {
         return totalCount;
     }
 
+    /**
+     * @return The maximum number of results to return or null if not specified
+     */
+    public Integer getMax() {
+        return query != null ? query.getMax() : null;
+    }
+
+    /**
+     * @return The offset of the first result or 0 if not specified
+     */
+    public int getOffset() {
+        if (query != null) {
+            Integer offset = query.getOffset();
+            return offset != null ? offset : 0;
+        }
+        return 0;
+    }
+
     @Override
     public E get(int i) {
         return resultList.get(i);
diff --git 
a/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/query/Query.java
 
b/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/query/Query.java
index 3d3e705974..a778e2e020 100644
--- 
a/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/query/Query.java
+++ 
b/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/query/Query.java
@@ -87,6 +87,20 @@ public abstract class Query implements Cloneable {
         return newQuery;
     }
 
+    /**
+     * @return The maximum number of results to return
+     */
+    public Integer getMax() {
+        return max;
+    }
+
+    /**
+     * @return The offset of the first result
+     */
+    public Integer getOffset() {
+        return offset;
+    }
+
     /**
      * @return The criteria defined by this query
      */

Reply via email to