From 4b7a740d7ef63f00c14fc2425604097267aa2d92 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 5 Apr 2024 00:38:17 +0200 Subject: [PATCH] validate that paginated query methods have a well-defined ordering Signed-off-by: Gavin King --- .../annotation/AnnotationMetaEntity.java | 61 ++++++++++++++++--- .../hibernate/processor/util/Constants.java | 2 + 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java index 55fd467177..3c321adf2c 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java @@ -1120,9 +1120,7 @@ public class AnnotationMetaEntity extends AnnotationMeta { final String typeName = typeElement.getQualifiedName().toString(); switch ( typeName ) { case JD_PAGE: - case JD_CURSORED_PAGE: - if ( method.getParameters().stream() - .noneMatch(param -> typeNameEquals(param.asType(), JD_PAGE_REQUEST))) { + if ( !hasPageRequest(method) ) { message(method, "method with return type '" + typeName + "' has no parameter of type 'PageRequest'", @@ -1132,9 +1130,26 @@ public class AnnotationMetaEntity extends AnnotationMeta { else { return true; } + case JD_CURSORED_PAGE: + if ( !hasPageRequest(method) ) { + message(method, + "method with return type '" + typeName + + "' has no parameter of type 'PageRequest'", + Diagnostic.Kind.ERROR); + return false; + } + else if ( !hasOrder(method) ) { + message(method, + "method with return type '" + typeName + + "' has no parameter of type 'Order' or 'Sort' and no '@OrderBy' annotation", + Diagnostic.Kind.ERROR); + return false; + } + else { + return true; + } case HIB_KEYED_RESULT_LIST: - if ( method.getParameters().stream() - .noneMatch(param -> typeNameEquals(param.asType(), HIB_KEYED_PAGE))) { + if ( !hashKeyedPage(method) ) { message(method, "method with return type '" + typeName + "' has no parameter of type 'KeyedPage'", @@ -1157,6 +1172,24 @@ public class AnnotationMetaEntity extends AnnotationMeta { } } + private static boolean hashKeyedPage(ExecutableElement method) { + return method.getParameters().stream() + .anyMatch(param -> typeNameEquals(param.asType(), HIB_KEYED_PAGE)); + } + + private static boolean hasPageRequest(ExecutableElement method) { + return method.getParameters().stream() + .anyMatch(param -> typeNameEquals(param.asType(), JD_PAGE_REQUEST)); + } + + private static boolean hasOrder(ExecutableElement method) { + return hasAnnotation(method, JD_ORDER_BY, JD_ORDER_BY_LIST) + || method.getParameters().stream() + .anyMatch(param -> typeNameEquals(param.asType(), JD_ORDER) + || typeNameEquals(param.asType(), JD_SORT) + || typeNameEqualsArray(param.asType(), JD_SORT)); + } + private static TypeMirror ununi(TypeMirror returnType) { if ( returnType.getKind() == TypeKind.DECLARED ) { final DeclaredType declaredType = (DeclaredType) returnType; @@ -1568,8 +1601,7 @@ public class AnnotationMetaEntity extends AnnotationMeta { private List orderByList(ExecutableElement method, TypeElement returnType) { final TypeElement entityType = implicitEntityType( returnType ); if ( entityType != null ) { - final AnnotationMirror orderByList = - getAnnotationMirror( method, "jakarta.data.repository.OrderBy.List" ); + final AnnotationMirror orderByList = getAnnotationMirror( method, JD_ORDER_BY_LIST ); if ( orderByList != null ) { final List result = new ArrayList<>(); @SuppressWarnings("unchecked") @@ -1580,8 +1612,7 @@ public class AnnotationMetaEntity extends AnnotationMeta { } return result; } - final AnnotationMirror orderBy = - getAnnotationMirror( method, "jakarta.data.repository.OrderBy" ); + final AnnotationMirror orderBy = getAnnotationMirror( method, JD_ORDER_BY ); if ( orderBy != null ) { return List.of( orderByExpression(orderBy, entityType, method) ); } @@ -2906,7 +2937,7 @@ public class AnnotationMetaEntity extends AnnotationMeta { return primaryEntity; } - private boolean typeNameEquals(TypeMirror parameterType, String typeName) { + private static boolean typeNameEquals(TypeMirror parameterType, String typeName) { if ( parameterType.getKind() == TypeKind.DECLARED ) { final DeclaredType declaredType = (DeclaredType) parameterType; final TypeElement typeElement = (TypeElement) declaredType.asElement(); @@ -2917,6 +2948,16 @@ public class AnnotationMetaEntity extends AnnotationMeta { } } + private static boolean typeNameEqualsArray(TypeMirror parameterType, String typeName) { + if ( parameterType.getKind() == TypeKind.ARRAY ) { + final ArrayType arrayType = (ArrayType) parameterType; + return typeNameEquals( arrayType.getComponentType(), typeName ); + } + else { + return false; + } + } + private static String typeName(TypeMirror parameterType) { if ( parameterType.getKind() == TypeKind.DECLARED ) { final DeclaredType declaredType = (DeclaredType) parameterType; diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/Constants.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/Constants.java index 0b8919f66e..b790ad8d8b 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/Constants.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/Constants.java @@ -80,6 +80,8 @@ public final class Constants { public static final String BASIC_REPOSITORY = "jakarta.data.repository.BasicRepository"; public static final String CRUD_REPOSITORY = "jakarta.data.repository.CrudRepository"; public static final String DATA_REPOSITORY = "jakarta.data.repository.DataRepository"; + public static final String JD_ORDER_BY = "jakarta.data.repository.OrderBy"; + public static final String JD_ORDER_BY_LIST = "jakarta.data.repository.OrderBy.List"; public static final String HIB_ORDER = "org.hibernate.query.Order"; public static final String HIB_PAGE = "org.hibernate.query.Page";