HHH-16776 more consistent reporting of errors in attribute paths

and squash some warnings
This commit is contained in:
Gavin 2023-06-09 17:46:39 +02:00 committed by Gavin King
parent 9075cf84fb
commit 5110fd4653
9 changed files with 109 additions and 82 deletions

View File

@ -39,7 +39,7 @@ import org.hibernate.metamodel.mapping.MappingModelHelper;
import org.hibernate.metamodel.model.domain.internal.AttributeContainer; import org.hibernate.metamodel.model.domain.internal.AttributeContainer;
import org.hibernate.metamodel.model.domain.internal.DomainModelHelper; import org.hibernate.metamodel.model.domain.internal.DomainModelHelper;
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor; import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
import org.hibernate.query.SemanticException; import org.hibernate.query.PathException;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
/** /**
@ -121,9 +121,8 @@ public abstract class AbstractManagedType<J>
} }
@Override @Override
@SuppressWarnings("unchecked")
public Set<Attribute<? super J, ?>> getAttributes() { public Set<Attribute<? super J, ?>> getAttributes() {
final HashSet attributes = new LinkedHashSet( getDeclaredAttributes() ); final HashSet<Attribute<? super J, ?>> attributes = new LinkedHashSet<>( getDeclaredAttributes() );
if ( getSuperType() != null ) { if ( getSuperType() != null ) {
attributes.addAll( getSuperType().getAttributes() ); attributes.addAll( getSuperType().getAttributes() );
@ -133,39 +132,36 @@ public abstract class AbstractManagedType<J>
} }
@Override @Override
@SuppressWarnings("unchecked")
public Set<Attribute<J, ?>> getDeclaredAttributes() { public Set<Attribute<J, ?>> getDeclaredAttributes() {
final boolean isDeclaredSingularAttributesEmpty = CollectionHelper.isEmpty( declaredSingularAttributes ); final boolean isDeclaredSingularAttributesEmpty = CollectionHelper.isEmpty( declaredSingularAttributes );
final boolean isDeclaredPluralAttributes = CollectionHelper.isEmpty( declaredPluralAttributes ); final boolean isDeclaredPluralAttributes = CollectionHelper.isEmpty( declaredPluralAttributes );
if ( isDeclaredSingularAttributesEmpty && isDeclaredPluralAttributes ) { if ( isDeclaredSingularAttributesEmpty && isDeclaredPluralAttributes ) {
return Collections.emptySet(); return Collections.emptySet();
} }
final HashSet attributes; final HashSet<Attribute<J, ?>> attributes;
if ( !isDeclaredSingularAttributesEmpty ) { if ( !isDeclaredSingularAttributesEmpty ) {
attributes = new LinkedHashSet( declaredSingularAttributes.values() ); attributes = new LinkedHashSet<>( declaredSingularAttributes.values() );
if ( !isDeclaredPluralAttributes ) { if ( !isDeclaredPluralAttributes ) {
attributes.addAll( declaredPluralAttributes.values() ); attributes.addAll( declaredPluralAttributes.values() );
} }
} }
else { else {
attributes = new LinkedHashSet( declaredPluralAttributes.values() ); attributes = new LinkedHashSet<>( declaredPluralAttributes.values() );
} }
return attributes; return attributes;
} }
@Override @Override
@SuppressWarnings("unchecked")
public PersistentAttribute<? super J,?> getAttribute(String name) { public PersistentAttribute<? super J,?> getAttribute(String name) {
final PersistentAttribute attribute = findAttribute( name ); final PersistentAttribute<? super J,?> attribute = findAttribute( name );
checkNotNull( "Attribute", attribute, name ); checkNotNull( "Attribute", attribute, name );
return attribute; return attribute;
} }
@Override @Override
@SuppressWarnings("unchecked")
public PersistentAttribute<? super J,?> findAttribute(String name) { public PersistentAttribute<? super J,?> findAttribute(String name) {
// first look at declared attributes // first look at declared attributes
PersistentAttribute attribute = findDeclaredAttribute( name ); PersistentAttribute<? super J,?> attribute = findDeclaredAttribute( name );
if ( attribute != null ) { if ( attribute != null ) {
return attribute; return attribute;
} }
@ -177,21 +173,19 @@ public abstract class AbstractManagedType<J>
} }
} }
for ( ManagedDomainType subType : subTypes ) { for ( ManagedDomainType<?> subType : subTypes ) {
PersistentAttribute subTypeAttribute = subType.findSubTypesAttribute( name ); PersistentAttribute subTypeAttribute = subType.findSubTypesAttribute( name );
if ( subTypeAttribute != null ) { if ( subTypeAttribute != null ) {
if ( attribute != null && !isCompatible( attribute, subTypeAttribute ) ) { if ( attribute != null && !isCompatible( attribute, subTypeAttribute ) ) {
throw new IllegalArgumentException( throw new PathException(
new SemanticException(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"Could not resolve attribute '%s' of '%s' due to the attribute being declared in multiple subtypes: ['%s', '%s']", "Could not resolve attribute '%s' of '%s' due to the attribute being declared in multiple subtypes: '%s', '%s'",
name, name,
getTypeName(), getTypeName(),
attribute.getDeclaringType().getTypeName(), attribute.getDeclaringType().getTypeName(),
subTypeAttribute.getDeclaringType().getTypeName() subTypeAttribute.getDeclaringType().getTypeName()
) )
)
); );
} }
attribute = subTypeAttribute; attribute = subTypeAttribute;
@ -236,12 +230,12 @@ public abstract class AbstractManagedType<J>
@Override @Override
public PersistentAttribute<? super J, ?> findSubTypesAttribute(String name) { public PersistentAttribute<? super J, ?> findSubTypesAttribute(String name) {
// first look at declared attributes // first look at declared attributes
PersistentAttribute attribute = findDeclaredAttribute( name ); PersistentAttribute<? super J,?> attribute = findDeclaredAttribute( name );
if ( attribute != null ) { if ( attribute != null ) {
return attribute; return attribute;
} }
for ( ManagedDomainType subType : subTypes ) { for ( ManagedDomainType<? extends J> subType : subTypes ) {
PersistentAttribute subTypeAttribute = subType.findAttribute( name ); PersistentAttribute subTypeAttribute = subType.findAttribute( name );
if ( subTypeAttribute != null ) { if ( subTypeAttribute != null ) {
return subTypeAttribute; return subTypeAttribute;
@ -252,10 +246,9 @@ public abstract class AbstractManagedType<J>
} }
@Override @Override
@SuppressWarnings("unchecked")
public PersistentAttribute<J,?> findDeclaredAttribute(String name) { public PersistentAttribute<J,?> findDeclaredAttribute(String name) {
// try singular attribute // try singular attribute
PersistentAttribute attribute = declaredSingularAttributes.get( name ); PersistentAttribute<J,?> attribute = declaredSingularAttributes.get( name );
if ( attribute != null ) { if ( attribute != null ) {
return attribute; return attribute;
} }
@ -274,9 +267,8 @@ public abstract class AbstractManagedType<J>
} }
@Override @Override
@SuppressWarnings("unchecked")
public PersistentAttribute<J,?> getDeclaredAttribute(String name) { public PersistentAttribute<J,?> getDeclaredAttribute(String name) {
PersistentAttribute attr = findDeclaredAttribute( name ); PersistentAttribute<J,?> attr = findDeclaredAttribute( name );
checkNotNull( "Attribute", attr, name ); checkNotNull( "Attribute", attr, name );
return attr; return attr;
} }
@ -304,9 +296,8 @@ public abstract class AbstractManagedType<J>
// Singular attributes // Singular attributes
@Override @Override
@SuppressWarnings("unchecked")
public Set<SingularAttribute<? super J, ?>> getSingularAttributes() { public Set<SingularAttribute<? super J, ?>> getSingularAttributes() {
HashSet attributes = new HashSet<>( declaredSingularAttributes.values() ); HashSet<SingularAttribute<? super J, ?>> attributes = new HashSet<>( declaredSingularAttributes.values() );
if ( getSuperType() != null ) { if ( getSuperType() != null ) {
attributes.addAll( getSuperType().getSingularAttributes() ); attributes.addAll( getSuperType().getSingularAttributes() );
} }
@ -319,17 +310,15 @@ public abstract class AbstractManagedType<J>
} }
@Override @Override
@SuppressWarnings("unchecked")
public SingularPersistentAttribute<? super J, ?> getSingularAttribute(String name) { public SingularPersistentAttribute<? super J, ?> getSingularAttribute(String name) {
SingularPersistentAttribute attribute = findSingularAttribute( name ); SingularPersistentAttribute<? super J, ?> attribute = findSingularAttribute( name );
checkNotNull( "SingularAttribute", attribute, name ); checkNotNull( "SingularAttribute", attribute, name );
return attribute; return attribute;
} }
@Override @Override
@SuppressWarnings("unchecked")
public SingularPersistentAttribute<? super J, ?> findSingularAttribute(String name) { public SingularPersistentAttribute<? super J, ?> findSingularAttribute(String name) {
SingularPersistentAttribute attribute = findDeclaredSingularAttribute( name ); SingularPersistentAttribute<? super J, ?> attribute = findDeclaredSingularAttribute( name );
if ( attribute == null && getSuperType() != null ) { if ( attribute == null && getSuperType() != null ) {
attribute = getSuperType().findSingularAttribute( name ); attribute = getSuperType().findSingularAttribute( name );
} }
@ -339,7 +328,7 @@ public abstract class AbstractManagedType<J>
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <Y> SingularPersistentAttribute<? super J, Y> getSingularAttribute(String name, Class<Y> type) { public <Y> SingularPersistentAttribute<? super J, Y> getSingularAttribute(String name, Class<Y> type) {
SingularAttribute attribute = findSingularAttribute( name ); SingularAttribute<? super J, ?> attribute = findSingularAttribute( name );
checkTypeForSingleAttribute( attribute, name, type ); checkTypeForSingleAttribute( attribute, name, type );
return (SingularPersistentAttribute) attribute; return (SingularPersistentAttribute) attribute;
} }
@ -362,7 +351,7 @@ public abstract class AbstractManagedType<J>
public <Y> SingularPersistentAttribute<J, Y> getDeclaredSingularAttribute(String name, Class<Y> javaType) { public <Y> SingularPersistentAttribute<J, Y> getDeclaredSingularAttribute(String name, Class<Y> javaType) {
final SingularAttribute attr = findDeclaredSingularAttribute( name ); final SingularAttribute attr = findDeclaredSingularAttribute( name );
checkTypeForSingleAttribute( attr, name, javaType ); checkTypeForSingleAttribute( attr, name, javaType );
return (SingularPersistentAttribute) attr; return (SingularPersistentAttribute<J, Y>) attr;
} }
private <Y> void checkTypeForSingleAttribute( private <Y> void checkTypeForSingleAttribute(
@ -747,7 +736,6 @@ public abstract class AbstractManagedType<J>
protected class InFlightAccessImpl implements InFlightAccess<J> { protected class InFlightAccessImpl implements InFlightAccess<J> {
@Override @Override
@SuppressWarnings("unchecked")
public void addAttribute(PersistentAttribute<J,?> attribute) { public void addAttribute(PersistentAttribute<J,?> attribute) {
if ( attribute instanceof SingularPersistentAttribute ) { if ( attribute instanceof SingularPersistentAttribute ) {
declaredSingularAttributes.put( attribute.getName(), (SingularPersistentAttribute<J, ?>) attribute ); declaredSingularAttributes.put( attribute.getName(), (SingularPersistentAttribute<J, ?>) attribute );

View File

@ -8,6 +8,7 @@ package org.hibernate.metamodel.model.domain.internal;
import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.query.ReturnableType; import org.hibernate.query.ReturnableType;
import org.hibernate.query.TerminalPathException;
import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath; import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.query.sqm.tree.domain.SqmPath;
@ -43,7 +44,8 @@ public class BasicSqmPathSource<J>
@Override @Override
public SqmPathSource<?> findSubPathSource(String name) { public SqmPathSource<?> findSubPathSource(String name) {
throw new IllegalStateException( "Basic paths cannot be dereferenced" ); throw new TerminalPathException( "Path '" + pathModel.getPathName()
+ "' has no attribute '" + name + "'" );
} }
@Override @Override

View File

@ -152,7 +152,7 @@ public class SingularAttributeImpl<D,J>
} }
//noinspection unchecked //noinspection unchecked
return new SqmSingularJoin( return new SqmSingularJoin<D,J>(
lhs, lhs,
this, this,
alias, alias,
@ -166,7 +166,7 @@ public class SingularAttributeImpl<D,J>
public NavigablePath createNavigablePath(SqmPath parent, String alias) { public NavigablePath createNavigablePath(SqmPath parent, String alias) {
if ( parent == null ) { if ( parent == null ) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"`lhs` cannot be null for a sub-navigable reference - " + getName() "LHS cannot be null for a sub-navigable reference - " + getName()
); );
} }
final SqmPathSource<?> parentPathSource = parent.getReferencedPathSource(); final SqmPathSource<?> parentPathSource = parent.getReferencedPathSource();
@ -216,7 +216,7 @@ public class SingularAttributeImpl<D,J>
public NavigablePath createNavigablePath(SqmPath parent, String alias) { public NavigablePath createNavigablePath(SqmPath parent, String alias) {
if ( parent == null ) { if ( parent == null ) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"`lhs` cannot be null for a sub-navigable reference - " + getName() "LHS cannot be null for a sub-navigable reference - " + getName()
); );
} }
NavigablePath navigablePath = parent.getNavigablePath(); NavigablePath navigablePath = parent.getNavigablePath();

View File

@ -209,7 +209,7 @@ import org.hibernate.persister.internal.SqlFragmentPredicate;
import org.hibernate.persister.spi.PersisterCreationContext; import org.hibernate.persister.spi.PersisterCreationContext;
import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.property.access.spi.Setter; import org.hibernate.property.access.spi.Setter;
import org.hibernate.query.SemanticException; import org.hibernate.query.PathException;
import org.hibernate.query.named.NamedQueryMemento; import org.hibernate.query.named.NamedQueryMemento;
import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.sql.internal.SQLQueryParser; import org.hibernate.query.sql.internal.SQLQueryParser;
@ -235,7 +235,6 @@ import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.AliasedExpression; import org.hibernate.sql.ast.tree.expression.AliasedExpression;
import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.expression.QueryLiteral; import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.from.NamedTableReference; import org.hibernate.sql.ast.tree.from.NamedTableReference;
import org.hibernate.sql.ast.tree.from.StandardTableGroup; import org.hibernate.sql.ast.tree.from.StandardTableGroup;
@ -5718,11 +5717,10 @@ public abstract class AbstractEntityPersister
final ModelPart subDefinedAttribute = subMappingType.findSubTypesSubPart( name, treatTargetType ); final ModelPart subDefinedAttribute = subMappingType.findSubTypesSubPart( name, treatTargetType );
if ( subDefinedAttribute != null ) { if ( subDefinedAttribute != null ) {
if ( attribute != null && !MappingModelHelper.isCompatibleModelPart( attribute, subDefinedAttribute ) ) { if ( attribute != null && !MappingModelHelper.isCompatibleModelPart( attribute, subDefinedAttribute ) ) {
throw new IllegalArgumentException( throw new PathException(
new SemanticException(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"Could not resolve attribute '%s' of '%s' due to the attribute being declared in multiple subtypes: ['%s', '%s']", "Could not resolve attribute '%s' of '%s' due to the attribute being declared in multiple subtypes: '%s', '%s'",
name, name,
getJavaType().getJavaType().getTypeName(), getJavaType().getJavaType().getTypeName(),
attribute.asAttributeMapping().getDeclaringType() attribute.asAttributeMapping().getDeclaringType()
@ -5734,7 +5732,6 @@ public abstract class AbstractEntityPersister
.getJavaType() .getJavaType()
.getTypeName() .getTypeName()
) )
)
); );
} }
attribute = subDefinedAttribute; attribute = subDefinedAttribute;

View File

@ -0,0 +1,25 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query;
/**
* Indicates that an element of a path did not resolve to
* a mapped program element.
*
* @apiNote extends {@link IllegalArgumentException} to
* satisfy a questionable requirement of the JPA criteria
* query API
*
* @since 6.3
*
* @author Gavin King
*/
public class PathElementException extends IllegalArgumentException {
public PathElementException(String message) {
super(message);
}
}

