validate that paginated query methods have a well-defined ordering

Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
Gavin King 2024-04-05 00:38:17 +02:00 committed by Christian Beikov
parent 0d872baf94
commit 4b7a740d7e
2 changed files with 53 additions and 10 deletions

View File

@ -1120,9 +1120,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
final String typeName = typeElement.getQualifiedName().toString(); final String typeName = typeElement.getQualifiedName().toString();
switch ( typeName ) { switch ( typeName ) {
case JD_PAGE: case JD_PAGE:
case JD_CURSORED_PAGE: if ( !hasPageRequest(method) ) {
if ( method.getParameters().stream()
.noneMatch(param -> typeNameEquals(param.asType(), JD_PAGE_REQUEST))) {
message(method, message(method,
"method with return type '" + typeName "method with return type '" + typeName
+ "' has no parameter of type 'PageRequest'", + "' has no parameter of type 'PageRequest'",
@ -1132,9 +1130,26 @@ public class AnnotationMetaEntity extends AnnotationMeta {
else { else {
return true; 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: case HIB_KEYED_RESULT_LIST:
if ( method.getParameters().stream() if ( !hashKeyedPage(method) ) {
.noneMatch(param -> typeNameEquals(param.asType(), HIB_KEYED_PAGE))) {
message(method, message(method,
"method with return type '" + typeName "method with return type '" + typeName
+ "' has no parameter of type 'KeyedPage'", + "' 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) { private static TypeMirror ununi(TypeMirror returnType) {
if ( returnType.getKind() == TypeKind.DECLARED ) { if ( returnType.getKind() == TypeKind.DECLARED ) {
final DeclaredType declaredType = (DeclaredType) returnType; final DeclaredType declaredType = (DeclaredType) returnType;
@ -1568,8 +1601,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
private List<OrderBy> orderByList(ExecutableElement method, TypeElement returnType) { private List<OrderBy> orderByList(ExecutableElement method, TypeElement returnType) {
final TypeElement entityType = implicitEntityType( returnType ); final TypeElement entityType = implicitEntityType( returnType );
if ( entityType != null ) { if ( entityType != null ) {
final AnnotationMirror orderByList = final AnnotationMirror orderByList = getAnnotationMirror( method, JD_ORDER_BY_LIST );
getAnnotationMirror( method, "jakarta.data.repository.OrderBy.List" );
if ( orderByList != null ) { if ( orderByList != null ) {
final List<OrderBy> result = new ArrayList<>(); final List<OrderBy> result = new ArrayList<>();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -1580,8 +1612,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
} }
return result; return result;
} }
final AnnotationMirror orderBy = final AnnotationMirror orderBy = getAnnotationMirror( method, JD_ORDER_BY );
getAnnotationMirror( method, "jakarta.data.repository.OrderBy" );
if ( orderBy != null ) { if ( orderBy != null ) {
return List.of( orderByExpression(orderBy, entityType, method) ); return List.of( orderByExpression(orderBy, entityType, method) );
} }
@ -2906,7 +2937,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
return primaryEntity; return primaryEntity;
} }
private boolean typeNameEquals(TypeMirror parameterType, String typeName) { private static boolean typeNameEquals(TypeMirror parameterType, String typeName) {
if ( parameterType.getKind() == TypeKind.DECLARED ) { if ( parameterType.getKind() == TypeKind.DECLARED ) {
final DeclaredType declaredType = (DeclaredType) parameterType; final DeclaredType declaredType = (DeclaredType) parameterType;
final TypeElement typeElement = (TypeElement) declaredType.asElement(); 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) { private static String typeName(TypeMirror parameterType) {
if ( parameterType.getKind() == TypeKind.DECLARED ) { if ( parameterType.getKind() == TypeKind.DECLARED ) {
final DeclaredType declaredType = (DeclaredType) parameterType; final DeclaredType declaredType = (DeclaredType) parameterType;

View File

@ -80,6 +80,8 @@ public final class Constants {
public static final String BASIC_REPOSITORY = "jakarta.data.repository.BasicRepository"; public static final String BASIC_REPOSITORY = "jakarta.data.repository.BasicRepository";
public static final String CRUD_REPOSITORY = "jakarta.data.repository.CrudRepository"; public static final String CRUD_REPOSITORY = "jakarta.data.repository.CrudRepository";
public static final String DATA_REPOSITORY = "jakarta.data.repository.DataRepository"; 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_ORDER = "org.hibernate.query.Order";
public static final String HIB_PAGE = "org.hibernate.query.Page"; public static final String HIB_PAGE = "org.hibernate.query.Page";