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

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

commit f2bbb1f3f501447e88a6f3886f60737ee8bcd093
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Thu Feb 19 15:58:47 2026 -0600

    Fluent refactoring of CriteriaMethodInvoker dispatch logic
---
 .../groovy/grails/orm/CriteriaMethodInvoker.java   | 383 ++++++++++++---------
 1 file changed, 212 insertions(+), 171 deletions(-)

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 0092d8ab72..5e645509f7 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
@@ -19,11 +19,10 @@ import java.beans.PropertyDescriptor;
 import java.util.Collection;
 import java.util.Map;
 
-/**
- * Helper class to handle method invocation for HibernateCriteriaBuilder.
- */
 public class CriteriaMethodInvoker {
 
+    private static final Object UNHANDLED = new Object();
+
     private final HibernateCriteriaBuilder builder;
 
     public CriteriaMethodInvoker(HibernateCriteriaBuilder builder) {
@@ -31,203 +30,245 @@ public class CriteriaMethodInvoker {
     }
 
     public Object invokeMethod(String name, Object[] args) {
-        HibernateQuery hibernateQuery = builder.getHibernateQuery();
         CriteriaMethods method = CriteriaMethods.fromName(name);
 
-        if (method != null && isCriteriaConstructionMethod(method, args)) {
-            switch (method) {
-                case GET_CALL -> builder.setUniqueResult(true);
-                case SCROLL_CALL -> builder.setScroll(true);
-                case COUNT_CALL -> builder.setCount(true);
-                case LIST_DISTINCT_CALL -> builder.setDistinct(true);
-            }
+        Object result = tryCriteriaConstruction(method, args);
+        if (result != UNHANDLED) return result;
 
-            // Check for pagination params
-            if (method == CriteriaMethods.LIST_CALL && args.length == 2) {
-                builder.setPaginationEnabledList(true);
-                if (args[0] instanceof Map map) {
-                    if (map.get("max") instanceof Number max) {
-                        hibernateQuery.maxResults(max.intValue());
-                    }
-                    if (map.get("offset") instanceof Number offset) {
-                        hibernateQuery.firstResult(offset.intValue());
-                    }
+        result = tryMetaMethod(name, args);
+        if (result != UNHANDLED) return result;
+
+        result = tryAssociationOrJunction(name, method, args);
+        if (result != UNHANDLED) return result;
+
+        result = trySimpleCriteria(name, method, args);
+        if (result != UNHANDLED) return result;
+
+        result = tryPropertyCriteria(method, args);
+        if (result != UNHANDLED) return result;
+
+        return CriteriaMethods.fromName(name, HibernateCriteriaBuilder.class, 
args);
+    }
+
+    private Object tryCriteriaConstruction(CriteriaMethods method, Object[] 
args) {
+        if (method == null || !isCriteriaConstructionMethod(method, args)) {
+            return UNHANDLED;
+        }
+
+        HibernateQuery hibernateQuery = builder.getHibernateQuery();
+        switch (method) {
+            case GET_CALL -> builder.setUniqueResult(true);
+            case SCROLL_CALL -> builder.setScroll(true);
+            case COUNT_CALL -> builder.setCount(true);
+            case LIST_DISTINCT_CALL -> builder.setDistinct(true);
+        }
+
+        // Check for pagination params
+        if (method == CriteriaMethods.LIST_CALL && args.length == 2) {
+            builder.setPaginationEnabledList(true);
+            if (args[0] instanceof Map map) {
+                if (map.get("max") instanceof Number max) {
+                    hibernateQuery.maxResults(max.intValue());
+                }
+                if (map.get("offset") instanceof Number offset) {
+                    hibernateQuery.firstResult(offset.intValue());
                 }
-                invokeClosureNode(args[1]);
-            } else {
-                invokeClosureNode(args[0]);
             }
+            invokeClosureNode(args[1]);
+        } else {
+            invokeClosureNode(args[0]);
+        }
 
-            Object result;
-            if (!builder.isUniqueResult()) {
-                if (builder.isDistinct()) {
-                    hibernateQuery.distinct();
-                    result = hibernateQuery.list();
-                } else if (builder.isCount()) {
-                    hibernateQuery.projections().count();
-                    result = hibernateQuery.singleResult();
-                } else if (builder.isPaginationEnabledList()) {
-                    Map argMap = (Map) args[0];
-                    final String sortField = (String) 
argMap.get(HibernateQueryConstants.ARGUMENT_SORT);
-                    if (sortField != null) {
-                        boolean ignoreCase = true;
-                        Object caseArg = 
argMap.get(HibernateQueryConstants.ARGUMENT_IGNORE_CASE);
-                        if (caseArg instanceof Boolean) {
-                            ignoreCase = (Boolean) caseArg;
-                        }
-                        final String orderParam = (String) 
argMap.get(HibernateQueryConstants.ARGUMENT_ORDER);
-                        final Query.Order.Direction direction = 
Query.Order.Direction.DESC.name().equalsIgnoreCase(orderParam) ? 
Query.Order.Direction.DESC : Query.Order.Direction.ASC;
-                        Query.Order order;
-                        if (ignoreCase) {
-                            order = new Query.Order(sortField, direction);
-                            order.ignoreCase();
-                        } else {
-                            order = new Query.Order(sortField, direction);
-                        }
-                        hibernateQuery.order(order);
+        Object result;
+        if (!builder.isUniqueResult()) {
+            if (builder.isDistinct()) {
+                hibernateQuery.distinct();
+                result = hibernateQuery.list();
+            } else if (builder.isCount()) {
+                hibernateQuery.projections().count();
+                result = hibernateQuery.singleResult();
+            } else if (builder.isPaginationEnabledList()) {
+                Map argMap = (Map) args[0];
+                final String sortField = (String) 
argMap.get(HibernateQueryConstants.ARGUMENT_SORT);
+                if (sortField != null) {
+                    boolean ignoreCase = true;
+                    Object caseArg = 
argMap.get(HibernateQueryConstants.ARGUMENT_IGNORE_CASE);
+                    if (caseArg instanceof Boolean) {
+                        ignoreCase = (Boolean) caseArg;
                     }
-                    result = new PagedResultList<>(hibernateQuery);
-                } else {
-                    result = hibernateQuery.list();
+                    final String orderParam = (String) 
argMap.get(HibernateQueryConstants.ARGUMENT_ORDER);
+                    final Query.Order.Direction direction = 
Query.Order.Direction.DESC.name().equalsIgnoreCase(orderParam) ? 
Query.Order.Direction.DESC : Query.Order.Direction.ASC;
+                    Query.Order order;
+                    if (ignoreCase) {
+                        order = new Query.Order(sortField, direction);
+                        order.ignoreCase();
+                    } else {
+                        order = new Query.Order(sortField, direction);
+                    }
+                    hibernateQuery.order(order);
                 }
+                result = new PagedResultList<>(hibernateQuery);
             } else {
-                result = hibernateQuery.singleResult();
+                result = hibernateQuery.list();
             }
-            if (!builder.isParticipate()) {
-                builder.closeSession();
-            }
-            return result;
+        } else {
+            result = hibernateQuery.singleResult();
+        }
+        if (!builder.isParticipate()) {
+            builder.closeSession();
         }
+        return result;
+    }
 
+    private Object tryMetaMethod(String name, Object[] args) {
         MetaMethod metaMethod = builder.getMetaClass().getMetaMethod(name, 
args);
         if (metaMethod != null) {
             return metaMethod.invoke(builder, args);
         }
+        return UNHANDLED;
+    }
 
-        if (isAssociationQueryMethod(args) || 
isAssociationQueryWithJoinSpecificationMethod(args)) {
-            final boolean hasMoreThanOneArg = args.length > 1;
-            Closure callable = hasMoreThanOneArg ? (Closure) args[1] : 
(Closure) args[0];
-            JoinType joinType = hasMoreThanOneArg ? 
builder.convertFromInt((Integer) args[0]) : builder.convertFromInt(0);
+    private Object tryAssociationOrJunction(String name, CriteriaMethods 
method, Object[] args) {
+        if (!isAssociationQueryMethod(args) && 
!isAssociationQueryWithJoinSpecificationMethod(args)) {
+            return UNHANDLED;
+        }
 
-            if (method != null) {
-                switch (method) {
-                    case AND:
-                        hibernateQuery.and(callable);
-                        return name;
-                    case OR:
-                        hibernateQuery.or(callable);
-                        return name;
-                    case NOT:
-                        hibernateQuery.not(callable);
+        HibernateQuery hibernateQuery = builder.getHibernateQuery();
+        final boolean hasMoreThanOneArg = args.length > 1;
+        Closure callable = hasMoreThanOneArg ? (Closure) args[1] : (Closure) 
args[0];
+        JoinType joinType = hasMoreThanOneArg ? 
builder.convertFromInt((Integer) args[0]) : builder.convertFromInt(0);
+
+        if (method != null) {
+            switch (method) {
+                case AND:
+                    hibernateQuery.and(callable);
+                    return name;
+                case OR:
+                    hibernateQuery.or(callable);
+                    return name;
+                case NOT:
+                    hibernateQuery.not(callable);
+                    return name;
+                case PROJECTIONS:
+                    if (args.length == 1 && (args[0] instanceof Closure)) {
+                        invokeClosureNode(callable);
                         return name;
-                    case PROJECTIONS:
-                        if (args.length == 1 && (args[0] instanceof Closure)) {
-                            invokeClosureNode(callable);
-                            return name;
-                        }
-                        break;
+                    }
+                    break;
+            }
+        }
+
+        final PropertyDescriptor pd = 
BeanUtils.getPropertyDescriptor(builder.getTargetClass(), name);
+        if (pd != null && pd.getReadMethod() != null) {
+            final Metamodel metamodel = 
builder.getSessionFactory().getMetamodel();
+            final EntityType<?> entityType = 
metamodel.entity(builder.getTargetClass());
+            final Attribute<?, ?> attribute = entityType.getAttribute(name);
+
+            if (attribute.isAssociation()) {
+                Class oldTargetClass = builder.getTargetClass();
+                
builder.setTargetClass(builder.getClassForAssociationType(attribute));
+                if (builder.getTargetClass().equals(oldTargetClass) && 
!hasMoreThanOneArg) {
+                    joinType = JoinType.LEFT; // default to left join if 
joining on the same table
                 }
+
+                hibernateQuery.join(name, joinType);
+                hibernateQuery.in(name, new 
DetachedCriteria(builder.getTargetClass()).build(callable));
+                builder.setTargetClass(oldTargetClass);
+
+                return name;
             }
+        }
+        return UNHANDLED;
+    }
 
-            final PropertyDescriptor pd = 
BeanUtils.getPropertyDescriptor(builder.getTargetClass(), name);
-            if (pd != null && pd.getReadMethod() != null) {
-                final Metamodel metamodel = 
builder.getSessionFactory().getMetamodel();
-                final EntityType<?> entityType = 
metamodel.entity(builder.getTargetClass());
-                final Attribute<?, ?> attribute = 
entityType.getAttribute(name);
-
-                if (attribute.isAssociation()) {
-                    Class oldTargetClass = builder.getTargetClass();
-                    
builder.setTargetClass(builder.getClassForAssociationType(attribute));
-                    if (builder.getTargetClass().equals(oldTargetClass) && 
!hasMoreThanOneArg) {
-                        joinType = JoinType.LEFT; // default to left join if 
joining on the same table
+    private Object trySimpleCriteria(String name, CriteriaMethods method, 
Object[] args) {
+        if (args.length != 1 || args[0] == null) {
+            return UNHANDLED;
+        }
+
+        Object value = args[0];
+        if (method != null) {
+            HibernateQuery hibernateQuery = builder.getHibernateQuery();
+            switch (method) {
+                case ID_EQUALS:
+                    return builder.eq("id", value);
+                case IS_NULL, IS_NOT_NULL, IS_EMPTY, IS_NOT_EMPTY:
+                    if (!(value instanceof String)) {
+                        builder.throwRuntimeException(new 
IllegalArgumentException("call to [" + name + "] with value [" +
+                                value + "] requires a String value."));
                     }
+                    String propertyName = 
builder.calculatePropertyName((String) value);
+                    switch (method) {
+                        case IS_NULL -> hibernateQuery.isNull(propertyName);
+                        case IS_NOT_NULL -> 
hibernateQuery.isNotNull(propertyName);
+                        case IS_EMPTY -> hibernateQuery.isEmpty(propertyName);
+                        case IS_NOT_EMPTY -> 
hibernateQuery.isNotEmpty(propertyName);
+                    }
+                    return name;
+            }
+        }
+        return UNHANDLED;
+    }
 
-                    hibernateQuery.join(name, joinType);
-                    hibernateQuery.in(name, new 
DetachedCriteria(builder.getTargetClass()).build(callable));
-                    builder.setTargetClass(oldTargetClass);
+    private Object tryPropertyCriteria(CriteriaMethods method, Object[] args) {
+        if (method == null || args.length < 2 || !(args[0] instanceof String)) 
{
+            return UNHANDLED;
+        }
 
-                    return name;
+        String propertyName = builder.calculatePropertyName((String) args[0]);
+        switch (method) {
+            case RLIKE:
+                return builder.rlike(propertyName, args[1]);
+            case BETWEEN:
+                if (args.length >= 3) {
+                    return builder.between(propertyName, args[1], args[2]);
                 }
-            }
-        } else if (args.length == 1 && args[0] != null) {
-            Object value = args[0];
-            if (method != null) {
-                switch (method) {
-                    case ID_EQUALS:
-                        return builder.eq("id", value);
-                    case IS_NULL, IS_NOT_NULL, IS_EMPTY, IS_NOT_EMPTY:
-                        if (!(value instanceof String)) {
-                            builder.throwRuntimeException(new 
IllegalArgumentException("call to [" + name + "] with value [" +
-                                    value + "] requires a String value."));
-                        }
-                        String propertyName = 
builder.calculatePropertyName((String) value);
-                        switch (method) {
-                            case IS_NULL -> 
hibernateQuery.isNull(propertyName);
-                            case IS_NOT_NULL -> 
hibernateQuery.isNotNull(propertyName);
-                            case IS_EMPTY -> 
hibernateQuery.isEmpty(propertyName);
-                            case IS_NOT_EMPTY -> 
hibernateQuery.isNotEmpty(propertyName);
-                        }
-                        return name;
+                break;
+            case EQUALS:
+                if (args.length == 3 && args[2] instanceof Map) {
+                    return builder.eq(propertyName, args[1], (Map) args[2]);
                 }
-            }
-        } else if (args.length >= 2 && args[0] instanceof String propertyName) 
{
-            propertyName = builder.calculatePropertyName(propertyName);
-            if (method != null) {
-                switch (method) {
-                    case RLIKE:
-                        return builder.rlike(propertyName, args[1]);
-                    case BETWEEN:
-                        if (args.length >= 3) {
-                            return builder.between(propertyName, args[1], 
args[2]);
-                        }
-                        break;
-                    case EQUALS:
-                        if (args.length == 3 && args[2] instanceof Map) {
-                            return builder.eq(propertyName, args[1], (Map) 
args[2]);
-                        }
-                        return builder.eq(propertyName, args[1]);
-                    case EQUALS_PROPERTY:
-                        return builder.eqProperty(propertyName, 
args[1].toString());
-                    case GREATER_THAN:
-                        return builder.gt(propertyName, args[1]);
-                    case GREATER_THAN_PROPERTY:
-                        return builder.gtProperty(propertyName, 
args[1].toString());
-                    case GREATER_THAN_OR_EQUAL:
-                        return builder.ge(propertyName, args[1]);
-                    case GREATER_THAN_OR_EQUAL_PROPERTY:
-                        return builder.geProperty(propertyName, 
args[1].toString());
-                    case ILIKE:
-                        return builder.ilike(propertyName, args[1]);
-                    case IN:
-                        if (args[1] instanceof Collection) {
-                            return builder.in(propertyName, (Collection) 
args[1]);
-                        } else if (args[1] instanceof Object[]) {
-                            return builder.in(propertyName, (Object[]) 
args[1]);
-                        }
-                        break;
-                    case LESS_THAN:
-                        return builder.lt(propertyName, args[1]);
-                    case LESS_THAN_PROPERTY:
-                        return builder.ltProperty(propertyName, 
args[1].toString());
-                    case LESS_THAN_OR_EQUAL:
-                        return builder.le(propertyName, args[1]);
-                    case LESS_THAN_OR_EQUAL_PROPERTY:
-                        return builder.leProperty(propertyName, 
args[1].toString());
-                    case LIKE:
-                        return builder.like(propertyName, args[1]);
-                    case NOT_EQUAL:
-                        return builder.ne(propertyName, args[1]);
-                    case NOT_EQUAL_PROPERTY:
-                        return builder.neProperty(propertyName, 
args[1].toString());
-                    case SIZE_EQUALS:
-                        if (args[1] instanceof Number) {
-                            return builder.sizeEq(propertyName, ((Number) 
args[1]).intValue());
-                        }
-                        break;
+                return builder.eq(propertyName, args[1]);
+            case EQUALS_PROPERTY:
+                return builder.eqProperty(propertyName, args[1].toString());
+            case GREATER_THAN:
+                return builder.gt(propertyName, args[1]);
+            case GREATER_THAN_PROPERTY:
+                return builder.gtProperty(propertyName, args[1].toString());
+            case GREATER_THAN_OR_EQUAL:
+                return builder.ge(propertyName, args[1]);
+            case GREATER_THAN_OR_EQUAL_PROPERTY:
+                return builder.geProperty(propertyName, args[1].toString());
+            case ILIKE:
+                return builder.ilike(propertyName, args[1]);
+            case IN:
+                if (args[1] instanceof Collection) {
+                    return builder.in(propertyName, (Collection) args[1]);
+                } else if (args[1] instanceof Object[]) {
+                    return builder.in(propertyName, (Object[]) args[1]);
                 }
-            }
+                break;
+            case LESS_THAN:
+                return builder.lt(propertyName, args[1]);
+            case LESS_THAN_PROPERTY:
+                return builder.ltProperty(propertyName, args[1].toString());
+            case LESS_THAN_OR_EQUAL:
+                return builder.le(propertyName, args[1]);
+            case LESS_THAN_OR_EQUAL_PROPERTY:
+                return builder.leProperty(propertyName, args[1].toString());
+            case LIKE:
+                return builder.like(propertyName, args[1]);
+            case NOT_EQUAL:
+                return builder.ne(propertyName, args[1]);
+            case NOT_EQUAL_PROPERTY:
+                return builder.neProperty(propertyName, args[1].toString());
+            case SIZE_EQUALS:
+                if (args[1] instanceof Number) {
+                    return builder.sizeEq(propertyName, ((Number) 
args[1]).intValue());
+                }
+                break;
         }
-        return CriteriaMethods.fromName(name, HibernateCriteriaBuilder.class, 
args);
+        return UNHANDLED;
     }
 
     private boolean isAssociationQueryMethod(Object[] args) {

Reply via email to