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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toDescriptiveText() {
|
||||
return "column reference (" + columnExpression + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,4 +25,9 @@ public interface DomainPath extends OrderingExpression, SequencePart {
|
|||
default PluralAttributeMapping 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( ')' );
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
String toDescriptiveText();
|
||||
|
||||
/**
|
||||
* 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.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.internal.util.QuotingHelper;
|
||||
import org.hibernate.query.sqm.NullPrecedence;
|
||||
|
@ -68,9 +69,12 @@ public class ParseTreeVisitor extends OrderingParserBaseVisitor<Object> {
|
|||
}
|
||||
else {
|
||||
throw new OrderByComplianceViolation(
|
||||
"`@OrderBy` expression (" + parsedSpec.expression().getText()
|
||||
+ ") resolved to `" + orderingExpression
|
||||
+ "` which is not a domain-model reference which violates the JPA specification"
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"`@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 ) );
|
||||
}
|
||||
|
||||
@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