Skip to content

HHH-19364 changes to Specifications to support Hibernate Processor #10066

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.Root;
import org.hibernate.Incubating;
import org.hibernate.SharedSessionContract;
import org.hibernate.Session;
import org.hibernate.StatelessSession;
import org.hibernate.query.IllegalMutationQueryException;
import org.hibernate.query.MutationQuery;
import org.hibernate.query.SelectionQuery;
Expand Down Expand Up @@ -43,7 +44,7 @@ public interface MutationSpecification<T> extends QuerySpecification<T> {
* Covariant override.
*/
@Override
MutationSpecification<T> restrict(Restriction<T> restriction);
MutationSpecification<T> restrict(Restriction<? super T> restriction);

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

/**
* Finalize the building and create the {@linkplain SelectionQuery} instance.
* Finalize the building and create the {@linkplain MutationQuery} instance.
*/
@Override
MutationQuery createQuery(SharedSessionContract session);
MutationQuery createQuery(Session session);

/**
* Finalize the building and create the {@linkplain MutationQuery} instance.
*/
@Override
MutationQuery createQuery(StatelessSession session);

/**
* Returns a specification reference which can be used to programmatically,
* iteratively build a {@linkplain MutationQuery} based on a base HQL statement,
* allowing the addition of {@linkplain MutationSpecification#restrict restrictions}.
* allowing the addition of {@linkplain #restrict restrictions}.
*
* @param hql The base HQL query (expected to be an {@code update} or {@code delete} query).
* @param mutationTarget The entity which is the target of the mutation.
Expand All @@ -91,7 +98,7 @@ static <T> MutationSpecification<T> create(Class<T> mutationTarget, String hql)
/**
* Returns a specification reference which can be used to programmatically,
* iteratively build a {@linkplain MutationQuery} based on the given criteria update,
* allowing the addition of {@linkplain MutationSpecification#restrict restrictions}.
* allowing the addition of {@linkplain #restrict restrictions}.
*
* @param criteriaUpdate The criteria update query
*
Expand All @@ -104,7 +111,7 @@ static <T> MutationSpecification<T> create(CriteriaUpdate<T> criteriaUpdate) {
/**
* Returns a specification reference which can be used to programmatically,
* iteratively build a {@linkplain MutationQuery} based on the given criteria delete,
* allowing the addition of {@linkplain MutationSpecification#restrict restrictions}.
* allowing the addition of {@linkplain #restrict restrictions}.
*
* @param criteriaDelete The criteria delete query
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
*/
package org.hibernate.query.programmatic;

import jakarta.persistence.EntityManager;

import org.hibernate.Incubating;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.SharedSessionContract;
import org.hibernate.StatelessSession;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.CommonQueryContract;
import org.hibernate.query.restriction.Restriction;
Expand All @@ -33,12 +36,22 @@
*
* @return {@code this} for method chaining.
*/
QuerySpecification<T> restrict(Restriction<T> restriction);
QuerySpecification<T> restrict(Restriction<? super T> restriction);

/**
* Finalize the building and create executable query instance.
*/
CommonQueryContract createQuery(Session session);

/**
* Finalize the building and create executable query instance.
*/
CommonQueryContract createQuery(StatelessSession session);

/**
* Finalize the building and create executable query instance.
*/
CommonQueryContract createQuery(SharedSessionContract session);
CommonQueryContract createQuery(EntityManager entityManager);

Check notice

Code scanning / CodeQL

Confusing overloading of methods Note

Method QuerySpecification.createQuery(..) could be confused with overloaded method
createQuery
, since dispatch depends on static types.

/**
* Validate the query.
Expand All @@ -47,7 +60,9 @@
// Extremely temporary implementation.
// We don't actually want to open a session here,
// nor create an instance of CommonQueryContract.
try ( var session = ((SessionFactoryImplementor) factory).openTemporarySession() ) {
final SessionFactoryImplementor factoryImplementor =
(SessionFactoryImplementor) factory;
try ( var session = factoryImplementor.openTemporarySession() ) {
createQuery( session );
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
*/
package org.hibernate.query.programmatic;

import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.Root;
import org.hibernate.Incubating;
import org.hibernate.SharedSessionContract;
import org.hibernate.Session;
import org.hibernate.StatelessSession;
import org.hibernate.query.IllegalSelectQueryException;
import org.hibernate.query.Order;
import org.hibernate.query.SelectionQuery;
Expand Down Expand Up @@ -63,7 +65,7 @@ public interface SelectionSpecification<T> extends QuerySpecification<T> {
*
* @return {@code this} for method chaining.
*/
SelectionSpecification<T> sort(Order<T> order);
SelectionSpecification<T> sort(Order<? super T> order);

/**
* Sets the ordering for this selection specification.
Expand All @@ -74,7 +76,7 @@ public interface SelectionSpecification<T> extends QuerySpecification<T> {
*
* @return {@code this} for method chaining.
*/
SelectionSpecification<T> resort(Order<T> order);
SelectionSpecification<T> resort(Order<? super T> order);

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

/**
* Covariant override.
*/
@Override
SelectionSpecification<T> restrict(Restriction<T> restriction);
SelectionSpecification<T> restrict(Restriction<? super T> restriction);

/**
* Add a fetch {@linkplain Path path} to the specification.
Expand Down Expand Up @@ -133,7 +135,7 @@ interface Augmentation<T> {
* SelectionSpecification.create(Book.class)
* .augment((builder, query, book) ->
* // eliminate explicit references to 'builder'
* new CriteriaDefinition<>(query) {{
* new CriteriaDefinition&lt;&gt;(query) {{
* where(like(entity.get(BasicEntity_.title), titlePattern),
* greaterThan(book.get(Book_.pages), minPages));
* orderBy(asc(book.get(Book_.isbn)));
Expand All @@ -153,13 +155,22 @@ interface Augmentation<T> {
* Covariant override.
*/
@Override
SelectionQuery<T> createQuery(SharedSessionContract session);
SelectionQuery<T> createQuery(Session session);

/**
* Covariant override.
*/
@Override
SelectionQuery<T> createQuery(StatelessSession session);

@Override
SelectionQuery<T> createQuery(EntityManager entityManager);

/**
* Returns a specification reference which can be used to programmatically,
* iteratively build a {@linkplain SelectionQuery} for the given entity type,
* allowing the addition of {@linkplain SelectionSpecification#sort sorting}
* and {@linkplain SelectionSpecification#restrict restrictions}.
* allowing the addition of {@linkplain #sort sorting}
* and {@linkplain #restrict restrictions}.
* This is effectively the same as calling {@linkplain #create(Class, String)}
* with {@code "from {rootEntityType}"} as the HQL.
*
Expand All @@ -175,8 +186,8 @@ static <T> SelectionSpecification<T> create(Class<T> rootEntityType) {
/**
* Returns a specification reference which can be used to programmatically,
* iteratively build a {@linkplain SelectionQuery} based on a base HQL statement,
* allowing the addition of {@linkplain SelectionSpecification#sort sorting}
* and {@linkplain SelectionSpecification#restrict restrictions}.
* allowing the addition of {@linkplain #sort sorting}
* and {@linkplain #restrict restrictions}.
*
* @param hql The base HQL query.
* @param resultType The result type which will ultimately be returned from the {@linkplain SelectionQuery}
Expand All @@ -194,8 +205,8 @@ static <T> SelectionSpecification<T> create(Class<T> resultType, String hql) {
/**
* Returns a specification reference which can be used to programmatically,
* iteratively build a {@linkplain SelectionQuery} for the given criteria query,
* allowing the addition of {@linkplain SelectionSpecification#sort sorting}
* and {@linkplain SelectionSpecification#restrict restrictions}.
* allowing the addition of {@linkplain #sort sorting}
* and {@linkplain #restrict restrictions}.
*
* @param criteria The criteria query
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
*/
package org.hibernate.query.programmatic.internal;

import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaUpdate;
import org.hibernate.AssertionFailure;
import org.hibernate.Session;
import org.hibernate.SharedSessionContract;
import org.hibernate.StatelessSession;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.query.programmatic.MutationSpecification;
import org.hibernate.query.IllegalMutationQueryException;
Expand Down Expand Up @@ -62,7 +65,7 @@
}

@Override
public MutationSpecification<T> restrict(Restriction<T> restriction) {
public MutationSpecification<T> restrict(Restriction<? super T> restriction) {
specifications.add( (sqmStatement, mutationTargetRoot) -> {
final SqmPredicate sqmPredicate = (SqmPredicate) restriction.toPredicate(
mutationTargetRoot,
Expand All @@ -81,6 +84,15 @@
}

@Override
public MutationQuery createQuery(Session session) {
return createQuery( (SharedSessionContract) session );
}

@Override
public MutationQuery createQuery(StatelessSession session) {
return createQuery( (SharedSessionContract) session );
}

public MutationQuery createQuery(SharedSessionContract session) {
final var sessionImpl = (SharedSessionContractImplementor) session;
final SqmDeleteOrUpdateStatement<T> sqmStatement;
Expand All @@ -101,6 +113,11 @@
return new QuerySqmImpl<>( sqmStatement, true, null, sessionImpl );
}

@Override
public MutationQuery createQuery(EntityManager entityManager) {

Check notice

Code scanning / CodeQL

Confusing overloading of methods Note

Method MutationSpecificationImpl.createQuery(..) could be confused with overloaded method
createQuery
, since dispatch depends on static types.
return createQuery( (SharedSessionContract) entityManager );
}

/**
* Used during construction to parse/interpret the incoming HQL
* and produce the corresponding SQM tree.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
*/
package org.hibernate.query.programmatic.internal;

import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaQuery;
import org.hibernate.QueryException;
import org.hibernate.Session;
import org.hibernate.SharedSessionContract;
import org.hibernate.StatelessSession;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.query.IllegalSelectQueryException;
import org.hibernate.query.Order;
Expand Down Expand Up @@ -64,7 +67,7 @@
}

@Override
public SelectionSpecification<T> restrict(Restriction<T> restriction) {
public SelectionSpecification<T> restrict(Restriction<? super T> restriction) {
specifications.add( (sqmStatement, root) -> {
final SqmPredicate sqmPredicate = SqmUtil.restriction( sqmStatement, resultType, restriction );
sqmStatement.getQuerySpec().applyPredicate( sqmPredicate );
Expand All @@ -86,15 +89,15 @@
}

@Override
public SelectionSpecification<T> sort(Order<T> order) {
public SelectionSpecification<T> sort(Order<? super T> order) {
specifications.add( (sqmStatement, root) -> {
addOrder( order, sqmStatement );
} );
return this;
}

@Override
public final SelectionSpecification<T> resort(Order<T> order) {
public final SelectionSpecification<T> resort(Order<? super T> order) {
specifications.add( (sqmStatement, root) -> {
sqmStatement.getQuerySpec().setOrderByClause( new SqmOrderByClause() );
addOrder( order, sqmStatement );
Expand All @@ -103,15 +106,15 @@
}

@Override
public final SelectionSpecification<T> resort(List<Order<T>> orders) {
public final SelectionSpecification<T> resort(List<Order<? super T>> orders) {
specifications.add( (sqmStatement, root) -> {
sqmStatement.getQuerySpec().setOrderByClause( new SqmOrderByClause() );
orders.forEach( order -> addOrder( order, sqmStatement ) );
} );
return this;
}

private static <T> void addOrder(Order<T> order, SqmSelectStatement<T> sqmStatement) {
private static <T> void addOrder(Order<? super T> order, SqmSelectStatement<T> sqmStatement) {
final SqmSortSpecification sortSpecification = SqmUtil.sortSpecification( sqmStatement, order );
final var querySpec = sqmStatement.getQuerySpec();
if ( querySpec.getOrderByClause() == null ) {
Expand All @@ -121,6 +124,15 @@
}

@Override
public SelectionQuery<T> createQuery(Session session) {
return createQuery( (SharedSessionContract) session );
}

@Override
public SelectionQuery<T> createQuery(StatelessSession session) {
return createQuery( (SharedSessionContract) session );
}

public SelectionQuery<T> createQuery(SharedSessionContract session) {
final var sessionImpl = (SharedSessionContractImplementor) session;
final SqmSelectStatement<T> sqmStatement;
Expand All @@ -145,6 +157,11 @@
return new SqmSelectionQueryImpl<>( sqmStatement, true, resultType, sessionImpl );
}

@Override
public SelectionQuery<T> createQuery(EntityManager entityManager) {

Check notice

Code scanning / CodeQL

Confusing overloading of methods Note

Method SelectionSpecificationImpl.createQuery(..) could be confused with overloaded method
createQuery
, since dispatch depends on static types.
return createQuery( (SharedSessionContract) entityManager );
}

/**
* Used during construction to parse/interpret the incoming HQL
* and produce the corresponding SQM tree.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.FetchParent;

import jakarta.persistence.criteria.JoinType;

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

@Override
public FetchParent<?, V> fetch(Root<? extends X> root) {
return parent.fetch( root ).fetch( attributeName );
return parent.fetch( root ).fetch( attributeName, JoinType.LEFT );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.FetchParent;
import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.metamodel.SingularAttribute;

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

@Override
public FetchParent<?, V> fetch(Root<? extends X> root) {
return parent.fetch( root ).fetch( attribute );
return parent.fetch( root ).fetch( attribute, JoinType.LEFT );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -947,7 +947,7 @@ public static Class<?> resolveExpressibleJavaTypeClass(final SqmExpression<?> ex
public static <X> SqmPredicate restriction(
SqmSelectStatement<X> sqmStatement,
Class<X> resultType,
Restriction<X> restriction) {
Restriction<? super X> restriction) {
//noinspection unchecked
final JpaRoot<X> root = (JpaRoot<X>) sqmStatement.getRoot( 0, resultType );
return (SqmPredicate) restriction.toPredicate( root, sqmStatement.nodeBuilder() );
Expand Down