HHH-17412 Special case SqmExpression passed as criteria value to help with surprising javac compiler choices

This commit is contained in:
Christian Beikov 2023-11-10 11:39:25 +01:00
parent 633412097f
commit 0ff7325e37
4 changed files with 63 additions and 18 deletions

View File

@ -1775,6 +1775,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
* Creates an expression for the value with the given "type inference" information
*/
public <T> SqmExpression<T> value(T value, SqmExpression<? extends T> typeInferenceSource) {
if ( value instanceof SqmExpression<?> ) {
//noinspection unchecked
return (SqmExpression<T>) value;
}
return inlineValue( value ) ? literal( value, typeInferenceSource ) : valueParameter( value, typeInferenceSource );
}
@ -1788,6 +1792,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
//noinspection unchecked
return (SqmExpression<T>) expression;
}
else if ( value instanceof SqmExpression<?> ) {
//noinspection unchecked
return (SqmExpression<T>) value;
}
else {
return inlineValue( value ) ? literal( value ) : valueParameter( value );
}

View File

@ -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<T> extends AbstractJpaSelection<T> i
@Override
public SqmPredicate in(Collection<?> values) {
final SqmInPredicate<T> in = nodeBuilder().in( this );
for ( Object value : values ) {
if ( value instanceof SqmExpression<?> ) {
//noinspection unchecked
in.value( (JpaExpression<? extends T>) value );
}
else {
//noinspection unchecked
in.value( (T) value );
}
}
return in;
//noinspection unchecked
return nodeBuilder().in( this, (Collection<T>) values );
}
@Override

View File

@ -99,9 +99,9 @@ public class SqmInListPredicate<T> extends AbstractNegatableSqmPredicate impleme
public SqmInPredicate<T> value(Object value) {
if ( value instanceof Collection ) {
//noinspection unchecked
( (Collection<T>) value ).forEach(
v -> addExpression( nodeBuilder().value( v, testExpression ) )
);
for ( T v : ( (Collection<T>) value ) ) {
addExpression( nodeBuilder().value( v, testExpression ) );
}
}
else {
//noinspection unchecked

View File

@ -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<Tuple> cq = cb.createTupleQuery();
final JpaRoot<Contact> root = cq.from( Contact.class );
cq.multiselect(
root.get( "id" ),
root.get( "name" )
);
final JpaParameterExpression<Contact.Gender> parameter = cb.parameter( Contact.Gender.class );
cq.where( root.get( "gender" ).equalTo( parameter ) );
session.createQuery( cq ).setParameter( parameter, Contact.Gender.FEMALE ).getResultList();
}
);
}
}