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();
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<OrderBy> 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<OrderBy> 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;

View File

@ -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";