more cosmetic improvements to HQL error reporting

makes the messages and exception types a bit more consistent
This commit is contained in:
Gavin King 2022-01-08 10:43:03 +01:00
parent 60ad64b2a6
commit e331c2870e
6 changed files with 53 additions and 32 deletions

View File

@ -118,7 +118,7 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
// identifier is an alias (identification variable) // identifier is an alias (identification variable)
if ( isTerminal ) { if ( isTerminal ) {
throw new SemanticException( "Cannot join to root : " + identifier ); throw new SemanticException( "Cannot join to root '" + identifier + "'" );
} }
return new AttributeJoinDelegate( return new AttributeJoinDelegate(
@ -181,9 +181,9 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
throw new HqlInterpretationException( throw new HqlInterpretationException(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"Could not locate specified joinable path : %s -> %s", "Could not resolve joined attribute '%s' of '%s'",
lhs.getNavigablePath(), name,
name lhs.getNavigablePath()
) )
); );
} }

View File

@ -423,7 +423,10 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final SqmRoot<R> root = visitTargetEntity( dmlTargetContext ); final SqmRoot<R> root = visitTargetEntity( dmlTargetContext );
if ( root.getReferencedPathSource() instanceof SqmPolymorphicRootDescriptor<?> ) { if ( root.getReferencedPathSource() instanceof SqmPolymorphicRootDescriptor<?> ) {
throw new SemanticException( throw new SemanticException(
"Can't create an INSERT for a non entity name: " + root.getReferencedPathSource().getHibernateEntityName() String.format(
"Target type '%s' in insert statement is not an entity",
root.getReferencedPathSource().getHibernateEntityName()
)
); );
} }
@ -511,7 +514,10 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final SqmRoot<R> root = visitTargetEntity( dmlTargetContext ); final SqmRoot<R> root = visitTargetEntity( dmlTargetContext );
if ( root.getReferencedPathSource() instanceof SqmPolymorphicRootDescriptor<?> ) { if ( root.getReferencedPathSource() instanceof SqmPolymorphicRootDescriptor<?> ) {
throw new SemanticException( throw new SemanticException(
"Can't create an UPDATE for a non entity name: " + root.getReferencedPathSource().getHibernateEntityName() String.format(
"Target type '%s' in update statement is not an entity",
root.getReferencedPathSource().getHibernateEntityName()
)
); );
} }
@ -779,7 +785,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
sqmQueryPart.setFetchExpression( visitLimitClause( limitClauseContext ) ); sqmQueryPart.setFetchExpression( visitLimitClause( limitClauseContext ) );
} }
else { else {
throw new SemanticException("Can't use both, limit and fetch clause!" ); throw new SemanticException("Can't use both limit and fetch clause" );
} }
} }
} }
@ -961,7 +967,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
); );
} }
catch (ClassLoadingException e) { catch (ClassLoadingException e) {
throw new SemanticException( "Unable to resolve class named for dynamic instantiation : " + className ); throw new SemanticException( "Could not resolve class '" + className + "' named for instantiation" );
} }
} }
else { else {
@ -1362,7 +1368,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
.getJpaMetamodel() .getJpaMetamodel()
.getHqlEntityReference( entityName ); .getHqlEntityReference( entityName );
if ( entityReference == null ) { if ( entityReference == null ) {
throw new UnknownEntityException( "Could not resolve entity name [" + entityName + "] as DML target", entityName ); throw new UnknownEntityException( "Could not resolve target entity '" + entityName + "'", entityName );
} }
checkFQNEntityNameJpaComplianceViolationIfNeeded( entityName, entityReference ); checkFQNEntityNameJpaComplianceViolationIfNeeded( entityName, entityReference );
if ( entityReference instanceof SqmPolymorphicRootDescriptor<?> && getCreationOptions().useStrictJpaCompliance() ) { if ( entityReference instanceof SqmPolymorphicRootDescriptor<?> && getCreationOptions().useStrictJpaCompliance() ) {
@ -1476,7 +1482,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
} }
throw new SemanticException( "Could not resolve entity or correlation path '" + name + "'" ); throw new SemanticException( "Could not resolve entity or correlation path '" + name + "'" );
} }
throw new SemanticException( "Could not resolve entity '" + name + "'" ); throw new UnknownEntityException( "Could not resolve root entity '" + name + "'", name );
} }
checkFQNEntityNameJpaComplianceViolationIfNeeded( name, entityDescriptor ); checkFQNEntityNameJpaComplianceViolationIfNeeded( name, entityDescriptor );
@ -1491,7 +1497,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
if ( processingStateStack.depth() > 1 ) { if ( processingStateStack.depth() > 1 ) {
throw new SemanticException( throw new SemanticException(
"Illegal implicit-polymorphic domain path in sub-query : " + entityDescriptor.getName() "Illegal implicit-polymorphic domain path in subquery '" + entityDescriptor.getName() +"'"
); );
} }
} }
@ -2140,7 +2146,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
throw new NotYetImplementedFor6Exception( "Path continuation from `id()` reference not yet implemented" ); throw new NotYetImplementedFor6Exception( "Path continuation from `id()` reference not yet implemented" );
} }
throw new SemanticException( "Path does not reference an identifiable-type : " + sqmPath.getNavigablePath().getFullPath() ); throw new SemanticException( "Path does not resolve to an entity type '" + sqmPath.getNavigablePath().getFullPath() + "'" );
} }
@Override @Override
@ -2159,15 +2165,17 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final SingularPersistentAttribute<Object, ?> versionAttribute = identifiableType.findVersionAttribute(); final SingularPersistentAttribute<Object, ?> versionAttribute = identifiableType.findVersionAttribute();
if ( versionAttribute == null ) { if ( versionAttribute == null ) {
throw new SemanticException( throw new SemanticException(
"`" + sqmPath.getNavigablePath().getFullPath() + "` resolved to an identifiable-type (`" + String.format(
identifiableType.getTypeName() + "`) which does not define a version" "Path '%s' resolved to entity type '%s' which does not define a version",
sqmPath.getNavigablePath().getFullPath(), identifiableType.getTypeName()
)
); );
} }
return sqmPath.get( versionAttribute ); return sqmPath.get( versionAttribute );
} }
throw new SemanticException( "Path does not reference an identifiable-type : " + sqmPath.getNavigablePath().getFullPath() ); throw new SemanticException( "Path does not resolve to an entity type '" + sqmPath.getNavigablePath().getFullPath() + "'" );
} }
@Override @Override
@ -2186,14 +2194,18 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final List<? extends PersistentAttribute<Object, ?>> attributes = identifiableType.findNaturalIdAttributes(); final List<? extends PersistentAttribute<Object, ?>> attributes = identifiableType.findNaturalIdAttributes();
if ( attributes == null ) { if ( attributes == null ) {
throw new SemanticException( throw new SemanticException(
"`" + sqmPath.getNavigablePath().getFullPath() + "` resolved to an identifiable-type (`" + String.format(
identifiableType.getTypeName() + "`) which does not define a natural id" "Path '%s' resolved to entity type '%s' which does not define a natural id",
sqmPath.getNavigablePath().getFullPath(), identifiableType.getTypeName()
)
); );
} }
else if ( attributes.size() >1 ) { else if ( attributes.size() >1 ) {
throw new SemanticException( throw new SemanticException(
"`" + sqmPath.getNavigablePath().getFullPath() + "` resolved to an identifiable-type (`" + String.format(
identifiableType.getTypeName() + "`) which defines multiple natural ids" "Path '%s' resolved to entity type '%s' which defines multiple natural ids",
sqmPath.getNavigablePath().getFullPath(), identifiableType.getTypeName()
)
); );
} }
@ -2203,7 +2215,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
return sqmPath.get( naturalIdAttribute ); return sqmPath.get( naturalIdAttribute );
} }
throw new SemanticException( "Path does not reference an identifiable-type : " + sqmPath.getNavigablePath().getFullPath() ); throw new SemanticException( "Path does not resolve to an entity type '" + sqmPath.getNavigablePath().getFullPath() + "'" );
} }
@Override @Override
@ -3501,7 +3513,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
public Object visitFormat(HqlParser.FormatContext ctx) { public Object visitFormat(HqlParser.FormatContext ctx) {
String format = QuotingHelper.unquoteStringLiteral( ctx.getChild( 0 ).getText() ); String format = QuotingHelper.unquoteStringLiteral( ctx.getChild( 0 ).getText() );
if (!FORMAT.matcher(format).matches()) { if (!FORMAT.matcher(format).matches()) {
throw new SemanticException("illegal format pattern: '" + format + "'"); throw new SemanticException("illegal format pattern '" + format + "'");
} }
return new SqmFormat( return new SqmFormat(
format, format,
@ -3681,7 +3693,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
if ( !(referencedPathSource instanceof PluralPersistentAttribute ) ) { if ( !(referencedPathSource instanceof PluralPersistentAttribute ) ) {
throw new PathException( throw new PathException(
"Illegal attempt to treat non-plural path as a plural path : " + pluralAttributePath.getNavigablePath() "Path is not a plural path '" + pluralAttributePath.getNavigablePath() + "'"
); );
} }
final SqmSubQuery<?> subQuery = new SqmSubQuery<>( final SqmSubQuery<?> subQuery = new SqmSubQuery<>(
@ -3809,7 +3821,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final String padCharText = ctx.STRING_LITERAL().getText(); final String padCharText = ctx.STRING_LITERAL().getText();
if ( padCharText.length() != 3 ) { if ( padCharText.length() != 3 ) {
throw new SemanticException( "Pad character for pad() function must be single character, found: " + padCharText ); throw new SemanticException( "Pad character for pad() function must be single character, found '" + padCharText + "'" );
} }
return new SqmLiteral<>( return new SqmLiteral<>(
@ -3878,7 +3890,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
: " "; // JPA says space is the default : " "; // JPA says space is the default
if ( trimCharText.length() != 1 ) { if ( trimCharText.length() != 1 ) {
throw new SemanticException( "Trim character for trim() function must be single character, found: " + trimCharText ); throw new SemanticException( "Trim character for trim() function must be single character, found '" + trimCharText + "'" );
} }
return new SqmLiteral<>( return new SqmLiteral<>(
@ -4181,10 +4193,15 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
public SqmPath<?> visitCollectionElementNavigablePath(HqlParser.CollectionElementNavigablePathContext ctx) { public SqmPath<?> visitCollectionElementNavigablePath(HqlParser.CollectionElementNavigablePathContext ctx) {
final SqmPath<?> pluralAttributePath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) ); final SqmPath<?> pluralAttributePath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) );
final SqmPathSource<?> referencedPathSource = pluralAttributePath.getReferencedPathSource(); final SqmPathSource<?> referencedPathSource = pluralAttributePath.getReferencedPathSource();
final TerminalNode firstNode = (TerminalNode) ctx.getChild( 0 );
if ( !(referencedPathSource instanceof PluralPersistentAttribute<?, ?, ?> ) ) { if ( !(referencedPathSource instanceof PluralPersistentAttribute<?, ?, ?> ) ) {
throw new PathException( throw new PathException(
"Illegal attempt to treat non-plural path as a plural path : " + pluralAttributePath.getNavigablePath() String.format(
"Argument of '%s' is not a plural path '%s'",
firstNode.getSymbol().getText(),
pluralAttributePath.getNavigablePath()
)
); );
} }
@ -4194,7 +4211,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
if ( attribute.getCollectionClassification() != CollectionClassification.MAP ) { if ( attribute.getCollectionClassification() != CollectionClassification.MAP ) {
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.VALUE_FUNCTION_ON_NON_MAP ); throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.VALUE_FUNCTION_ON_NON_MAP );
} }
final TerminalNode firstNode = (TerminalNode) ctx.getChild( 0 );
if ( firstNode.getSymbol().getType() == HqlParser.ELEMENTS ) { if ( firstNode.getSymbol().getType() == HqlParser.ELEMENTS ) {
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION ); throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION );
} }
@ -4219,8 +4235,13 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final SqmPathSource<?> referencedPathSource = pluralAttributePath.getReferencedPathSource(); final SqmPathSource<?> referencedPathSource = pluralAttributePath.getReferencedPathSource();
if ( !(referencedPathSource instanceof PluralPersistentAttribute<?, ?, ?> ) ) { if ( !(referencedPathSource instanceof PluralPersistentAttribute<?, ?, ?> ) ) {
final TerminalNode firstNode = (TerminalNode) ctx.getChild( 0 );
throw new PathException( throw new PathException(
"Illegal attempt to treat non-plural path as a plural path : " + pluralAttributePath.getNavigablePath() String.format(
"Argument of '%s' is not a plural path '%s'",
firstNode.getSymbol().getText(),
pluralAttributePath.getNavigablePath()
)
); );
} }

View File

@ -22,7 +22,7 @@ public class UnknownEntityException extends SemanticException {
private final String entityName; private final String entityName;
public UnknownEntityException(String entityName) { public UnknownEntityException(String entityName) {
this( "Unable to resolve [" + entityName + "] as entity", entityName ); this( "Could not resolve entity '" + entityName + "'", entityName );
} }
public UnknownEntityException(String message, String entityName) { public UnknownEntityException(String message, String entityName) {

View File

@ -15,8 +15,8 @@ import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment; import org.hibernate.cfg.Environment;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.SemanticException;
import org.hibernate.query.sqm.UnknownEntityException;
import org.hibernate.test.annotations.Boat; import org.hibernate.test.annotations.Boat;
import org.hibernate.test.annotations.Ferry; import org.hibernate.test.annotations.Ferry;
import org.hibernate.test.annotations.Port; import org.hibernate.test.annotations.Port;
@ -68,7 +68,7 @@ public class ConfigurationTest {
fail( "Boat should not be mapped" ); fail( "Boat should not be mapped" );
} }
catch (IllegalArgumentException expected) { catch (IllegalArgumentException expected) {
assertEquals( SemanticException.class, expected.getCause().getClass() ); assertEquals( UnknownEntityException.class, expected.getCause().getClass() );
// expected outcome // expected outcome
// see org.hibernate.test.jpa.compliance.tck2_2.QueryApiTest#testInvalidQueryMarksTxnForRollback // see org.hibernate.test.jpa.compliance.tck2_2.QueryApiTest#testInvalidQueryMarksTxnForRollback

View File

@ -44,7 +44,7 @@ public class LoaderWithInvalidQueryTest extends BaseEntityManagerFunctionalTestC
Throwable[] suppressed = rootCause.getSuppressed(); Throwable[] suppressed = rootCause.getSuppressed();
assertEquals( 2, suppressed.length ); assertEquals( 2, suppressed.length );
assertTrue( ExceptionUtil.rootCause( suppressed[0] ).getMessage().contains( "Could not resolve attribute 'valid'" ) ); assertTrue( ExceptionUtil.rootCause( suppressed[0] ).getMessage().contains( "Could not resolve attribute 'valid'" ) );
assertTrue( ExceptionUtil.rootCause( suppressed[1] ).getMessage().contains( "Could not resolve entity '_Person'" ) ); assertTrue( ExceptionUtil.rootCause( suppressed[1] ).getMessage().contains( "Could not resolve root entity '_Person'" ) );
} }
} }

View File

@ -76,7 +76,7 @@ public class MappedSuperclassInheritanceTest extends BaseEntityManagerFunctional
fail(); fail();
} catch (Exception expected) { } catch (Exception expected) {
SemanticException rootException = (SemanticException) ExceptionUtil.rootCause( expected); SemanticException rootException = (SemanticException) ExceptionUtil.rootCause( expected);
assertEquals("Could not resolve entity 'Employee'", rootException.getMessage()); assertEquals("Could not resolve root entity 'Employee'", rootException.getMessage());
} }
} ); } );
} }