From 7e723da507f77a8bdf6233757b0f22b343178c98 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Wed, 7 Feb 2024 20:26:47 +0100 Subject: [PATCH] validate the type arg of Order parameters in @Find and @HQL methods --- .../annotation/AnnotationMetaEntity.java | 73 ++++++++++++++++++- .../jpamodelgen/test/hqlsql/Books.java | 2 +- 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java index 80abe9c981..61b9dd4f8a 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java @@ -26,6 +26,7 @@ import javax.lang.model.type.ExecutableType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.WildcardType; import javax.tools.Diagnostic; import org.checkerframework.checker.nullness.qual.Nullable; @@ -41,6 +42,7 @@ import org.hibernate.jpamodelgen.validation.ProcessorSessionFactory; import org.hibernate.jpamodelgen.validation.Validation; import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.query.Order; import org.hibernate.query.criteria.JpaEntityJoin; import org.hibernate.query.criteria.JpaRoot; import org.hibernate.query.criteria.JpaSelection; @@ -592,9 +594,23 @@ private void createCriteriaFinder( final List paramTypes = parameterTypes( method ); final String[] sessionType = sessionTypeFromParameters( paramNames, paramTypes ); final String methodKey = methodName + paramTypes; - for ( VariableElement param : method.getParameters() ) { - if ( isFinderParameterMappingToAttribute( param ) ) { - validateFinderParameter( entity, param ); + for ( VariableElement parameter : method.getParameters() ) { + if ( isFinderParameterMappingToAttribute( parameter ) ) { + validateFinderParameter( entity, parameter ); + } + else { + final TypeMirror parameterType = parameter.asType(); + if ( isOrderParam( parameterType.toString() ) ) { + final TypeMirror typeArgument = getTypeArgument( parameterType ); + if ( typeArgument == null ) { + context.message( parameter, "missing type of order (should be 'Order')", Diagnostic.Kind.ERROR ); + } + else if ( !context.getTypeUtils().isSameType( typeArgument, entity.asType() ) ) { + context.message( parameter, "mismatched type of order (should be 'Order')", Diagnostic.Kind.ERROR); + } + } } } putMember( methodKey, @@ -615,6 +631,38 @@ private void createCriteriaFinder( ); } + private static @Nullable TypeMirror getTypeArgument(TypeMirror parameterType) { + switch ( parameterType.getKind() ) { + case ARRAY: + final ArrayType arrayType = (ArrayType) parameterType; + return getTypeArgument( arrayType.getComponentType() ); + case DECLARED: + final DeclaredType type = (DeclaredType) parameterType; + if ( parameterType.toString().startsWith( List.class.getName() ) ) { + for (TypeMirror arg : type.getTypeArguments()) { + return getTypeArgument( arg ); + } + } + else if ( parameterType.toString().startsWith( Order.class.getName() ) ) { + for ( TypeMirror arg : type.getTypeArguments() ) { + switch ( arg.getKind() ) { + case WILDCARD: + return ((WildcardType) arg).getSuperBound(); + case ARRAY: + case DECLARED: + case TYPEVAR: + return arg; + default: + return null; + } + } + } + return null; + default: + return null; + } + } + private static boolean isFinderParameterMappingToAttribute(VariableElement param) { final String type = param.asType().toString(); return !isSessionParameter( type ) @@ -1006,7 +1054,7 @@ private void addQueryMethod( } // now check that the query has a parameter for every method parameter - checkParameters( method, paramNames, paramTypes, mirror, value, queryString ); + checkParameters( method, returnType, paramNames, paramTypes, mirror, value, queryString ); } } } @@ -1375,6 +1423,7 @@ private static boolean isNullable(Element member) { private void checkParameters( ExecutableElement method, + @Nullable TypeMirror returnType, List paramNames, List paramTypes, AnnotationMirror mirror, AnnotationValue value, @@ -1389,6 +1438,22 @@ private void checkParameters( Diagnostic.Kind.ERROR ); } } + if ( returnType != null ) { + for ( VariableElement parameter : method.getParameters() ) { + final TypeMirror parameterType = parameter.asType(); + final TypeMirror typeArgument = getTypeArgument( parameterType ); + if ( isOrderParam( parameterType.toString() ) ) { + if ( typeArgument == null ) { + context.message( parameter, "missing type of order (should be 'Order')", Diagnostic.Kind.ERROR ); + } + else if ( !context.getTypeUtils().isSameType(typeArgument, returnType) ) { + context.message( parameter, "mismatched type of order (should be 'Order')", Diagnostic.Kind.ERROR ); + } + } + } + } } private static boolean parameterIsMissing(String hql, int i, String param, String type) { diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/hqlsql/Books.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/hqlsql/Books.java index 1f3c00ed6c..de5ee8618b 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/hqlsql/Books.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/hqlsql/Books.java @@ -32,5 +32,5 @@ public abstract class Books { static class Summary { Summary(String title, String publisher, String isbn) {} } @HQL("select title, publisher.name, isbn from Book") - abstract List summarize(Session session, Order order); + abstract List summarize(Session session, Order order); }