diff --git a/integration/spring-data/base-3.1/src/main/java/com/blazebit/persistence/spring/data/base/EntityViewSortUtil.java b/integration/spring-data/base-3.1/src/main/java/com/blazebit/persistence/spring/data/base/EntityViewSortUtil.java index ba8211f74e..42fc68494e 100644 --- a/integration/spring-data/base-3.1/src/main/java/com/blazebit/persistence/spring/data/base/EntityViewSortUtil.java +++ b/integration/spring-data/base-3.1/src/main/java/com/blazebit/persistence/spring/data/base/EntityViewSortUtil.java @@ -16,7 +16,13 @@ package com.blazebit.persistence.spring.data.base; +import jakarta.persistence.metamodel.Attribute; +import jakarta.persistence.metamodel.ManagedType; + import com.blazebit.persistence.FullQueryBuilder; +import com.blazebit.persistence.parser.expression.ExpressionFactory; +import com.blazebit.persistence.parser.expression.PathElementExpression; +import com.blazebit.persistence.parser.expression.PathExpression; import com.blazebit.persistence.view.EntityViewManager; import com.blazebit.persistence.view.metamodel.ManagedViewType; import com.blazebit.persistence.view.metamodel.MethodAttribute; @@ -82,6 +88,24 @@ public static void applySort(EntityViewManager evm, Class entityViewClass, Fu for (Sort.Order order : sort) { String entityViewAttributeAlias; if ((entityViewAttributeAlias = EntityViewSortUtil.resolveViewAttributeSelectAlias(viewType, order.getProperty())) == null) { + PathExpression pathExpression; + try { + pathExpression = cb.getService(ExpressionFactory.class).createPathExpression(order.getProperty()); + } catch (RuntimeException ex) { + throw new IllegalArgumentException("Sort order [" + order.getProperty() + "] is not resolvable to a path expression.", ex); + } + jakarta.persistence.metamodel.Type resultType = cb.getMetamodel().entity(viewType.getEntityClass()); + for (PathElementExpression expression : pathExpression.getExpressions()) { + if (!(resultType instanceof ManagedType)) { + throw new IllegalArgumentException("Sort order [" + order.getProperty() + "] is not resolvable to a valid path expression, because the type [" + resultType.getJavaType().getName() + "] can't be de-referenced."); + } + ManagedType managedType = (ManagedType) resultType; + Attribute attribute = managedType.getAttribute(expression.toString()); + if (!(attribute instanceof jakarta.persistence.metamodel.SingularAttribute)) { + throw new IllegalArgumentException("Sort order [" + order.getProperty() + "] is not resolvable to a valid path expression, because the type [" + resultType.getJavaType().getName() + "] does not contain a singular attribute named [" + expression + "]."); + } + resultType = ( (jakarta.persistence.metamodel.SingularAttribute) attribute ).getType(); + } cb.orderBy(order.getProperty(), order.isAscending(), order.getNullHandling() == Sort.NullHandling.NULLS_FIRST); } else { cb.orderBy(entityViewAttributeAlias, order.isAscending(), order.getNullHandling() == Sort.NullHandling.NULLS_FIRST); diff --git a/integration/spring-data/base/src/main/java/com/blazebit/persistence/spring/data/base/EntityViewSortUtil.java b/integration/spring-data/base/src/main/java/com/blazebit/persistence/spring/data/base/EntityViewSortUtil.java index 200add4d50..5c123c7b46 100644 --- a/integration/spring-data/base/src/main/java/com/blazebit/persistence/spring/data/base/EntityViewSortUtil.java +++ b/integration/spring-data/base/src/main/java/com/blazebit/persistence/spring/data/base/EntityViewSortUtil.java @@ -16,7 +16,13 @@ package com.blazebit.persistence.spring.data.base; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.ManagedType; + import com.blazebit.persistence.FullQueryBuilder; +import com.blazebit.persistence.parser.expression.ExpressionFactory; +import com.blazebit.persistence.parser.expression.PathElementExpression; +import com.blazebit.persistence.parser.expression.PathExpression; import com.blazebit.persistence.view.EntityViewManager; import com.blazebit.persistence.view.metamodel.ManagedViewType; import com.blazebit.persistence.view.metamodel.MethodAttribute; @@ -81,6 +87,24 @@ public static void applySort(EntityViewManager evm, Class entityViewClass, Fu for (Sort.Order order : sort) { String entityViewAttributeAlias; if ((entityViewAttributeAlias = EntityViewSortUtil.resolveViewAttributeSelectAlias(viewType, order.getProperty())) == null) { + PathExpression pathExpression; + try { + pathExpression = cb.getService(ExpressionFactory.class).createPathExpression(order.getProperty()); + } catch (RuntimeException ex) { + throw new IllegalArgumentException("Sort order [" + order.getProperty() + "] is not resolvable to a path expression.", ex); + } + javax.persistence.metamodel.Type resultType = cb.getMetamodel().entity(viewType.getEntityClass()); + for (PathElementExpression expression : pathExpression.getExpressions()) { + if (!(resultType instanceof ManagedType)) { + throw new IllegalArgumentException("Sort order [" + order.getProperty() + "] is not resolvable to a valid path expression, because the type [" + resultType.getJavaType().getName() + "] can't be de-referenced."); + } + ManagedType managedType = (ManagedType) resultType; + Attribute attribute = managedType.getAttribute(expression.toString()); + if (!(attribute instanceof javax.persistence.metamodel.SingularAttribute)) { + throw new IllegalArgumentException("Sort order [" + order.getProperty() + "] is not resolvable to a valid path expression, because the type [" + resultType.getJavaType().getName() + "] does not contain a singular attribute named [" + expression + "]."); + } + resultType = ( (javax.persistence.metamodel.SingularAttribute) attribute ).getType(); + } cb.orderBy(order.getProperty(), order.isAscending(), order.getNullHandling() == Sort.NullHandling.NULLS_FIRST); } else { cb.orderBy(entityViewAttributeAlias, order.isAscending(), order.getNullHandling() == Sort.NullHandling.NULLS_FIRST); diff --git a/integration/spring-data/testsuite/webmvc/src/test/java/com/blazebit/persistence/spring/data/testsuite/webmvc/ReadOnlyDocumentRepositoryTest.java b/integration/spring-data/testsuite/webmvc/src/test/java/com/blazebit/persistence/spring/data/testsuite/webmvc/ReadOnlyDocumentRepositoryTest.java index 1531d61f7c..c2234c44a8 100644 --- a/integration/spring-data/testsuite/webmvc/src/test/java/com/blazebit/persistence/spring/data/testsuite/webmvc/ReadOnlyDocumentRepositoryTest.java +++ b/integration/spring-data/testsuite/webmvc/src/test/java/com/blazebit/persistence/spring/data/testsuite/webmvc/ReadOnlyDocumentRepositoryTest.java @@ -46,6 +46,8 @@ import com.blazebit.persistence.view.EntityViewManager; import com.blazebit.persistence.view.EntityViewSetting; import com.blazebit.persistence.view.Sorters; + +import org.junit.Assert; import org.junit.Assume; import org.junit.Before; import org.junit.Test; @@ -879,6 +881,21 @@ public void testFindByEnum() { assertEquals(1, elementCount); } + @Test + public void testSortByExpression() { + // Given + final Document d1 = createDocument("D1", "test", 0, null); + + // When + try { + readOnlyDocumentRepository.findAll(Sort.of(new org.springframework.data.domain.Sort.Order(null, "1"))); + Assert.fail("Should fail because '1' is not a valid property to sort by"); + } catch (RuntimeException ex) { + // Then + assertTrue( ex.getMessage().contains( "Sort order [1] is not resolvable to a path expression" ) ); + } + } + private Pageable unpaged() { try { Method unpaged = Class.forName("org.springframework.data.domain.Pageable").getMethod("unpaged");