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 f44737e51c8878321f8b49837a4332263968df01
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Fri Mar 6 07:30:04 2026 -0600

    hibernate7: PredicateGenerator now uses ConversionService to coerce 
accidental String to Number
---
 .../grails/orm/hibernate/query/HibernateQuery.java |  5 ++++-
 .../hibernate/query/JpaCriteriaQueryCreator.java   |  9 +++++++--
 .../orm/hibernate/query/PredicateGenerator.java    | 15 ++++++++++++++
 .../JpaCriteriaQueryCreatorSpec.groovy             | 19 +++++++++---------
 .../hibernatequery/PredicateGeneratorSpec.groovy   | 23 +++++++++++++++++++++-
 5 files changed, 58 insertions(+), 13 deletions(-)

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 21b8c06d62..61a47e48ea 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
@@ -45,6 +45,7 @@ import org.hibernate.Session;
 import org.hibernate.SessionFactory;
 import org.hibernate.query.criteria.HibernateCriteriaBuilder;
 import org.hibernate.query.criteria.JpaCriteriaQuery;
+import org.springframework.core.convert.ConversionService;
 import org.springframework.dao.InvalidDataAccessApiUsageException;
 
 /**
@@ -410,7 +411,9 @@ public class HibernateQuery extends Query {
   }
 
   public JpaCriteriaQuery<?> getJpaCriteriaQuery() {
-    return new JpaCriteriaQueryCreator(projections, getCriteriaBuilder(), 
entity, detachedCriteria)
+    ConversionService conversionService =
+        getSession().getMappingContext().getConversionService();
+    return new JpaCriteriaQueryCreator(projections, getCriteriaBuilder(), 
entity, detachedCriteria, conversionService)
         .createQuery();
   }
 
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/JpaCriteriaQueryCreator.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/JpaCriteriaQueryCreator.java
index 60378b3545..201c0cabae 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/JpaCriteriaQueryCreator.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/JpaCriteriaQueryCreator.java
@@ -37,6 +37,8 @@ import org.hibernate.query.criteria.HibernateCriteriaBuilder;
 import org.hibernate.query.criteria.JpaCriteriaQuery;
 import org.hibernate.query.criteria.JpaExpression;
 
+import org.springframework.core.convert.ConversionService;
+
 @SuppressWarnings("PMD.DataflowAnomalyAnalysis")
 public class JpaCriteriaQueryCreator {
 
@@ -44,16 +46,19 @@ public class JpaCriteriaQueryCreator {
   private final HibernateCriteriaBuilder criteriaBuilder;
   private final PersistentEntity entity;
   private final DetachedCriteria<?> detachedCriteria;
+  private final ConversionService conversionService;
 
   public JpaCriteriaQueryCreator(
       Query.ProjectionList projections,
       HibernateCriteriaBuilder criteriaBuilder,
       PersistentEntity entity,
-      DetachedCriteria<?> detachedCriteria) {
+      DetachedCriteria<?> detachedCriteria,
+      ConversionService conversionService) {
     this.projections = projections;
     this.criteriaBuilder = criteriaBuilder;
     this.entity = entity;
     this.detachedCriteria = detachedCriteria;
+    this.conversionService = conversionService;
   }
 
   public JpaCriteriaQuery<?> createQuery() {
@@ -156,7 +161,7 @@ public class JpaCriteriaQueryCreator {
     List<Query.Criterion> criteriaList = detachedCriteria.getCriteria();
     if (!criteriaList.isEmpty()) {
       Predicate[] predicates =
-          new PredicateGenerator()
+          new PredicateGenerator(conversionService)
               .getPredicates(criteriaBuilder, cq, root, criteriaList, 
tablesByName, entity);
       cq.where(criteriaBuilder.and(predicates));
     }
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PredicateGenerator.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PredicateGenerator.java
index 8488ef23d1..ed9c2b3b8d 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PredicateGenerator.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PredicateGenerator.java
@@ -47,6 +47,7 @@ import org.hibernate.query.sqm.tree.domain.SqmPath;
 import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.core.convert.ConversionService;
 
 @Slf4j
 @SuppressWarnings({
@@ -63,6 +64,13 @@ import org.slf4j.LoggerFactory;
 public class PredicateGenerator {
   private static final Logger log = 
LoggerFactory.getLogger(PredicateGenerator.class);
 
+  private final ConversionService conversionService;
+
+
+  public PredicateGenerator(ConversionService conversionService) {
+    this.conversionService = conversionService;
+  }
+
   public Predicate[] getPredicates(
       HibernateCriteriaBuilder cb,
       CriteriaQuery<?> criteriaQuery,
@@ -472,6 +480,13 @@ public class PredicateGenerator {
   private Number getNumericValue(Query.PropertyCriterion criterion) {
     Object value = criterion.getValue();
     if (value instanceof Number num) return num;
+    if (value != null && conversionService.canConvert(value.getClass(), 
Number.class)) {
+      try {
+        return conversionService.convert(value, Number.class);
+      } catch (org.springframework.core.convert.ConversionException ignored) {
+        // fall through to ConfigurationException
+      }
+    }
     throw new ConfigurationException(
         String.format(
             "Operation '%s' on property '%s' only accepts a numeric value, but 
received a %s",
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/hibernatequery/JpaCriteriaQueryCreatorSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/hibernatequery/JpaCriteriaQueryCreatorSpec.groovy
index 968e78f914..32686a2eed 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/hibernatequery/JpaCriteriaQueryCreatorSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/hibernatequery/JpaCriteriaQueryCreatorSpec.groovy
@@ -7,6 +7,7 @@ import org.grails.datastore.mapping.query.Query
 import org.grails.orm.hibernate.query.JpaCriteriaQueryCreator
 import org.hibernate.query.criteria.HibernateCriteriaBuilder
 import org.hibernate.query.criteria.JpaCriteriaQuery
+import org.springframework.core.convert.support.DefaultConversionService
 
 class JpaCriteriaQueryCreatorSpec extends HibernateGormDatastoreSpec {
 
@@ -23,7 +24,7 @@ class JpaCriteriaQueryCreatorSpec extends 
HibernateGormDatastoreSpec {
         projections.property("firstName")
 
         
-        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria)
+        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria, new DefaultConversionService())
 
         when:
         JpaCriteriaQuery<?> query = creator.createQuery()
@@ -43,7 +44,7 @@ class JpaCriteriaQueryCreatorSpec extends 
HibernateGormDatastoreSpec {
         projections.property("lastName")
 
 
-        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria)
+        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria, new DefaultConversionService())
 
         when:
         JpaCriteriaQuery<?> query = creator.createQuery()
@@ -62,7 +63,7 @@ class JpaCriteriaQueryCreatorSpec extends 
HibernateGormDatastoreSpec {
         projections.count()
 
 
-        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria)
+        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria, new DefaultConversionService())
 
         when:
         JpaCriteriaQuery<?> query = creator.createQuery()
@@ -80,7 +81,7 @@ class JpaCriteriaQueryCreatorSpec extends 
HibernateGormDatastoreSpec {
         projections.countDistinct("firstName")
 
 
-        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria)
+        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria, new DefaultConversionService())
 
         when:
         JpaCriteriaQuery<?> query = creator.createQuery()
@@ -98,7 +99,7 @@ class JpaCriteriaQueryCreatorSpec extends 
HibernateGormDatastoreSpec {
         projections.id()
 
 
-        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria)
+        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria, new DefaultConversionService())
 
         when:
         JpaCriteriaQuery<?> query = creator.createQuery()
@@ -119,7 +120,7 @@ class JpaCriteriaQueryCreatorSpec extends 
HibernateGormDatastoreSpec {
         projections.sum("age")
 
 
-        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria)
+        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria, new DefaultConversionService())
 
         when:
         JpaCriteriaQuery<?> query = creator.createQuery()
@@ -141,7 +142,7 @@ class JpaCriteriaQueryCreatorSpec extends 
HibernateGormDatastoreSpec {
         projections.count()
 
 
-        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria)
+        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria, new DefaultConversionService())
 
         when:
         JpaCriteriaQuery<?> query = creator.createQuery()
@@ -160,7 +161,7 @@ class JpaCriteriaQueryCreatorSpec extends 
HibernateGormDatastoreSpec {
         var projections = new Query.ProjectionList()
 
 
-        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria)
+        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria, new DefaultConversionService())
 
         when:
         JpaCriteriaQuery<?> query = creator.createQuery()
@@ -180,7 +181,7 @@ class JpaCriteriaQueryCreatorSpec extends 
HibernateGormDatastoreSpec {
         projections.property("firstName")
 
 
-        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria)
+        var creator = new JpaCriteriaQueryCreator(projections, 
criteriaBuilder, entity, detachedCriteria, new DefaultConversionService())
 
         when:
         JpaCriteriaQuery<?> query = creator.createQuery()
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/hibernatequery/PredicateGeneratorSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/hibernatequery/PredicateGeneratorSpec.groovy
index 6eb19d48fd..2fc7f6a795 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/hibernatequery/PredicateGeneratorSpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/hibernatequery/PredicateGeneratorSpec.groovy
@@ -12,6 +12,7 @@ import org.grails.datastore.mapping.query.Query
 import org.grails.orm.hibernate.query.JpaFromProvider
 import org.grails.orm.hibernate.query.PredicateGenerator
 import org.hibernate.query.criteria.HibernateCriteriaBuilder
+import org.springframework.core.convert.support.DefaultConversionService
 
 class PredicateGeneratorSpec extends HibernateGormDatastoreSpec {
 
@@ -23,7 +24,7 @@ class PredicateGeneratorSpec extends 
HibernateGormDatastoreSpec {
     PersistentEntity personEntity
 
     def setup() {
-        predicateGenerator = new PredicateGenerator()
+        predicateGenerator = new PredicateGenerator(new 
DefaultConversionService())
         cb = sessionFactory.getCriteriaBuilder()
         query = cb.createQuery(Person)
         root = query.from(Person)
@@ -481,4 +482,24 @@ class PredicateGeneratorSpec extends 
HibernateGormDatastoreSpec {
         then:
         predicates.length == 1
     }
+
+    def "test gt with String value is coerced to Number"() {
+        given:
+        List criteria = [new Query.GreaterThan("age", "20")]
+        when:
+        def predicates = predicateGenerator.getPredicates(cb, query, root, 
criteria, fromProvider, personEntity)
+        then:
+        noExceptionThrown()
+        predicates.length == 1
+    }
+
+    def "test lt with String value is coerced to Number"() {
+        given:
+        List criteria = [new Query.LessThan("age", "30")]
+        when:
+        def predicates = predicateGenerator.getPredicates(cb, query, root, 
criteria, fromProvider, personEntity)
+        then:
+        noExceptionThrown()
+        predicates.length == 1
+    }
 }

Reply via email to