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.DomainModelHelper;
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;
/**
@ -121,9 +121,8 @@ public abstract class AbstractManagedType<J>
}
@Override
@SuppressWarnings("unchecked")
public Set<Attribute<? super J, ?>> getAttributes() {
final HashSet attributes = new LinkedHashSet( getDeclaredAttributes() );
final HashSet<Attribute<? super J, ?>> attributes = new LinkedHashSet<>( getDeclaredAttributes() );
if ( getSuperType() != null ) {
attributes.addAll( getSuperType().getAttributes() );
@ -133,39 +132,36 @@ public abstract class AbstractManagedType<J>
}
@Override
@SuppressWarnings("unchecked")
public Set<Attribute<J, ?>> getDeclaredAttributes() {
final boolean isDeclaredSingularAttributesEmpty = CollectionHelper.isEmpty( declaredSingularAttributes );
final boolean isDeclaredPluralAttributes = CollectionHelper.isEmpty( declaredPluralAttributes );
if ( isDeclaredSingularAttributesEmpty && isDeclaredPluralAttributes ) {
return Collections.emptySet();
}
final HashSet attributes;
final HashSet<Attribute<J, ?>> attributes;
if ( !isDeclaredSingularAttributesEmpty ) {
attributes = new LinkedHashSet( declaredSingularAttributes.values() );
attributes = new LinkedHashSet<>( declaredSingularAttributes.values() );
if ( !isDeclaredPluralAttributes ) {
attributes.addAll( declaredPluralAttributes.values() );
}
}
else {
attributes = new LinkedHashSet( declaredPluralAttributes.values() );
attributes = new LinkedHashSet<>( declaredPluralAttributes.values() );
}
return attributes;
}
@Override
@SuppressWarnings("unchecked")
public PersistentAttribute<? super J,?> getAttribute(String name) {
final PersistentAttribute attribute = findAttribute( name );
final PersistentAttribute<? super J,?> attribute = findAttribute( name );
checkNotNull( "Attribute", attribute, name );
return attribute;
}
@Override
@SuppressWarnings("unchecked")
public PersistentAttribute<? super J,?> findAttribute(String name) {
// first look at declared attributes
PersistentAttribute attribute = findDeclaredAttribute( name );
PersistentAttribute<? super J,?> attribute = findDeclaredAttribute( name );
if ( attribute != null ) {
return attribute;
}
@ -177,20 +173,18 @@ public abstract class AbstractManagedType<J>
}
}
for ( ManagedDomainType subType : subTypes ) {
for ( ManagedDomainType<?> subType : subTypes ) {
PersistentAttribute subTypeAttribute = subType.findSubTypesAttribute( name );
if ( subTypeAttribute != null ) {
if ( attribute != null && !isCompatible( attribute, subTypeAttribute ) ) {
throw new IllegalArgumentException(
new SemanticException(
String.format(
Locale.ROOT,
"Could not resolve attribute '%s' of '%s' due to the attribute being declared in multiple subtypes: ['%s', '%s']",
name,
getTypeName(),
attribute.getDeclaringType().getTypeName(),
subTypeAttribute.getDeclaringType().getTypeName()
)
throw new PathException(
String.format(
Locale.ROOT,
"Could not resolve attribute '%s' of '%s' due to the attribute being declared in multiple subtypes: '%s', '%s'",
name,
getTypeName(),
attribute.getDeclaringType().getTypeName(),
subTypeAttribute.getDeclaringType().getTypeName()
)
);
}
@ -236,12 +230,12 @@ public abstract class AbstractManagedType<J>
@Override
public PersistentAttribute<? super J, ?> findSubTypesAttribute(String name) {
// first look at declared attributes
PersistentAttribute attribute = findDeclaredAttribute( name );
PersistentAttribute<? super J,?> attribute = findDeclaredAttribute( name );
if ( attribute != null ) {
return attribute;
}
for ( ManagedDomainType subType : subTypes ) {
for ( ManagedDomainType<? extends J> subType : subTypes ) {
PersistentAttribute subTypeAttribute = subType.findAttribute( name );
if ( subTypeAttribute != null ) {
return subTypeAttribute;
@ -252,10 +246,9 @@ public abstract class AbstractManagedType<J>
}
@Override
@SuppressWarnings("unchecked")
public PersistentAttribute<J,?> findDeclaredAttribute(String name) {
// try singular attribute
PersistentAttribute attribute = declaredSingularAttributes.get( name );
PersistentAttribute<J,?> attribute = declaredSingularAttributes.get( name );
if ( attribute != null ) {
return attribute;
}
@ -274,9 +267,8 @@ public abstract class AbstractManagedType<J>
}
@Override
@SuppressWarnings("unchecked")
public PersistentAttribute<J,?> getDeclaredAttribute(String name) {
PersistentAttribute attr = findDeclaredAttribute( name );
PersistentAttribute<J,?> attr = findDeclaredAttribute( name );
checkNotNull( "Attribute", attr, name );
return attr;
}
@ -304,9 +296,8 @@ public abstract class AbstractManagedType<J>
// Singular attributes
@Override
@SuppressWarnings("unchecked")
public Set<SingularAttribute<? super J, ?>> getSingularAttributes() {
HashSet attributes = new HashSet<>( declaredSingularAttributes.values() );
HashSet<SingularAttribute<? super J, ?>> attributes = new HashSet<>( declaredSingularAttributes.values() );
if ( getSuperType() != null ) {
attributes.addAll( getSuperType().getSingularAttributes() );
}
@ -319,17 +310,15 @@ public abstract class AbstractManagedType<J>
}
@Override
@SuppressWarnings("unchecked")
public SingularPersistentAttribute<? super J, ?> getSingularAttribute(String name) {
SingularPersistentAttribute attribute = findSingularAttribute( name );
SingularPersistentAttribute<? super J, ?> attribute = findSingularAttribute( name );
checkNotNull( "SingularAttribute", attribute, name );
return attribute;
}
@Override
@SuppressWarnings("unchecked")
public SingularPersistentAttribute<? super J, ?> findSingularAttribute(String name) {
SingularPersistentAttribute attribute = findDeclaredSingularAttribute( name );
SingularPersistentAttribute<? super J, ?> attribute = findDeclaredSingularAttribute( name );
if ( attribute == null && getSuperType() != null ) {
attribute = getSuperType().findSingularAttribute( name );
}
@ -339,7 +328,7 @@ public abstract class AbstractManagedType<J>
@Override
@SuppressWarnings("unchecked")
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 );
return (SingularPersistentAttribute) attribute;
}
@ -362,7 +351,7 @@ public abstract class AbstractManagedType<J>
public <Y> SingularPersistentAttribute<J, Y> getDeclaredSingularAttribute(String name, Class<Y> javaType) {
final SingularAttribute attr = findDeclaredSingularAttribute( name );
checkTypeForSingleAttribute( attr, name, javaType );
return (SingularPersistentAttribute) attr;
return (SingularPersistentAttribute<J, Y>) attr;
}
private <Y> void checkTypeForSingleAttribute(
@ -747,7 +736,6 @@ public abstract class AbstractManagedType<J>
protected class InFlightAccessImpl implements InFlightAccess<J> {
@Override
@SuppressWarnings("unchecked")
public void addAttribute(PersistentAttribute<J,?> attribute) {
if ( attribute instanceof SingularPersistentAttribute ) {
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.query.ReturnableType;
import org.hibernate.query.TerminalPathException;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmPath;
@ -43,7 +44,8 @@ public class BasicSqmPathSource<J>
@Override
public SqmPathSource<?> findSubPathSource(String name) {
throw new IllegalStateException( "Basic paths cannot be dereferenced" );
throw new TerminalPathException( "Path '" + pathModel.getPathName()
+ "' has no attribute '" + name + "'" );
}
@Override

View File

@ -152,7 +152,7 @@ public class SingularAttributeImpl<D,J>
}
//noinspection unchecked
return new SqmSingularJoin(
return new SqmSingularJoin<D,J>(
lhs,
this,
alias,
@ -166,7 +166,7 @@ public class SingularAttributeImpl<D,J>
public NavigablePath createNavigablePath(SqmPath parent, String alias) {
if ( parent == null ) {
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();
@ -216,7 +216,7 @@ public class SingularAttributeImpl<D,J>
public NavigablePath createNavigablePath(SqmPath parent, String alias) {
if ( parent == null ) {
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();
@ -280,7 +280,7 @@ public class SingularAttributeImpl<D,J>
@Override
public boolean isAssociation() {
return getPersistentAttributeType() == PersistentAttributeType.MANY_TO_ONE
|| getPersistentAttributeType() == PersistentAttributeType.ONE_TO_ONE;
|| getPersistentAttributeType() == PersistentAttributeType.ONE_TO_ONE;
}
@Override

View File

@ -209,7 +209,7 @@ import org.hibernate.persister.internal.SqlFragmentPredicate;
import org.hibernate.persister.spi.PersisterCreationContext;
import org.hibernate.property.access.spi.PropertyAccess;
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.spi.QueryOptions;
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.ColumnReference;
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.from.NamedTableReference;
import org.hibernate.sql.ast.tree.from.StandardTableGroup;
@ -5718,22 +5717,20 @@ public abstract class AbstractEntityPersister
final ModelPart subDefinedAttribute = subMappingType.findSubTypesSubPart( name, treatTargetType );
if ( subDefinedAttribute != null ) {
if ( attribute != null && !MappingModelHelper.isCompatibleModelPart( attribute, subDefinedAttribute ) ) {
throw new IllegalArgumentException(
new SemanticException(
String.format(
Locale.ROOT,
"Could not resolve attribute '%s' of '%s' due to the attribute being declared in multiple subtypes: ['%s', '%s']",
name,
getJavaType().getJavaType().getTypeName(),
attribute.asAttributeMapping().getDeclaringType()
.getJavaType()
.getJavaType()
.getTypeName(),
subDefinedAttribute.asAttributeMapping().getDeclaringType()
.getJavaType()
.getJavaType()
.getTypeName()
)
throw new PathException(
String.format(
Locale.ROOT,
"Could not resolve attribute '%s' of '%s' due to the attribute being declared in multiple subtypes: '%s', '%s'",
name,
getJavaType().getJavaType().getTypeName(),
attribute.asAttributeMapping().getDeclaringType()
.getJavaType()
.getJavaType()
.getTypeName(),
subDefinedAttribute.asAttributeMapping().getDeclaringType()
.getJavaType()
.getJavaType()
.getTypeName()
)
);
}

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
*
* @author Steve Ebersole
*
* @see PathElementException
* @see TerminalPathException
*/
public class PathException extends HibernateException {
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 org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.query.SemanticException;
import org.hibernate.query.PathElementException;
import org.hibernate.spi.NavigablePath;
import org.hibernate.query.sqm.tree.SqmExpressibleAccessor;
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.
*
* 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
*/
@ -56,14 +56,12 @@ public interface SqmPathSource<J> extends SqmExpressible<J>, Bindable<J>, SqmExp
default SqmPathSource<?> getSubPathSource(String name) {
final SqmPathSource<?> subPathSource = findSubPathSource( name );
if ( subPathSource == null ) {
throw new IllegalArgumentException(
new SemanticException(
String.format(
Locale.ROOT,
"Could not resolve attribute '%s' of '%s'",
name,
getExpressible().getTypeName()
)
throw new PathElementException(
String.format(
Locale.ROOT,
"Could not resolve attribute '%s' of '%s'",
name,
getExpressible().getTypeName()
)
);
}

View File

@ -9,7 +9,6 @@ package org.hibernate.query.sqm.tree.domain;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.spi.NavigablePath;
import org.hibernate.query.PathException;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmPathSource;
@ -52,16 +51,6 @@ public class NonAggregatedCompositeSimplePath<T> extends SqmEntityValuedSimplePa
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
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitNonAggregatedCompositeValuedPath( this );
@ -70,7 +59,7 @@ public class NonAggregatedCompositeSimplePath<T> extends SqmEntityValuedSimplePa
@Override
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" );
}
}