Skip to content

Commit 6a1581c

Browse files
dreab8sebersole
authored andcommitted
HHH-15725 Criteria API Expression.as adds cast even when the cast type is equal to the expression type
1 parent aece493 commit 6a1581c

File tree

15 files changed

+235
-10
lines changed

15 files changed

+235
-10
lines changed

hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,4 +301,9 @@ public BindableType getBindableType() {
301301
public SqmPath<J> createSqmPath(SqmPath<?> lhs, SqmPathSource<?> intermediatePathSource) {
302302
return sqmPathSource.createSqmPath( lhs, intermediatePathSource );
303303
}
304+
305+
@Override
306+
public JavaType<?> getRelationalJavaType() {
307+
return sqmPathSource.getRelationalJavaType();
308+
}
304309
}

hibernate-core/src/main/java/org/hibernate/query/criteria/JpaExpression.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,6 @@ public interface JpaExpression<T> extends JpaSelection<T>, Expression<T> {
5656
JpaPredicate equalTo(Expression<T> that);
5757

5858
JpaPredicate equalTo(T that);
59+
60+
<X> JpaExpression<X> cast(Class<X> type);
5961
}

hibernate-core/src/main/java/org/hibernate/query/sqm/SemanticQueryWalker.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.hibernate.query.sqm.tree.domain.SqmSetJoin;
4646
import org.hibernate.query.sqm.tree.domain.SqmSingularJoin;
4747
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
48+
import org.hibernate.query.sqm.tree.expression.AsWrapperSqmExpression;
4849
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
4950
import org.hibernate.query.sqm.tree.expression.SqmAny;
5051
import org.hibernate.query.sqm.tree.expression.SqmAnyDiscriminatorValue;
@@ -417,4 +418,6 @@ default T visitCorrelatedRoot(SqmCorrelatedRoot<?> correlatedRoot){
417418
T visitMapEntryFunction(SqmMapEntryReference<?, ?> function);
418419

419420
T visitFullyQualifiedClass(Class<?> namedClass);
421+
422+
T visitAsWrapperExpression(AsWrapperSqmExpression<?> expression);
420423
}

hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmTreePrinter.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.hibernate.query.sqm.tree.domain.SqmPluralPartJoin;
3535
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
3636
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
37+
import org.hibernate.query.sqm.tree.expression.AsWrapperSqmExpression;
3738
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
3839
import org.hibernate.query.sqm.tree.expression.SqmAny;
3940
import org.hibernate.query.sqm.tree.expression.SqmAnyDiscriminatorValue;
@@ -1194,6 +1195,11 @@ public Object visitFullyQualifiedClass(Class namedClass) {
11941195
return null;
11951196
}
11961197

1198+
@Override
1199+
public Object visitAsWrapperExpression(AsWrapperSqmExpression expression) {
1200+
return null;
1201+
}
1202+
11971203
@Override
11981204
public Object visitModifiedSubQueryExpression(SqmModifiedSubQueryExpression expression) {
11991205
return null;

hibernate-core/src/main/java/org/hibernate/query/sqm/spi/BaseSemanticQueryWalker.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.hibernate.query.sqm.tree.domain.SqmPluralPartJoin;
3535
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
3636
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
37+
import org.hibernate.query.sqm.tree.expression.AsWrapperSqmExpression;
3738
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
3839
import org.hibernate.query.sqm.tree.expression.SqmAggregateFunction;
3940
import org.hibernate.query.sqm.tree.expression.SqmAny;
@@ -981,4 +982,9 @@ public Object visitFieldLiteral(SqmFieldLiteral<?> sqmFieldLiteral) {
981982
return sqmFieldLiteral;
982983
}
983984

985+
@Override
986+
public Object visitAsWrapperExpression(AsWrapperSqmExpression<?> expression) {
987+
expression.getExpression().accept( this );
988+
return expression;
989+
}
984990
}

hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@
128128
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
129129
import org.hibernate.query.sqm.spi.BaseSemanticQueryWalker;
130130
import org.hibernate.query.sqm.sql.internal.AnyDiscriminatorPathInterpretation;
131+
import org.hibernate.query.sqm.sql.internal.AsWrappedExpression;
131132
import org.hibernate.query.sqm.sql.internal.BasicValuedPathInterpretation;
132133
import org.hibernate.query.sqm.sql.internal.DiscriminatedAssociationPathInterpretation;
133134
import org.hibernate.query.sqm.sql.internal.DiscriminatorPathInterpretation;
@@ -174,6 +175,7 @@
174175
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
175176
import org.hibernate.query.sqm.tree.domain.SqmSimplePath;
176177
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
178+
import org.hibernate.query.sqm.tree.expression.AsWrapperSqmExpression;
177179
import org.hibernate.query.sqm.tree.expression.Conversion;
178180
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
179181
import org.hibernate.query.sqm.tree.expression.SqmAliasedNodeRef;
@@ -8268,6 +8270,14 @@ public Object visitFullyQualifiedClass(Class<?> namedClass) {
82688270
// .getOrMakeJavaDescriptor( namedClass );
82698271
}
82708272

8273+
@Override
8274+
public Object visitAsWrapperExpression(AsWrapperSqmExpression<?> sqmExpression) {
8275+
return new AsWrappedExpression<>(
8276+
(Expression) sqmExpression.getExpression().accept( this ),
8277+
sqmExpression.getNodeType()
8278+
);
8279+
}
8280+
82718281
@Override
82728282
public Fetch visitIdentifierFetch(EntityResultGraphNode fetchParent) {
82738283
final EntityIdentifierMapping identifierMapping = fetchParent.getReferencedMappingContainer()
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
6+
*/
7+
package org.hibernate.query.sqm.sql.internal;
8+
9+
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
10+
import org.hibernate.sql.ast.SqlAstWalker;
11+
import org.hibernate.sql.ast.spi.SqlAstCreationState;
12+
import org.hibernate.sql.ast.spi.SqlSelection;
13+
import org.hibernate.sql.ast.tree.expression.ColumnReference;
14+
import org.hibernate.sql.ast.tree.expression.Expression;
15+
import org.hibernate.sql.results.graph.DomainResult;
16+
import org.hibernate.sql.results.graph.DomainResultCreationState;
17+
import org.hibernate.sql.results.graph.basic.BasicResult;
18+
import org.hibernate.type.BasicType;
19+
import org.hibernate.type.descriptor.java.JavaType;
20+
import org.hibernate.type.spi.TypeConfiguration;
21+
22+
public class AsWrappedExpression<B> implements Expression, DomainResultProducer<B> {
23+
private final Expression wrappedExpression;
24+
private final BasicType<B> expressionType;
25+
26+
public AsWrappedExpression(Expression wrappedExpression, BasicType<B> expressionType) {
27+
assert wrappedExpression instanceof DomainResultProducer : "AsWrappedExpression expected to be an instance of DomainResultProducer";
28+
this.wrappedExpression = wrappedExpression;
29+
this.expressionType = expressionType;
30+
}
31+
32+
@Override
33+
public JdbcMappingContainer getExpressionType() {
34+
return expressionType;
35+
}
36+
37+
@Override
38+
public ColumnReference getColumnReference() {
39+
return wrappedExpression.getColumnReference();
40+
}
41+
42+
@Override
43+
public SqlSelection createSqlSelection(
44+
int jdbcPosition,
45+
int valuesArrayPosition,
46+
JavaType javaType,
47+
boolean virtual,
48+
TypeConfiguration typeConfiguration) {
49+
return wrappedExpression.createSqlSelection(
50+
jdbcPosition,
51+
valuesArrayPosition,
52+
javaType,
53+
virtual,
54+
typeConfiguration
55+
);
56+
}
57+
58+
@Override
59+
public SqlSelection createDomainResultSqlSelection(
60+
int jdbcPosition,
61+
int valuesArrayPosition,
62+
JavaType javaType,
63+
boolean virtual,
64+
TypeConfiguration typeConfiguration) {
65+
return wrappedExpression.createDomainResultSqlSelection(
66+
jdbcPosition,
67+
valuesArrayPosition,
68+
javaType,
69+
virtual,
70+
typeConfiguration
71+
);
72+
}
73+
74+
@Override
75+
public void accept(SqlAstWalker sqlTreeWalker) {
76+
wrappedExpression.accept( sqlTreeWalker );
77+
}
78+
79+
@Override
80+
public DomainResult<B> createDomainResult(String resultVariable, DomainResultCreationState creationState) {
81+
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
82+
final SqlSelection sqlSelection = sqlAstCreationState.getSqlExpressionResolver()
83+
.resolveSqlSelection(
84+
wrappedExpression,
85+
wrappedExpression.getExpressionType().getSingleJdbcMapping().getJdbcJavaType(),
86+
null,
87+
sqlAstCreationState.getCreationContext()
88+
.getMappingMetamodel().getTypeConfiguration()
89+
);
90+
return new BasicResult<>(
91+
sqlSelection.getValuesArrayPosition(),
92+
resultVariable,
93+
expressionType.getExpressibleJavaType(),
94+
null,
95+
null,
96+
false,
97+
false
98+
);
99+
}
100+
101+
@Override
102+
public void applySqlSelections(DomainResultCreationState creationState) {
103+
//noinspection unchecked
104+
( (DomainResultProducer<B>) wrappedExpression ).applySqlSelections( creationState );
105+
}
106+
}

hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmBasicValuedSimplePath.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,4 +197,9 @@ public DomainType<T> getSqmType() {
197197
public <X> X accept(SemanticQueryWalker<X> walker) {
198198
return walker.visitBasicValuedPath( this );
199199
}
200+
201+
@Override
202+
public JavaType<?> getRelationalJavaType() {
203+
return super.getExpressible().getRelationalJavaType();
204+
}
200205
}

hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmEmbeddedValuedSimplePath.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,9 @@ public Class<T> getJavaType() {
121121
public Class<T> getBindableJavaType() {
122122
return getJavaType();
123123
}
124+
125+
@Override
126+
public JavaType<?> getRelationalJavaType() {
127+
return super.getExpressible().getRelationalJavaType();
128+
}
124129
}

hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AbstractSqmExpression.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
import java.math.BigInteger;
1111
import java.util.Collection;
1212

13-
import org.hibernate.query.criteria.JpaSelection;
1413
import org.hibernate.query.sqm.NodeBuilder;
1514
import org.hibernate.query.sqm.SqmExpressible;
1615
import org.hibernate.query.sqm.SqmTreeCreationLogger;
1716
import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder;
1817
import org.hibernate.query.sqm.tree.jpa.AbstractJpaSelection;
1918
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
19+
import org.hibernate.type.BasicType;
2020
import org.hibernate.type.descriptor.java.JavaType;
2121

2222
import jakarta.persistence.criteria.Expression;
@@ -94,7 +94,11 @@ public SqmExpression<String> asString() {
9494

9595
@Override
9696
public <X> SqmExpression<X> as(Class<X> type) {
97-
return nodeBuilder().cast( this, type );
97+
final BasicType<X> basicTypeForJavaType = nodeBuilder().getTypeConfiguration().getBasicTypeForJavaType( type );
98+
if ( basicTypeForJavaType == null ) {
99+
throw new IllegalArgumentException( "Can't cast expression to unknown type: " + type.getCanonicalName() );
100+
}
101+
return new AsWrapperSqmExpression<>( basicTypeForJavaType, this );
98102
}
99103

100104
@Override

0 commit comments

Comments
 (0)