From 0ff7325e37214e38d5db259107364afb7282d363 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Fri, 10 Nov 2023 11:39:25 +0100 Subject: [PATCH] HHH-17412 Special case SqmExpression passed as criteria value to help with surprising javac compiler choices --- .../sqm/internal/SqmCriteriaNodeBuilder.java | 8 +++ .../expression/AbstractSqmExpression.java | 17 +------ .../tree/predicate/SqmInListPredicate.java | 6 +-- .../query/CriteriaExpressionAsValueTests.java | 50 +++++++++++++++++++ 4 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/query/CriteriaExpressionAsValueTests.java diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java index 947137a5db..301e154124 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java @@ -1775,6 +1775,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, * Creates an expression for the value with the given "type inference" information */ public SqmExpression value(T value, SqmExpression typeInferenceSource) { + if ( value instanceof SqmExpression ) { + //noinspection unchecked + return (SqmExpression) value; + } return inlineValue( value ) ? literal( value, typeInferenceSource ) : valueParameter( value, typeInferenceSource ); } @@ -1788,6 +1792,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, //noinspection unchecked return (SqmExpression) expression; } + else if ( value instanceof SqmExpression ) { + //noinspection unchecked + return (SqmExpression) value; + } else { return inlineValue( value ) ? literal( value ) : valueParameter( value ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AbstractSqmExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AbstractSqmExpression.java index 7731485c57..88f02c5f1e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AbstractSqmExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AbstractSqmExpression.java @@ -10,14 +10,12 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collection; -import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SqmExpressible; import org.hibernate.query.sqm.SqmTreeCreationLogger; import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder; import org.hibernate.query.sqm.tree.jpa.AbstractJpaSelection; -import org.hibernate.query.sqm.tree.predicate.SqmInPredicate; import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.type.descriptor.java.JavaType; @@ -130,19 +128,8 @@ public abstract class AbstractSqmExpression extends AbstractJpaSelection i @Override public SqmPredicate in(Collection values) { - final SqmInPredicate in = nodeBuilder().in( this ); - for ( Object value : values ) { - if ( value instanceof SqmExpression ) { - //noinspection unchecked - in.value( (JpaExpression) value ); - } - else { - //noinspection unchecked - in.value( (T) value ); - } - } - - return in; + //noinspection unchecked + return nodeBuilder().in( this, (Collection) values ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInListPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInListPredicate.java index cf57530a42..64eef0b08a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInListPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInListPredicate.java @@ -99,9 +99,9 @@ public class SqmInListPredicate extends AbstractNegatableSqmPredicate impleme public SqmInPredicate value(Object value) { if ( value instanceof Collection ) { //noinspection unchecked - ( (Collection) value ).forEach( - v -> addExpression( nodeBuilder().value( v, testExpression ) ) - ); + for ( T v : ( (Collection) value ) ) { + addExpression( nodeBuilder().value( v, testExpression ) ); + } } else { //noinspection unchecked diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/CriteriaExpressionAsValueTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/CriteriaExpressionAsValueTests.java new file mode 100644 index 0000000000..d2e3db0430 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/CriteriaExpressionAsValueTests.java @@ -0,0 +1,50 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.query; + +import org.hibernate.query.criteria.HibernateCriteriaBuilder; +import org.hibernate.query.criteria.JpaCriteriaQuery; +import org.hibernate.query.criteria.JpaParameterExpression; +import org.hibernate.query.criteria.JpaRoot; + +import org.hibernate.testing.orm.domain.StandardDomainModel; +import org.hibernate.testing.orm.domain.contacts.Contact; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.Tuple; + +/** + * @author Christian Beikov + */ +@DomainModel(standardModels = StandardDomainModel.CONTACTS) +@SessionFactory +@JiraKey("HHH-17412") +public class CriteriaExpressionAsValueTests { + + @Test + public void testParameters(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + final HibernateCriteriaBuilder cb = session.getCriteriaBuilder(); + final JpaCriteriaQuery cq = cb.createTupleQuery(); + final JpaRoot root = cq.from( Contact.class ); + cq.multiselect( + root.get( "id" ), + root.get( "name" ) + ); + final JpaParameterExpression parameter = cb.parameter( Contact.Gender.class ); + cq.where( root.get( "gender" ).equalTo( parameter ) ); + + session.createQuery( cq ).setParameter( parameter, Contact.Gender.FEMALE ).getResultList(); + } + ); + } +}