diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java index 8963691ec8..f2aafa5671 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java @@ -1286,10 +1286,10 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem } } - @SuppressWarnings("rawtypes") private EntityDomainType getResultEntity() { final JpaMetamodelImplementor jpaMetamodel = creationContext.getJpaMetamodel(); if ( expectedResultEntity != null ) { + @SuppressWarnings("rawtypes") final EntityDomainType entityDescriptor = jpaMetamodel.entity( expectedResultEntity ); if ( entityDescriptor == null ) { throw new SemanticException( "Query has no 'from' clause, and the result type '" @@ -1331,7 +1331,8 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem // we found an entity with the alias 'this' // assigned explicitly, JPA says we should // infer the select list 'select this' - SqmSelectClause selectClause = new SqmSelectClause( false, 1, nodeBuilder ); + final SqmSelectClause selectClause = + new SqmSelectClause( false, 1, nodeBuilder ); selectClause.addSelection( new SqmSelection<>( sqmRoot, "this", nodeBuilder) ); return selectClause; } @@ -1353,7 +1354,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem // we may safely assume the query returns that entity if ( fromClause.getNumberOfRoots() == 1 ) { final SqmRoot sqmRoot = fromClause.getRoots().get(0); - if ( sqmRoot.hasTrueJoin() ) { + if ( sqmRoot.hasImplicitlySelectableJoin() ) { // the entity has joins, and doesn't explicitly have // the alias 'this', so the 'select' list cannot be // inferred @@ -1365,7 +1366,8 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem // 'this', and that we should infer 'select this', but we // accept even the case where the entity has an explicit // alias, and infer 'select explicit_alias' - SqmSelectClause selectClause = new SqmSelectClause( false, 1, nodeBuilder ); + final SqmSelectClause selectClause = + new SqmSelectClause( false, 1, nodeBuilder ); selectClause.addSelection( new SqmSelection<>( sqmRoot, sqmRoot.getAlias(), nodeBuilder) ); return selectClause; } @@ -1398,7 +1400,8 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem else { // exactly one root entity, return it // (joined entities are not returned) - final SqmSelectClause selectClause = new SqmSelectClause( false, 1, nodeBuilder ); + final SqmSelectClause selectClause = + new SqmSelectClause( false, 1, nodeBuilder ); selectClause.addSelection( new SqmSelection<>( sqmRoot, sqmRoot.getAlias(), nodeBuilder) ); return selectClause; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmAttributeJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmAttributeJoin.java index ca46098b98..f1827326b4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmAttributeJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmAttributeJoin.java @@ -12,7 +12,6 @@ import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.criteria.JpaPredicate; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SemanticQueryWalker; -import org.hibernate.query.sqm.SqmJoinable; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.spi.SqmCreationHelper; import org.hibernate.query.sqm.tree.SqmJoinType; @@ -33,48 +32,38 @@ public abstract class AbstractSqmAttributeJoin extends AbstractSqmJoin implements SqmAttributeJoin { - private boolean fetched; + private final boolean implicitJoin; + private boolean fetchJoin; - @SuppressWarnings({ "rawtypes", "unchecked" }) - public AbstractSqmAttributeJoin( - SqmFrom lhs, - SqmJoinable joinedNavigable, - String alias, - SqmJoinType joinType, - boolean fetched, - NodeBuilder nodeBuilder) { - //noinspection StringEquality - this( - lhs, - joinedNavigable.createNavigablePath( lhs, alias ), - joinedNavigable, - alias == SqmCreationHelper.IMPLICIT_ALIAS ? null : alias, - joinType, - fetched, - nodeBuilder - ); - } - - @SuppressWarnings("rawtypes") protected AbstractSqmAttributeJoin( SqmFrom lhs, NavigablePath navigablePath, - SqmJoinable joinedNavigable, + SqmPathSource joinedNavigable, String alias, SqmJoinType joinType, - boolean fetched, + boolean fetchJoin, NodeBuilder nodeBuilder) { - //noinspection unchecked super( navigablePath, - (SqmPathSource) joinedNavigable, + joinedNavigable, lhs, - alias, + isImplicitAlias( alias ) ? null : alias, joinType, nodeBuilder ); - this.fetched = fetched; + this.fetchJoin = fetchJoin; validateFetchAlias( alias ); + implicitJoin = isImplicitAlias( alias ); //TODO: add a parameter + } + + @SuppressWarnings("StringEquality") + private static boolean isImplicitAlias(String alias) { + return alias == SqmCreationHelper.IMPLICIT_ALIAS; + } + + @Override + public boolean isImplicitJoin() { + return implicitJoin; } @Override @@ -89,7 +78,7 @@ public abstract class AbstractSqmAttributeJoin @Override public boolean isFetched() { - return fetched; + return fetchJoin; } @Override @@ -100,11 +89,11 @@ public abstract class AbstractSqmAttributeJoin @Override public void clearFetched() { - fetched = false; + fetchJoin = false; } private void validateFetchAlias(String alias) { - if ( fetched && alias != null && nodeBuilder().isJpaQueryComplianceEnabled() ) { + if ( fetchJoin && alias != null && nodeBuilder().isJpaQueryComplianceEnabled() ) { throw new IllegalStateException( "The JPA specification does not permit specifying an alias for fetch joins." ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java index 9227309323..1d25c8d882 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java @@ -60,7 +60,6 @@ import jakarta.persistence.metamodel.PluralAttribute; import jakarta.persistence.metamodel.SetAttribute; import jakarta.persistence.metamodel.SingularAttribute; -import static org.hibernate.metamodel.AttributeClassification.EMBEDDED; import static org.hibernate.query.sqm.internal.SqmUtil.findCompatibleFetchJoin; /** @@ -163,9 +162,8 @@ public abstract class AbstractSqmFrom extends AbstractSqmPath implements SqmPath resolvedPath = null; for ( SqmJoin sqmJoin : getSqmJoins() ) { // We can only match singular joins here, as plural path parts are interpreted like sub-queries - if ( sqmJoin instanceof SqmSingularJoin + if ( sqmJoin instanceof SqmSingularJoin attributeJoin && name.equals( sqmJoin.getReferencedPathSource().getPathName() ) ) { - final SqmAttributeJoin attributeJoin = (SqmAttributeJoin) sqmJoin; if ( attributeJoin.getOn() == null ) { // todo (6.0): to match the expectation of the JPA spec I think we also have to check // that the join type is INNER or the default join type for the attribute, @@ -223,8 +221,7 @@ public abstract class AbstractSqmFrom extends AbstractSqmPath implements public void removeLeftFetchJoins() { if ( joins != null ) { for ( SqmJoin join : new ArrayList<>(joins) ) { - if ( join instanceof SqmAttributeJoin ) { - final SqmAttributeJoin attributeJoin = (SqmAttributeJoin) join; + if ( join instanceof SqmAttributeJoin attributeJoin ) { if ( attributeJoin.isFetched() ) { if ( join.getSqmJoinType() == SqmJoinType.LEFT ) { joins.remove( join ); @@ -306,11 +303,10 @@ public abstract class AbstractSqmFrom extends AbstractSqmPath implements } @Override - public boolean hasTrueJoin() { + public boolean hasImplicitlySelectableJoin() { return getSqmJoins().stream() .anyMatch( sqmJoin -> sqmJoin instanceof SqmAttributeJoin attributeJoin - && !attributeJoin.isFetched() - && attributeJoin.getAttribute().getAttributeClassification()!=EMBEDDED ); + && attributeJoin.isImplicitlySelectable() ); } @Override @@ -642,8 +638,7 @@ public abstract class AbstractSqmFrom extends AbstractSqmPath implements @Override public JpaCrossJoin crossJoin(EntityDomainType entity) { - //noinspection unchecked - final SqmCrossJoin crossJoin = new SqmCrossJoin<>( entity, null, (SqmRoot) findRoot() ); + final SqmCrossJoin crossJoin = new SqmCrossJoin<>( entity, null, findRoot() ); // noinspection unchecked addSqmJoin( (SqmJoin) crossJoin ); return crossJoin; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPluralJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPluralJoin.java index e24e787ac5..96f36b1eb6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPluralJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPluralJoin.java @@ -35,7 +35,15 @@ public abstract class AbstractSqmPluralJoin SqmJoinType joinType, boolean fetched, NodeBuilder nodeBuilder) { - super( lhs, joinedNavigable, alias, joinType, fetched, nodeBuilder ); + super( + lhs, + joinedNavigable.createNavigablePath( lhs, alias ), + joinedNavigable, + alias, + joinType, + fetched, + nodeBuilder + ); } protected AbstractSqmPluralJoin( diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmSingularJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmSingularJoin.java index 97bf66c955..0aea46d9e9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmSingularJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmSingularJoin.java @@ -15,7 +15,6 @@ import org.hibernate.metamodel.model.domain.TreatableDomainType; import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.spi.NavigablePath; import org.hibernate.query.sqm.NodeBuilder; -import org.hibernate.query.sqm.SqmJoinable; import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmJoinType; import org.hibernate.query.sqm.tree.from.SqmFrom; @@ -25,6 +24,7 @@ import org.hibernate.query.sqm.tree.from.SqmTreatedAttributeJoin; * @author Steve Ebersole */ public class SqmSingularJoin extends AbstractSqmAttributeJoin implements SqmSingularValuedJoin { + public SqmSingularJoin( SqmFrom lhs, SingularPersistentAttribute joinedNavigable, @@ -32,17 +32,15 @@ public class SqmSingularJoin extends AbstractSqmAttributeJoin implemen SqmJoinType joinType, boolean fetched, NodeBuilder nodeBuilder) { - super( lhs, joinedNavigable, alias, joinType, fetched, nodeBuilder ); - } - - public SqmSingularJoin( - SqmFrom lhs, - SqmJoinable joinedNavigable, - String alias, - SqmJoinType joinType, - boolean fetched, - NodeBuilder nodeBuilder) { - super( lhs, joinedNavigable, alias, joinType, fetched, nodeBuilder ); + super( + lhs, + joinedNavigable.createNavigablePath( lhs, alias ), + joinedNavigable, + alias, + joinType, + fetched, + nodeBuilder + ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmAttributeJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmAttributeJoin.java index 556a01d819..77fbbddd03 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmAttributeJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmAttributeJoin.java @@ -30,7 +30,7 @@ public interface SqmAttributeJoin extends SqmJoin, JpaFetch, JpaJ @Override default boolean isImplicitlySelectable() { - return !isFetched(); + return !isFetched() && !isImplicitJoin(); } @Override @@ -39,8 +39,16 @@ public interface SqmAttributeJoin extends SqmJoin, JpaFetch, JpaJ @Override JavaType getJavaTypeDescriptor(); + /** + * Is this a fetch join? + */ boolean isFetched(); + /** + * Is this an implicit join inferred from a path expression? + */ + boolean isImplicitJoin(); + @Internal void clearFetched(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java index d32024576f..0e06c6f7e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java @@ -102,7 +102,7 @@ public interface SqmFrom extends SqmVisitableNode, SqmPath, JpaFrom SqmEntityJoin join(Class entityClass, JoinType joinType); @Incubating - boolean hasTrueJoin(); + boolean hasImplicitlySelectableJoin(); @Override SqmSingularJoin join(SingularAttribute attribute);