validate the type arg of Order parameters in @Find and @HQL methods

This commit is contained in:
Gavin King 2024-02-07 20:26:47 +01:00
parent 508df48686
commit cb1b276ff8
2 changed files with 70 additions and 5 deletions

View File

@ -26,6 +26,7 @@ import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType; import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.WildcardType;
import javax.tools.Diagnostic; import javax.tools.Diagnostic;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
@ -41,6 +42,7 @@ import org.hibernate.jpamodelgen.util.Constants;
import org.hibernate.jpamodelgen.validation.ProcessorSessionFactory; import org.hibernate.jpamodelgen.validation.ProcessorSessionFactory;
import org.hibernate.jpamodelgen.validation.Validation; import org.hibernate.jpamodelgen.validation.Validation;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.Order;
import org.hibernate.query.criteria.JpaEntityJoin; import org.hibernate.query.criteria.JpaEntityJoin;
import org.hibernate.query.criteria.JpaRoot; import org.hibernate.query.criteria.JpaRoot;
import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.criteria.JpaSelection;
@ -592,9 +594,23 @@ public class AnnotationMetaEntity extends AnnotationMeta {
final List<String> paramTypes = parameterTypes( method ); final List<String> paramTypes = parameterTypes( method );
final String[] sessionType = sessionTypeFromParameters( paramNames, paramTypes ); final String[] sessionType = sessionTypeFromParameters( paramNames, paramTypes );
final String methodKey = methodName + paramTypes; final String methodKey = methodName + paramTypes;
for ( VariableElement param : method.getParameters() ) { for ( VariableElement parameter : method.getParameters() ) {
if ( isFinderParameterMappingToAttribute( param ) ) { if ( isFinderParameterMappingToAttribute( parameter ) ) {
validateFinderParameter( entity, param ); 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<? super "
+ entity.getSimpleName() + ">')", Diagnostic.Kind.ERROR );
}
else if ( !context.getTypeUtils().isSameType( typeArgument, entity.asType() ) ) {
context.message( parameter, "mismatched type of order (should be 'Order<? super "
+ entity.getSimpleName() + ">')", Diagnostic.Kind.ERROR);
}
}
} }
} }
putMember( methodKey, putMember( methodKey,
@ -615,6 +631,38 @@ public class AnnotationMetaEntity extends AnnotationMeta {
); );
} }
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) { private static boolean isFinderParameterMappingToAttribute(VariableElement param) {
final String type = param.asType().toString(); final String type = param.asType().toString();
return !isSessionParameter( type ) return !isSessionParameter( type )
@ -1006,7 +1054,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
} }
// now check that the query has a parameter for every method parameter // 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 @@ public class AnnotationMetaEntity extends AnnotationMeta {
private void checkParameters( private void checkParameters(
ExecutableElement method, ExecutableElement method,
@Nullable TypeMirror returnType,
List<String> paramNames, List<String> paramTypes, List<String> paramNames, List<String> paramTypes,
AnnotationMirror mirror, AnnotationMirror mirror,
AnnotationValue value, AnnotationValue value,
@ -1389,6 +1438,22 @@ public class AnnotationMetaEntity extends AnnotationMeta {
Diagnostic.Kind.ERROR ); 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<? super "
+ returnType + ">')", Diagnostic.Kind.ERROR );
}
else if ( !context.getTypeUtils().isSameType(typeArgument, returnType) ) {
context.message( parameter, "mismatched type of order (should be 'Order<? super "
+ returnType + ">')", Diagnostic.Kind.ERROR );
}
}
}
}
} }
private static boolean parameterIsMissing(String hql, int i, String param, String type) { private static boolean parameterIsMissing(String hql, int i, String param, String type) {

View File

@ -32,5 +32,5 @@ public abstract class Books {
static class Summary { Summary(String title, String publisher, String isbn) {} } static class Summary { Summary(String title, String publisher, String isbn) {} }
@HQL("select title, publisher.name, isbn from Book") @HQL("select title, publisher.name, isbn from Book")
abstract List<Summary> summarize(Session session, Order order); abstract List<Summary> summarize(Session session, Order<Summary> order);
} }