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 + } }
