Skip to content

Commit 5f4ab63

Browse files
committed
sort out typing issues with NamedCriteriaQueryMemento
check the result type
1 parent f2a1902 commit 5f4ab63

File tree

5 files changed

+73
-33
lines changed

5 files changed

+73
-33
lines changed

hibernate-core/src/main/java/org/hibernate/query/criteria/internal/NamedCriteriaQueryMementoImpl.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
package org.hibernate.query.criteria.internal;
66

77
import java.io.Serializable;
8+
import java.util.Locale;
89
import java.util.Map;
910

1011
import org.hibernate.CacheMode;
1112
import org.hibernate.FlushMode;
1213
import org.hibernate.LockOptions;
1314
import org.hibernate.engine.spi.SharedSessionContractImplementor;
15+
import org.hibernate.query.IllegalSelectQueryException;
16+
import org.hibernate.query.QueryTypeMismatchException;
1417
import org.hibernate.query.hql.spi.SqmQueryImplementor;
1518
import org.hibernate.query.named.AbstractNamedQueryMemento;
1619
import org.hibernate.query.spi.QueryEngine;
@@ -21,6 +24,7 @@
2124
import org.hibernate.query.sqm.tree.SqmStatement;
2225

2326
import org.checkerframework.checker.nullness.qual.Nullable;
27+
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
2428