View File

@ -12,6 +12,9 @@ import org.hibernate.HibernateException;
* Indicates an attempt to use a path in an unsupported way * Indicates an attempt to use a path in an unsupported way
* *
* @author Steve Ebersole * @author Steve Ebersole
*
* @see PathElementException
* @see TerminalPathException
*/ */
public class PathException extends HibernateException { public class PathException extends HibernateException {
public PathException(String message) { public PathException(String message) {

View File

@ -0,0 +1,25 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query;
/**
* Indicates an attempt to dereference a terminal path
* (usually a path referring to something of basic type)
*
* @apiNote extends {@link IllegalStateException} to
* satisfy a questionable requirement of the JPA criteria
* query API
*
* @since 6.3
*
* @author Gavin King
*/
public class TerminalPathException extends IllegalStateException {
public TerminalPathException(String message) {
super(message);
}
}

View File

@ -11,7 +11,7 @@ import java.util.Locale;
import jakarta.persistence.metamodel.Bindable; import jakarta.persistence.metamodel.Bindable;
import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.query.SemanticException; import org.hibernate.query.PathElementException;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.query.sqm.tree.SqmExpressibleAccessor; import org.hibernate.query.sqm.tree.SqmExpressibleAccessor;
import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.query.sqm.tree.domain.SqmPath;
@ -41,7 +41,7 @@ public interface SqmPathSource<J> extends SqmExpressible<J>, Bindable<J>, SqmExp
/** /**
* Find a SqmPathSource by name relative to this source. * Find a SqmPathSource by name relative to this source.
* *
* returns null if the subPathSource is not found * @return null if the subPathSource is not found
* *
* @throws IllegalStateException to indicate that this source cannot be de-referenced * @throws IllegalStateException to indicate that this source cannot be de-referenced
*/ */
@ -56,15 +56,13 @@ public interface SqmPathSource<J> extends SqmExpressible<J>, Bindable<J>, SqmExp
default SqmPathSource<?> getSubPathSource(String name) { default SqmPathSource<?> getSubPathSource(String name) {
final SqmPathSource<?> subPathSource = findSubPathSource( name ); final SqmPathSource<?> subPathSource = findSubPathSource( name );
if ( subPathSource == null ) { if ( subPathSource == null ) {
throw new IllegalArgumentException( throw new PathElementException(
new SemanticException(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"Could not resolve attribute '%s' of '%s'", "Could not resolve attribute '%s' of '%s'",
name, name,
getExpressible().getTypeName() getExpressible().getTypeName()
) )
)
); );
} }
return subPathSource; return subPathSource;

View File

@ -9,7 +9,6 @@ package org.hibernate.query.sqm.tree.domain;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.query.PathException; import org.hibernate.query.PathException;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.SqmPathSource;
@ -52,16 +51,6 @@ public class NonAggregatedCompositeSimplePath<T> extends SqmEntityValuedSimplePa
return path; return path;
} }
@Override
public SqmPath<?> resolvePathPart(
String name,
boolean isTerminal,
SqmCreationState creationState) {
final SqmPath<?> sqmPath = get( name );
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
return sqmPath;
}
@Override @Override
public <X> X accept(SemanticQueryWalker<X> walker) { public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitNonAggregatedCompositeValuedPath( this ); return walker.visitNonAggregatedCompositeValuedPath( this );
@ -70,7 +59,7 @@ public class NonAggregatedCompositeSimplePath<T> extends SqmEntityValuedSimplePa
@Override @Override
public <S extends T> SqmTreatedPath<T, S> treatAs(EntityDomainType<S> treatTarget) throws PathException { public <S extends T> SqmTreatedPath<T, S> treatAs(EntityDomainType<S> treatTarget) throws PathException {
throw new PathException( "Non Aggregate composite paths cannot be TREAT-ed" ); throw new PathException( "Non-aggregate composite paths cannot be TREAT-ed" );
} }
} }