HHH-16276 - More readable exception for non-compliant @OrderBy expressions
This commit is contained in:
parent
e5aa1413d8
commit
eaeb7f38ae
|
@ -133,4 +133,8 @@ public class ColumnReference implements OrderingExpression, SequencePart {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toDescriptiveText() {
|
||||||
|
return "column reference (" + columnExpression + ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,4 +25,9 @@ public interface DomainPath extends OrderingExpression, SequencePart {
|
||||||
default PluralAttributeMapping getPluralAttribute() {
|
default PluralAttributeMapping getPluralAttribute() {
|
||||||
return getLhs().getPluralAttribute();
|
return getLhs().getPluralAttribute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default String toDescriptiveText() {
|
||||||
|
return "domain path (" + getNavigablePath().getFullPath() + ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,4 +120,9 @@ public class FunctionExpression implements OrderingExpression, FunctionRendering
|
||||||
}
|
}
|
||||||
sqlAppender.appendSql( ')' );
|
sqlAppender.appendSql( ')' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toDescriptiveText() {
|
||||||
|
return "function (" + name + ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ public interface OrderingExpression extends Node {
|
||||||
|
|
||||||
SqlAstNode resolve(QuerySpec ast, TableGroup tableGroup, String modelPartName, SqlAstCreationState creationState);
|
SqlAstNode resolve(QuerySpec ast, TableGroup tableGroup, String modelPartName, SqlAstCreationState creationState);
|
||||||
|
|
||||||
|
String toDescriptiveText();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply the SQL AST sort-specifications associated with this ordering-expression
|
* Apply the SQL AST sort-specifications associated with this ordering-expression
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.metamodel.mapping.ordering.ast;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.hibernate.internal.util.QuotingHelper;
|
import org.hibernate.internal.util.QuotingHelper;
|
||||||
import org.hibernate.query.sqm.NullPrecedence;
|
import org.hibernate.query.sqm.NullPrecedence;
|
||||||
|
@ -68,9 +69,12 @@ public class ParseTreeVisitor extends OrderingParserBaseVisitor<Object> {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new OrderByComplianceViolation(
|
throw new OrderByComplianceViolation(
|
||||||
"`@OrderBy` expression (" + parsedSpec.expression().getText()
|
String.format(
|
||||||
+ ") resolved to `" + orderingExpression
|
Locale.ROOT,
|
||||||
+ "` which is not a domain-model reference which violates the JPA specification"
|
"`@OrderBy` expression (%s) is not a domain-model reference, which violates the Jakarta Persistence specification - %s",
|
||||||
|
parsedSpec.expression().getText(),
|
||||||
|
orderingExpression.toDescriptiveText()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,4 +66,8 @@ public class SelfRenderingOrderingExpression extends SelfRenderingSqlFragmentExp
|
||||||
ast.addSortSpecification( new SortSpecification( sortExpression, sortOrder, nullPrecedence ) );
|
ast.addSortSpecification( new SortSpecification( sortExpression, sortOrder, nullPrecedence ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toDescriptiveText() {
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.mapping.collections.ordering;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.ElementCollection;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.OrderBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class AddressBook {
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
@Basic
|
||||||
|
private String name;
|
||||||
|
@OrderBy( "last_name" )
|
||||||
|
@ElementCollection
|
||||||
|
private Set<Contact> contacts;
|
||||||
|
|
||||||
|
private AddressBook() {
|
||||||
|
// for Hibernate use
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddressBook(Integer id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Contact> getContacts() {
|
||||||
|
return contacts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContacts(Set<Contact> contacts) {
|
||||||
|
this.contacts = contacts;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.mapping.collections.ordering;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.ElementCollection;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.OrderBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class CompliantAddressBook {
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
@Basic
|
||||||
|
private String name;
|
||||||
|
@OrderBy( "lastName" )
|
||||||
|
@ElementCollection
|
||||||
|
private Set<Contact> contacts;
|
||||||
|
|
||||||
|
private CompliantAddressBook() {
|
||||||
|
// for Hibernate use
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompliantAddressBook(Integer id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Contact> getContacts() {
|
||||||
|
return contacts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContacts(Set<Contact> contacts) {
|
||||||
|
this.contacts = contacts;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.mapping.collections.ordering;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.EnumType;
|
||||||
|
import jakarta.persistence.Enumerated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Embeddable
|
||||||
|
public class Contact {
|
||||||
|
@Basic
|
||||||
|
@Column(name = "last_name")
|
||||||
|
private String lastName;
|
||||||
|
@Basic
|
||||||
|
@Column(name = "first_name")
|
||||||
|
private String firstName;
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private TypesOfThings stuff;
|
||||||
|
public Contact(String lastName, String firstName) {
|
||||||
|
this.lastName = lastName;
|
||||||
|
this.firstName = firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastName() {
|
||||||
|
return lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastName(String lastName) {
|
||||||
|
this.lastName = lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFirstName() {
|
||||||
|
return firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFirstName(String firstName) {
|
||||||
|
this.firstName = firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypesOfThings getStuff() {
|
||||||
|
return stuff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStuff(TypesOfThings stuff) {
|
||||||
|
this.stuff = stuff;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.mapping.collections.ordering;
|
||||||
|
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.metamodel.mapping.ordering.ast.OrderByComplianceViolation;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModelScope;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class OrderByComplianceTests {
|
||||||
|
@Test
|
||||||
|
@ServiceRegistry( settings = @Setting( name= AvailableSettings.JPA_ORDER_BY_MAPPING_COMPLIANCE, value = "false" ) )
|
||||||
|
@DomainModel( annotatedClasses = { TypesOfThings.class, Contact.class, AddressBook.class } )
|
||||||
|
public void testNonCompliantBaseline(DomainModelScope scope) {
|
||||||
|
final SessionFactory sessionFactory = scope.getDomainModel().buildSessionFactory();
|
||||||
|
assertThat( sessionFactory ).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@ServiceRegistry( settings = @Setting( name= AvailableSettings.JPA_ORDER_BY_MAPPING_COMPLIANCE, value = "true" ) )
|
||||||
|
@DomainModel( annotatedClasses = { TypesOfThings.class, Contact.class, AddressBook.class } )
|
||||||
|
public void testNonCompliantStrictly(DomainModelScope scope) {
|
||||||
|
try {
|
||||||
|
final SessionFactory sessionFactory = scope.getDomainModel().buildSessionFactory();
|
||||||
|
assertThat( sessionFactory ).isNotNull();
|
||||||
|
fail( "Expecting a failure here" );
|
||||||
|
}
|
||||||
|
catch (OrderByComplianceViolation exception) {
|
||||||
|
assertThat( exception.getMessage() ).isEqualTo(
|
||||||
|
"`@OrderBy` expression (last_name) is not a domain-model reference " +
|
||||||
|
"which violates the Jakarta Persistence specification - column reference (last_name)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@ServiceRegistry( settings = @Setting( name= AvailableSettings.JPA_ORDER_BY_MAPPING_COMPLIANCE, value = "false" ) )
|
||||||
|
@DomainModel( annotatedClasses = { TypesOfThings.class, Contact.class, CompliantAddressBook.class } )
|
||||||
|
public void testCompliantBaseline(DomainModelScope scope) {
|
||||||
|
final SessionFactory sessionFactory = scope.getDomainModel().buildSessionFactory();
|
||||||
|
assertThat( sessionFactory ).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@ServiceRegistry( settings = @Setting( name= AvailableSettings.JPA_ORDER_BY_MAPPING_COMPLIANCE, value = "true" ) )
|
||||||
|
@DomainModel( annotatedClasses = { TypesOfThings.class, Contact.class, CompliantAddressBook.class } )
|
||||||
|
public void testCompliantStrictly(DomainModelScope scope) {
|
||||||
|
final SessionFactory sessionFactory = scope.getDomainModel().buildSessionFactory();
|
||||||
|
assertThat( sessionFactory ).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.mapping.collections.ordering;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public enum TypesOfThings {
|
||||||
|
PUPPIES,
|
||||||
|
RAINDROPS,
|
||||||
|
SMOKE
|
||||||
|
}
|
Loading…
Reference in New Issue