2529
public class NamedCriteriaQueryMementoImpl<E> extends AbstractNamedQueryMemento<E>
2630
implements NamedSqmQueryMemento<E>, Serializable {
@@ -60,12 +64,33 @@ public NamedCriteriaQueryMementoImpl(
6064

6165
@Override
6266
public void validate(QueryEngine queryEngine) {
67+
// nothing to do
68+
}
6369

70+
private static <T> void checkResultType(Class<T> resultType, SqmSelectStatement<?> selectStatement) {
71+
final Class<?> expectedResultType = selectStatement.getResultType();
72+
if ( expectedResultType != null ) {
73+
if ( !resultType.isAssignableFrom( expectedResultType ) ) {
74+
throw new QueryTypeMismatchException(
75+
String.format(
76+
Locale.ROOT,
77+
"Incorrect query result type: query produces '%s' but type '%s' was given",
78+
expectedResultType.getName(),
79+
resultType.getName()
80+
)
81+
);
82+
}
83+
}
6484
}
6585

6686
@Override
6787
public <T> SqmQueryImplementor<T> toQuery(SharedSessionContractImplementor session, Class<T> resultType) {
68-
return new QuerySqmImpl<>( this, resultType, session );
88+
if ( sqmStatement instanceof SqmSelectStatement<?> selectStatement ) {
89+
checkResultType( resultType, selectStatement );
90+
}
91+
@SuppressWarnings("unchecked") // we just checked the result type
92+
final SqmStatement<T> statement = (SqmStatement<T>) sqmStatement;
93+
return new QuerySqmImpl<>( this, statement, resultType, session );
6994
}
7095

7196
@Override
@@ -75,7 +100,13 @@ public SqmQueryImplementor<E> toQuery(SharedSessionContractImplementor session)
75100

76101
@Override
77102
public <T> SqmSelectionQuery<T> toSelectionQuery(Class<T> resultType, SharedSessionContractImplementor session) {
78-
return new SqmSelectionQueryImpl<>( this, resultType, session );
103+
if ( !( sqmStatement instanceof SqmSelectStatement<?> selectStatement ) ) {
104+
throw new IllegalSelectQueryException( "Named query is not a SELECT statement: " + getName() );
105+
}
106+
checkResultType( resultType, selectStatement );
107+
@SuppressWarnings("unchecked") // we just checked the result type
108+
final SqmSelectStatement<T> statement = (SqmSelectStatement<T>) selectStatement;
109+
return new SqmSelectionQueryImpl<>( this, statement, resultType, session );
79110
}
80111

81112
@Override
@@ -110,7 +141,7 @@ public Map<String, String> getParameterTypes() {
110141

111142
@Override
112143
public NamedSqmQueryMemento<E> makeCopy(String name) {
113-
return new NamedCriteriaQueryMementoImpl<E>(
144+
return new NamedCriteriaQueryMementoImpl<>(
114145
name,
115146
getResultType(),
116147
sqmStatement,

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import org.hibernate.query.restriction.Restriction;
1717
import org.hibernate.query.SelectionQuery;
1818
import org.hibernate.query.criteria.JpaSelection;
19-
import org.hibernate.query.hql.internal.NamedHqlQueryMementoImpl;
2019
import org.hibernate.query.hql.internal.QuerySplitter;
2120
import org.hibernate.query.spi.AbstractSelectionQuery;
2221
import org.hibernate.query.spi.HqlInterpretation;
@@ -169,7 +168,7 @@ public KeyedResultList<R> getKeyedResultList(KeyedPage<R> keyedPage) {
169168
final List<KeyedResult<R>> results =
170169
new SqmSelectionQueryImpl<KeyedResult<R>>( this, keyedPage )
171170
.getResultList();
172-
int pageSize = keyedPage.getPage().getSize();
171+
final int pageSize = keyedPage.getPage().getSize();
173172
return new KeyedResultList<>(
174173
collectResults( results, pageSize, keyedPage.getKeyInterpretation() ),
175174
collectKeys( results, pageSize ),
@@ -388,7 +387,7 @@ else if ( queryPart instanceof SqmQueryGroup<?> queryGroup ) {
388387
}
389388

390389
protected static <T> HqlInterpretation<T> interpretation(
391-
NamedHqlQueryMementoImpl<?> memento,
390+
NamedSqmQueryMemento<?> memento,
392391
Class<T> expectedResultType,
393392
SharedSessionContractImplementor session) {
394393
final QueryEngine queryEngine = session.getFactory().getQueryEngine();

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

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -132,27 +132,31 @@ public class QuerySqmImpl<R>
132132
private final TupleMetadata tupleMetadata;
133133

134134
/**
135-
* Creates a Query instance from a named HQL memento
135+
* Creates a {@link org.hibernate.query.Query}
136+
* instance from a named HQL memento.
137+
* Form used from {@link NamedHqlQueryMementoImpl}.
136138
*/
137139
public QuerySqmImpl(
138-
NamedHqlQueryMementoImpl<?> memento,
140+
NamedSqmQueryMemento<?> memento,
139141
Class<R> expectedResultType,
140142
SharedSessionContractImplementor session) {
141-
this(
142-
memento.getHqlString(),
143+
this( memento.getHqlString(),
143144
interpretation( memento, expectedResultType, session ),
144-
expectedResultType,
145-
session
146-
);
145+
expectedResultType, session );
147146
applySqmOptions( memento );
148147
}
149148

149+
/**
150+
* Creates a {@link org.hibernate.query.Query}
151+
* instance from a named criteria query memento.
152+
* Form used from {@link NamedCriteriaQueryMementoImpl}
153+
*/
150154
public QuerySqmImpl(
151-
NamedCriteriaQueryMementoImpl<?> memento,
155+
NamedSqmQueryMemento<?> memento,
156+
SqmStatement<R> statement,
152157
Class<R> resultType,
153158
SharedSessionContractImplementor session) {
154-
this( (SqmStatement<R>) memento.getSqmStatement(), resultType, session );
155-
159+
this( statement, resultType, session );
156160
applySqmOptions( memento );
157161
}
158162

@@ -177,10 +181,8 @@ public QuerySqmImpl(
177181
if ( sqm instanceof SqmSelectStatement<?> ) {
178182
hqlInterpretation.validateResultType( resultType );
179183
}
180-
else {
181-
if ( resultType != null ) {
182-
throw new IllegalQueryOperationException( "Result type given for a non-SELECT Query", hql, null );
183-
}
184+
else if ( resultType != null ) {
185+
throw new IllegalQueryOperationException( "Result type given for a non-SELECT Query", hql, null );
184186
}
185187
setComment( hql );
186188

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

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ public class SqmSelectionQueryImpl<R> extends AbstractSqmSelectionQuery<R>
9999
private final Class<?> resultType;
100100
private final TupleMetadata tupleMetadata;
101101

102+
/**
103+
* Form used for HQL queries
104+
*/
102105
public SqmSelectionQueryImpl(
103106
String hql,
104107
HqlInterpretation<R> hqlInterpretation,
@@ -114,7 +117,6 @@ public SqmSelectionQueryImpl(
114117
this.domainParameterXref = hqlInterpretation.getDomainParameterXref();
115118
this.parameterBindings = parameterMetadata.createBindings( session.getFactory() );
116119

117-
118120
this.expectedResultType = expectedResultType;
119121
this.resultType = determineResultType( sqm, expectedResultType );
120122
this.tupleMetadata = buildTupleMetadata( sqm, expectedResultType );
@@ -123,29 +125,38 @@ public SqmSelectionQueryImpl(
123125
setComment( hql );
124126
}
125127

128+
/**
129+
* Creates a {@link org.hibernate.query.SelectionQuery}
130+
* instance from a named HQL memento.
131+
* Form used from {@link NamedHqlQueryMementoImpl}.
132+
*/
126133
public SqmSelectionQueryImpl(
127134
NamedHqlQueryMementoImpl<?> memento,
128135
Class<R> resultType,
129136
SharedSessionContractImplementor session) {
130-
this(
131-
memento.getHqlString(),
137+
this( memento.getHqlString(),
132138
interpretation( memento, resultType, session ),
133-
resultType,
134-
session
135-
);
136-
139+
resultType, session );
137140
applySqmOptions( memento );
138141
}
139142

143+
/**
144+
* Creates a {@link org.hibernate.query.SelectionQuery}
145+
* instance from a named criteria query memento.
146+
* Form used from {@link NamedCriteriaQueryMementoImpl}
147+
*/
140148
public SqmSelectionQueryImpl(
141149
NamedCriteriaQueryMementoImpl<?> memento,
150+
SqmSelectStatement<R> selectStatement,
142151
Class<R> expectedResultType,
143152
SharedSessionContractImplementor session) {
144-
//noinspection unchecked
145-
this( (SqmSelectStatement<R>) memento.getSqmStatement(), expectedResultType, session );
153+
this( selectStatement, expectedResultType, session );
146154
applySqmOptions( memento );
147155
}
148156

157+
/**
158+
* Form used for criteria queries
159+
*/
149160
public SqmSelectionQueryImpl(
150161
SqmSelectStatement<R> criteria,
151162
Class<R> expectedResultType,

hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,7 @@ private SqmSelectStatement(
124124
@Override
125125
public SqmSelectStatement<T> copy(SqmCopyContext context) {
126126
final SqmSelectStatement<T> existing = context.getCopy( this );
127-
if ( existing != null ) {
128-
return existing;
129-
}
130-
return createCopy( context, getResultType() );
127+
return existing != null ? existing : createCopy( context, getResultType() );
131128
}
132129

133130
@Internal

0 commit comments

Comments
 (0)