Skip to content

Commit 876018d

Browse files
committed
HHH-19364 changes to Specifications to support Hibernate Processor
1. fix generic types of parameters (should be lower bounds) 2. make it work with plain-vanilla EntityManager 3. to eliminate ambiguity in overload resolution, this unfortunately required disallowing SharedSessionContract 4. make Path.fetch() use LEFT join
1 parent 50a4444 commit 876018d

File tree

8 files changed

+102
-34
lines changed

8 files changed

+102
-34
lines changed

hibernate-core/src/main/java/org/hibernate/query/programmatic/MutationSpecification.java

+14-7
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
import jakarta.persistence.criteria.CriteriaBuilder;
1111
import jakarta.persistence.criteria.Root;
1212
import org.hibernate.Incubating;
13-
import org.hibernate.SharedSessionContract;
13+
import org.hibernate.Session;
14+
import org.hibernate.StatelessSession;
1415
import org.hibernate.query.IllegalMutationQueryException;
1516
import org.hibernate.query.MutationQuery;
1617
import org.hibernate.query.SelectionQuery;
@@ -43,7 +44,7 @@ public interface MutationSpecification<T> extends QuerySpecification<T> {
4344
* Covariant override.
4445
*/
4546
@Override
46-
MutationSpecification<T> restrict(Restriction<T> restriction);
47+
MutationSpecification<T> restrict(Restriction<? super T> restriction);
4748

4849
/**
4950
* A function capable of modifying or augmenting a criteria query.
@@ -65,15 +66,21 @@ interface Augmentation<T> {
6566
MutationSpecification<T> augment(Augmentation<T> augmentation);
6667

6768
/**
68-
* Finalize the building and create the {@linkplain SelectionQuery} instance.
69+
* Finalize the building and create the {@linkplain MutationQuery} instance.
6970
*/
7071
@Override
71-
MutationQuery createQuery(SharedSessionContract session);
72+
MutationQuery createQuery(Session session);
73+
74+
/**
75+
* Finalize the building and create the {@linkplain MutationQuery} instance.
76+
*/
77+
@Override
78+
MutationQuery createQuery(StatelessSession session);
7279

7380
/**
7481
* Returns a specification reference which can be used to programmatically,
7582
* iteratively build a {@linkplain MutationQuery} based on a base HQL statement,
76-
* allowing the addition of {@linkplain MutationSpecification#restrict restrictions}.
83+
* allowing the addition of {@linkplain #restrict restrictions}.
7784
*
7885
* @param hql The base HQL query (expected to be an {@code update} or {@code delete} query).
7986
* @param mutationTarget The entity which is the target of the mutation.
@@ -91,7 +98,7 @@ static <T> MutationSpecification<T> create(Class<T> mutationTarget, String hql)
9198
/**
9299
* Returns a specification reference which can be used to programmatically,
93100
* iteratively build a {@linkplain MutationQuery} based on the given criteria update,
94-
* allowing the addition of {@linkplain MutationSpecification#restrict restrictions}.
101+
* allowing the addition of {@linkplain #restrict restrictions}.
95102
*
96103
* @param criteriaUpdate The criteria update query
97104
*
@@ -104,7 +111,7 @@ static <T> MutationSpecification<T> create(CriteriaUpdate<T> criteriaUpdate) {
104111
/**
105112
* Returns a specification reference which can be used to programmatically,
106113
* iteratively build a {@linkplain MutationQuery} based on the given criteria delete,
107-
* allowing the addition of {@linkplain MutationSpecification#restrict restrictions}.
114+
* allowing the addition of {@linkplain #restrict restrictions}.
108115
*
109116
* @param criteriaDelete The criteria delete query
110117
*

hibernate-core/src/main/java/org/hibernate/query/programmatic/QuerySpecification.java

+19-4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
*/
55
package org.hibernate.query.programmatic;
66

7+
import jakarta.persistence.EntityManager;
8+
79
import org.hibernate.Incubating;
10+
import org.hibernate.Session;
811
import org.hibernate.SessionFactory;
9-
import org.hibernate.SharedSessionContract;
12+
import org.hibernate.StatelessSession;
1013
import org.hibernate.engine.spi.SessionFactoryImplementor;
1114
import org.hibernate.query.CommonQueryContract;
1215
import org.hibernate.query.restriction.Restriction;
@@ -33,12 +36,22 @@ public interface QuerySpecification<T> {
3336
*
3437
* @return {@code this} for method chaining.
3538
*/
36-
QuerySpecification<T> restrict(Restriction<T> restriction);
39+
QuerySpecification<T> restrict(Restriction<? super T> restriction);
40+
41+
/**
42+
* Finalize the building and create executable query instance.
43+
*/
44+
CommonQueryContract createQuery(Session session);
45+
46+
/**
47+
* Finalize the building and create executable query instance.
48+
*/
49+
CommonQueryContract createQuery(StatelessSession session);
3750

3851
/**
3952
* Finalize the building and create executable query instance.
4053
*/
41-
CommonQueryContract createQuery(SharedSessionContract session);
54+
CommonQueryContract createQuery(EntityManager entityManager);
4255

4356
/**
4457
* Validate the query.
@@ -47,7 +60,9 @@ default void validate(SessionFactory factory) {
4760
// Extremely temporary implementation.
4861
// We don't actually want to open a session here,
4962
// nor create an instance of CommonQueryContract.
50-
try ( var session = ((SessionFactoryImplementor) factory).openTemporarySession() ) {
63+
final SessionFactoryImplementor factoryImplementor =
64+
(SessionFactoryImplementor) factory;
65+
try ( var session = factoryImplementor.openTemporarySession() ) {
5166
createQuery( session );
5267
}
5368
}

hibernate-core/src/main/java/org/hibernate/query/programmatic/SelectionSpecification.java

+24-13
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
*/
55
package org.hibernate.query.programmatic;
66

7+
import jakarta.persistence.EntityManager;
78
import jakarta.persistence.criteria.CriteriaQuery;
89
import jakarta.persistence.criteria.CriteriaBuilder;
910
import jakarta.persistence.criteria.Root;
1011
import org.hibernate.Incubating;
11-
import org.hibernate.SharedSessionContract;
12+
import org.hibernate.Session;
13+
import org.hibernate.StatelessSession;
1214
import org.hibernate.query.IllegalSelectQueryException;
1315
import org.hibernate.query.Order;
1416
import org.hibernate.query.SelectionQuery;
@@ -63,7 +65,7 @@ public interface SelectionSpecification<T> extends QuerySpecification<T> {
6365
*
6466
* @return {@code this} for method chaining.
6567
*/
66-
SelectionSpecification<T> sort(Order<T> order);
68+
SelectionSpecification<T> sort(Order<? super T> order);
6769

6870
/**
6971
* Sets the ordering for this selection specification.
@@ -74,7 +76,7 @@ public interface SelectionSpecification<T> extends QuerySpecification<T> {
7476
*
7577
* @return {@code this} for method chaining.
7678
*/
77-
SelectionSpecification<T> resort(Order<T> order);
79+
SelectionSpecification<T> resort(Order<? super T> order);
7880

7981
/**
8082
* Sets the sorting for this selection specification.
@@ -85,13 +87,13 @@ public interface SelectionSpecification<T> extends QuerySpecification<T> {
8587
*
8688
* @return {@code this} for method chaining.
8789
*/
88-
SelectionSpecification<T> resort(List<Order<T>> orders);
90+
SelectionSpecification<T> resort(List<Order<? super T>> orders);
8991

9092
/**
9193
* Covariant override.
9294
*/
9395
@Override
94-
SelectionSpecification<T> restrict(Restriction<T> restriction);
96+
SelectionSpecification<T> restrict(Restriction<? super T> restriction);
9597

9698
/**
9799
* Add a fetch {@linkplain Path path} to the specification.
@@ -133,7 +135,7 @@ interface Augmentation<T> {
133135
* SelectionSpecification.create(Book.class)
134136
* .augment((builder, query, book) ->
135137
* // eliminate explicit references to 'builder'
136-
* new CriteriaDefinition<>(query) {{
138+
* new CriteriaDefinition&lt;&gt;(query) {{
137139
* where(like(entity.get(BasicEntity_.title), titlePattern),
138140
* greaterThan(book.get(Book_.pages), minPages));
139141
* orderBy(asc(book.get(Book_.isbn)));
@@ -153,13 +155,22 @@ interface Augmentation<T> {
153155
* Covariant override.
154156
*/
155157
@Override
156-
SelectionQuery<T> createQuery(SharedSessionContract session);
158+
SelectionQuery<T> createQuery(Session session);
159+
160+
/**
161+
* Covariant override.
162+
*/
163+
@Override
164+
SelectionQuery<T> createQuery(StatelessSession session);
165+
166+
@Override
167+
SelectionQuery<T> createQuery(EntityManager entityManager);
157168

158169
/**
159170
* Returns a specification reference which can be used to programmatically,
160171
* iteratively build a {@linkplain SelectionQuery} for the given entity type,
161-
* allowing the addition of {@linkplain SelectionSpecification#sort sorting}
162-
* and {@linkplain SelectionSpecification#restrict restrictions}.
172+
* allowing the addition of {@linkplain #sort sorting}
173+
* and {@linkplain #restrict restrictions}.
163174
* This is effectively the same as calling {@linkplain #create(Class, String)}
164175
* with {@code "from {rootEntityType}"} as the HQL.
165176
*
@@ -175,8 +186,8 @@ static <T> SelectionSpecification<T> create(Class<T> rootEntityType) {
175186
/**
176187
* Returns a specification reference which can be used to programmatically,
177188
* iteratively build a {@linkplain SelectionQuery} based on a base HQL statement,
178-
* allowing the addition of {@linkplain SelectionSpecification#sort sorting}
179-
* and {@linkplain SelectionSpecification#restrict restrictions}.
189+
* allowing the addition of {@linkplain #sort sorting}
190+
* and {@linkplain #restrict restrictions}.
180191
*
181192
* @param hql The base HQL query.
182193
* @param resultType The result type which will ultimately be returned from the {@linkplain SelectionQuery}
@@ -194,8 +205,8 @@ static <T> SelectionSpecification<T> create(Class<T> resultType, String hql) {
194205
/**
195206
* Returns a specification reference which can be used to programmatically,
196207
* iteratively build a {@linkplain SelectionQuery} for the given criteria query,
197-
* allowing the addition of {@linkplain SelectionSpecification#sort sorting}
198-
* and {@linkplain SelectionSpecification#restrict restrictions}.
208+
* allowing the addition of {@linkplain #sort sorting}
209+
* and {@linkplain #restrict restrictions}.
199210
*
200211
* @param criteria The criteria query
201212
*

hibernate-core/src/main/java/org/hibernate/query/programmatic/internal/MutationSpecificationImpl.java

+18-1
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
*/
55
package org.hibernate.query.programmatic.internal;
66

7+
import jakarta.persistence.EntityManager;
78
import jakarta.persistence.criteria.CriteriaDelete;
89
import jakarta.persistence.criteria.CriteriaUpdate;
910
import org.hibernate.AssertionFailure;
11+
import org.hibernate.Session;
1012
import org.hibernate.SharedSessionContract;
13+
import org.hibernate.StatelessSession;
1114
import org.hibernate.engine.spi.SharedSessionContractImplementor;
1215
import org.hibernate.query.programmatic.MutationSpecification;
1316
import org.hibernate.query.IllegalMutationQueryException;
@@ -62,7 +65,7 @@ public MutationSpecificationImpl(CriteriaDelete<T> criteriaQuery) {
6265
}
6366

6467
@Override
65-
public MutationSpecification<T> restrict(Restriction<T> restriction) {
68+
public MutationSpecification<T> restrict(Restriction<? super T> restriction) {
6669
specifications.add( (sqmStatement, mutationTargetRoot) -> {
6770
final SqmPredicate sqmPredicate = (SqmPredicate) restriction.toPredicate(
6871
mutationTargetRoot,
@@ -81,6 +84,15 @@ public MutationSpecification<T> augment(Augmentation<T> augmentation) {
8184
}
8285

8386
@Override
87+
public MutationQuery createQuery(Session session) {
88+
return createQuery( (SharedSessionContract) session );
89+
}
90+
91+
@Override
92+
public MutationQuery createQuery(StatelessSession session) {
93+
return createQuery( (SharedSessionContract) session );
94+
}
95+
8496
public MutationQuery createQuery(SharedSessionContract session) {
8597
final var sessionImpl = (SharedSessionContractImplementor) session;
8698
final SqmDeleteOrUpdateStatement<T> sqmStatement;
@@ -101,6 +113,11 @@ else if ( deleteOrUpdateStatement != null ) {
101113
return new QuerySqmImpl<>( sqmStatement, true, null, sessionImpl );
102114
}
103115

116+
@Override
117+
public MutationQuery createQuery(EntityManager entityManager) {
118+
return createQuery( (SharedSessionContract) entityManager );
119+
}
120+
104121
/**
105122
* Used during construction to parse/interpret the incoming HQL
106123
* and produce the corresponding SQM tree.

hibernate-core/src/main/java/org/hibernate/query/programmatic/internal/SelectionSpecificationImpl.java

+22-5
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
*/
55
package org.hibernate.query.programmatic.internal;
66

7+
import jakarta.persistence.EntityManager;
78
import jakarta.persistence.criteria.CriteriaQuery;
89
import org.hibernate.QueryException;
10+
import org.hibernate.Session;
911
import org.hibernate.SharedSessionContract;
12+
import org.hibernate.StatelessSession;
1013
import org.hibernate.engine.spi.SharedSessionContractImplementor;
1114
import org.hibernate.query.IllegalSelectQueryException;
1215
import org.hibernate.query.Order;
@@ -64,7 +67,7 @@ public SelectionSpecificationImpl(CriteriaQuery<T> criteriaQuery) {
6467
}
6568

6669
@Override
67-
public SelectionSpecification<T> restrict(Restriction<T> restriction) {
70+
public SelectionSpecification<T> restrict(Restriction<? super T> restriction) {
6871
specifications.add( (sqmStatement, root) -> {
6972
final SqmPredicate sqmPredicate = SqmUtil.restriction( sqmStatement, resultType, restriction );
7073
sqmStatement.getQuerySpec().applyPredicate( sqmPredicate );
@@ -86,15 +89,15 @@ public SelectionSpecification<T> fetch(Path<T, ?> fetchPath) {
8689
}
8790

8891
@Override
89-
public SelectionSpecification<T> sort(Order<T> order) {
92+
public SelectionSpecification<T> sort(Order<? super T> order) {
9093
specifications.add( (sqmStatement, root) -> {
9194
addOrder( order, sqmStatement );
9295
} );
9396
return this;
9497
}
9598

9699
@Override
97-
public final SelectionSpecification<T> resort(Order<T> order) {
100+
public final SelectionSpecification<T> resort(Order<? super T> order) {
98101
specifications.add( (sqmStatement, root) -> {
99102
sqmStatement.getQuerySpec().setOrderByClause( new SqmOrderByClause() );
100103
addOrder( order, sqmStatement );
@@ -103,15 +106,15 @@ public final SelectionSpecification<T> resort(Order<T> order) {
103106
}
104107

105108
@Override
106-
public final SelectionSpecification<T> resort(List<Order<T>> orders) {
109+
public final SelectionSpecification<T> resort(List<Order<? super T>> orders) {
107110
specifications.add( (sqmStatement, root) -> {
108111
sqmStatement.getQuerySpec().setOrderByClause( new SqmOrderByClause() );
109112
orders.forEach( order -> addOrder( order, sqmStatement ) );
110113
} );
111114
return this;
112115
}
113116

114-
private static <T> void addOrder(Order<T> order, SqmSelectStatement<T> sqmStatement) {
117+
private static <T> void addOrder(Order<? super T> order, SqmSelectStatement<T> sqmStatement) {
115118
final SqmSortSpecification sortSpecification = SqmUtil.sortSpecification( sqmStatement, order );
116119
final var querySpec = sqmStatement.getQuerySpec();
117120
if ( querySpec.getOrderByClause() == null ) {
@@ -121,6 +124,15 @@ private static <T> void addOrder(Order<T> order, SqmSelectStatement<T> sqmStatem
121124
}
122125

123126
@Override
127+
public SelectionQuery<T> createQuery(Session session) {
128+
return createQuery( (SharedSessionContract) session );
129+
}
130+
131+
@Override
132+
public SelectionQuery<T> createQuery(StatelessSession session) {
133+
return createQuery( (SharedSessionContract) session );
134+
}
135+
124136
public SelectionQuery<T> createQuery(SharedSessionContract session) {
125137
final var sessionImpl = (SharedSessionContractImplementor) session;
126138
final SqmSelectStatement<T> sqmStatement;
@@ -145,6 +157,11 @@ else if ( criteriaQuery != null ) {
145157
return new SqmSelectionQueryImpl<>( sqmStatement, true, resultType, sessionImpl );
146158
}
147159

160+
@Override
161+
public SelectionQuery<T> createQuery(EntityManager entityManager) {
162+
return createQuery( (SharedSessionContract) entityManager );
163+
}
164+
148165
/**
149166
* Used during construction to parse/interpret the incoming HQL
150167
* and produce the corresponding SQM tree.

hibernate-core/src/main/java/org/hibernate/query/restriction/NamedPathElement.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import jakarta.persistence.criteria.Root;
88
import jakarta.persistence.criteria.FetchParent;
9-
9+
import jakarta.persistence.criteria.JoinType;
1010

1111
/**
1212
* A non-root element of a {@link Path}, using a stringly-typed
@@ -33,6 +33,6 @@ public jakarta.persistence.criteria.Path<V> path(Root<? extends X> root) {
3333

3434
@Override
3535
public FetchParent<?, V> fetch(Root<? extends X> root) {
36-
return parent.fetch( root ).fetch( attributeName );
36+
return parent.fetch( root ).fetch( attributeName, JoinType.LEFT );
3737
}
3838
}

hibernate-core/src/main/java/org/hibernate/query/restriction/PathElement.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import jakarta.persistence.criteria.Root;
88
import jakarta.persistence.criteria.FetchParent;
9+
import jakarta.persistence.criteria.JoinType;
910
import jakarta.persistence.metamodel.SingularAttribute;
1011

1112
/**
@@ -27,6 +28,6 @@ public jakarta.persistence.criteria.Path<V> path(Root<? extends X> root) {
2728

2829
@Override
2930
public FetchParent<?, V> fetch(Root<? extends X> root) {
30-
return parent.fetch( root ).fetch( attribute );
31+
return parent.fetch( root ).fetch( attribute, JoinType.LEFT );
3132
}
3233
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,7 @@ public static Class<?> resolveExpressibleJavaTypeClass(final SqmExpression<?> ex
947947
public static <X> SqmPredicate restriction(
948948
SqmSelectStatement<X> sqmStatement,
949949
Class<X> resultType,
950-
Restriction<X> restriction) {
950+
Restriction<? super X> restriction) {
951951
//noinspection unchecked
952952
final JpaRoot<X> root = (JpaRoot<X>) sqmStatement.getRoot( 0, resultType );
953953
return (SqmPredicate) restriction.toPredicate( root, sqmStatement.nodeBuilder() );

0 commit comments

Comments
 (0)