allow criteria-based @Find methods to specify Page and Order

This is not necessary for @Id or @NaturalId-based @Find methods,
because they don't return multiple results.
This commit is contained in:
Gavin King 2023-07-23 13:16:18 +02:00
parent 1c15267d3a
commit 8794f86ad2
5 changed files with 108 additions and 81 deletions

View File

@ -10,6 +10,8 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.jpamodelgen.model.MetaAttribute; import org.hibernate.jpamodelgen.model.MetaAttribute;
import org.hibernate.jpamodelgen.model.Metamodel; import org.hibernate.jpamodelgen.model.Metamodel;
import org.hibernate.jpamodelgen.util.Constants; import org.hibernate.jpamodelgen.util.Constants;
import org.hibernate.query.Order;
import org.hibernate.query.Page;
import java.util.List; import java.util.List;
@ -159,4 +161,59 @@ public abstract class AbstractQueryMethod implements MetaAttribute {
boolean isReactive() { boolean isReactive() {
return Constants.MUTINY_SESSION.equals(sessionType); return Constants.MUTINY_SESSION.equals(sessionType);
} }
void setPage(StringBuilder declaration, String paramName) {
if ( isUsingEntityManager() ) {
declaration
.append("\n\t\t\t.setFirstResult(")
.append(paramName)
.append(".getFirstResult())")
.append("\n\t\t\t.setMaxResults(")
.append(paramName)
.append(".getMaxResults())");
}
else {
declaration
.append("\n\t\t\t.setPage(")
.append(paramName)
.append(")");
}
}
boolean setOrder(StringBuilder declaration, boolean unwrapped, String paramName, String paramType) {
unwrapQuery( declaration, unwrapped );
if ( paramType.endsWith("...") ) {
declaration
.append("\n\t\t\t.setOrder(")
.append(annotationMetaEntity.importType(Constants.LIST))
.append(".of(")
.append(paramName)
.append("))");
}
else {
declaration
.append("\n\t\t\t.setOrder(")
.append(paramName)
.append(")");
}
return true;
}
private void unwrapQuery(StringBuilder declaration, boolean unwrapped) {
if ( !unwrapped ) {
declaration
.append("\n\t\t\t.unwrap(")
.append(annotationMetaEntity.importType(Constants.HIB_SELECTION_QUERY))
.append(".class)");
}
}
static boolean isPageParam(String parameterType) {
return Page.class.getName().equals(parameterType);
}
static boolean isOrderParam(String parameterType) {
return parameterType.startsWith(Order.class.getName())
|| parameterType.startsWith(List.class.getName() + "<" + Order.class.getName());
}
} }

View File

@ -573,7 +573,10 @@ public class AnnotationMetaEntity extends AnnotationMeta {
} }
private static boolean isFinderParameterMappingToAttribute(VariableElement param) { private static boolean isFinderParameterMappingToAttribute(VariableElement param) {
return !isSessionParameter( param.asType().toString() ); final String type = param.asType().toString();
return !isSessionParameter( type )
&& !isPageParam( type )
&& !isOrderParam( type );
} }
private String[] sessionTypeFromParameters(List<String> paramNames, List<String> paramTypes) { private String[] sessionTypeFromParameters(List<String> paramNames, List<String> paramTypes) {

View File

@ -86,7 +86,9 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
for ( int i = 0; i < paramNames.size(); i ++ ) { for ( int i = 0; i < paramNames.size(); i ++ ) {
final String paramName = paramNames.get(i); final String paramName = paramNames.get(i);
final String paramType = paramTypes.get(i); final String paramType = paramTypes.get(i);
if ( !isSessionParameter(paramType) ) { if ( !isSessionParameter(paramType)
&& !isPageParam(paramType)
&& !isOrderParam(paramType) ) {
if ( first ) { if ( first ) {
first = false; first = false;
} }
@ -94,27 +96,7 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
declaration declaration
.append(", "); .append(", ");
} }
declaration parameter( declaration, i, paramName, paramType );
.append("\n\t\t\t");
if ( isNullable(i) && !isPrimitive(paramType) ) {
declaration
.append(paramName)
.append("==null")
.append("\n\t\t\t\t? ")
.append("entity");
path( declaration, paramName );
declaration
.append(".isNull()")
.append("\n\t\t\t\t: ");
}
declaration
.append("builder.equal(entity");
path( declaration, paramName );
declaration
.append(", ")
//TODO: only safe if we are binding literals as parameters!!!
.append(paramName)
.append(')');
} }
} }
declaration declaration
@ -122,11 +104,12 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
.append("\n\treturn ") .append("\n\treturn ")
.append(sessionName) .append(sessionName)
.append(".createQuery(query)"); .append(".createQuery(query)");
final boolean hasOrderParameter = paramTypes.stream().anyMatch(AbstractQueryMethod::isOrderParam);
final boolean hasEnabledFetchProfiles = !fetchProfiles.isEmpty(); final boolean hasEnabledFetchProfiles = !fetchProfiles.isEmpty();
final boolean hasNativeReturnType = final boolean hasNativeReturnType =
containerType != null && containerType.startsWith("org.hibernate"); containerType != null && containerType.startsWith("org.hibernate");
final boolean unwrap = final boolean unwrap =
( hasEnabledFetchProfiles || hasNativeReturnType ) ( hasOrderParameter || hasEnabledFetchProfiles || hasNativeReturnType )
&& isUsingEntityManager(); && isUsingEntityManager();
if ( unwrap ) { if ( unwrap ) {
declaration declaration
@ -134,16 +117,26 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
.append(annotationMetaEntity.importType(Constants.HIB_SELECTION_QUERY)) .append(annotationMetaEntity.importType(Constants.HIB_SELECTION_QUERY))
.append(".class)"); .append(".class)");
} }
for ( int i = 0; i < paramNames.size(); i ++ ) {
final String paramName = paramNames.get(i);
final String paramType = paramTypes.get(i);
if ( isPageParam(paramType) ) {
setPage( declaration, paramName );
}
else if ( isOrderParam(paramType) ) {
setOrder( declaration, true, paramName, paramType );
}
}
enableFetchProfile( declaration ); enableFetchProfile( declaration );
if ( containerType == null) { if ( containerType == null) {
if ( unwrap || hasEnabledFetchProfiles) { if ( unwrap || hasEnabledFetchProfiles ) {
declaration.append("\n\t\t\t"); declaration.append("\n\t\t\t");
} }
declaration declaration
.append(".getSingleResult()"); .append(".getSingleResult()");
} }
else if ( containerType.equals(Constants.LIST) ) { else if ( containerType.equals(Constants.LIST) ) {
if ( unwrap || hasEnabledFetchProfiles ) { if ( unwrap || hasOrderParameter || hasEnabledFetchProfiles ) {
declaration.append("\n\t\t\t"); declaration.append("\n\t\t\t");
} }
declaration declaration
@ -154,6 +147,30 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
return declaration.toString(); return declaration.toString();
} }
private void parameter(StringBuilder declaration, int i, String paramName, String paramType) {
declaration
.append("\n\t\t\t");
if ( isNullable(i) && !isPrimitive(paramType) ) {
declaration
.append(paramName)
.append("==null")
.append("\n\t\t\t\t? ")
.append("entity");
path( declaration, paramName );
declaration
.append(".isNull()")
.append("\n\t\t\t\t: ");
}
declaration
.append("builder.equal(entity");
path( declaration, paramName );
declaration
.append(", ")
//TODO: only safe if we are binding literals as parameters!!!
.append(paramName)
.append(')');
}
private void path(StringBuilder declaration, String paramName) { private void path(StringBuilder declaration, String paramName) {
final StringTokenizer tokens = new StringTokenizer(paramName, "$"); final StringTokenizer tokens = new StringTokenizer(paramName, "$");
String typeName = entity; String typeName = entity;

View File

@ -183,43 +183,6 @@ public class QueryMethod extends AbstractQueryMethod {
.append(")"); .append(")");
} }
private void setPage(StringBuilder declaration, String paramName) {
if ( isUsingEntityManager() ) {
declaration
.append("\n\t\t\t.setFirstResult(")
.append(paramName)
.append(".getFirstResult())")
.append("\n\t\t\t.setMaxResults(")
.append(paramName)
.append(".getMaxResults())");
}
else {
declaration
.append("\n\t\t\t.setPage(")
.append(paramName)
.append(")");
}
}
private boolean setOrder(StringBuilder declaration, boolean unwrapped, String paramName, String paramType) {
unwrap( declaration, unwrapped );
if ( paramType.endsWith("...") ) {
declaration
.append("\n\t\t\t.setOrder(")
.append(annotationMetaEntity.importType(Constants.LIST))
.append(".of(")
.append(paramName)
.append("))");
}
else {
declaration
.append("\n\t\t\t.setOrder(")
.append(paramName)
.append(")");
}
return true;
}
private StringBuilder returnType() { private StringBuilder returnType() {
StringBuilder type = new StringBuilder(); StringBuilder type = new StringBuilder();
boolean returnsUni = isReactive() boolean returnsUni = isReactive()
@ -283,24 +246,6 @@ public class QueryMethod extends AbstractQueryMethod {
} }
} }
static boolean isPageParam(String parameterType) {
return Page.class.getName().equals(parameterType);
}
static boolean isOrderParam(String parameterType) {
return parameterType.startsWith(Order.class.getName())
|| parameterType.startsWith(List.class.getName() + "<" + Order.class.getName());
}
private void unwrap(StringBuilder declaration, boolean unwrapped) {
if ( !unwrapped ) {
declaration
.append("\n\t\t\t.unwrap(")
.append(annotationMetaEntity.importType(Constants.HIB_SELECTION_QUERY))
.append(".class)");
}
}
@Override @Override
public String getAttributeNameDeclarationString() { public String getAttributeNameDeclarationString() {
return new StringBuilder() return new StringBuilder()

View File

@ -5,6 +5,8 @@ import jakarta.persistence.TypedQuery;
import org.hibernate.annotations.processing.Find; import org.hibernate.annotations.processing.Find;
import org.hibernate.annotations.processing.HQL; import org.hibernate.annotations.processing.HQL;
import org.hibernate.annotations.processing.SQL; import org.hibernate.annotations.processing.SQL;
import org.hibernate.query.Order;
import org.hibernate.query.Page;
import org.hibernate.query.SelectionQuery; import org.hibernate.query.SelectionQuery;
import java.util.List; import java.util.List;
@ -34,6 +36,9 @@ public interface Dao {
@Find(enabledFetchProfiles="Hello") @Find(enabledFetchProfiles="Hello")
List<Book> getBooksFetching(String title); List<Book> getBooksFetching(String title);
@Find
List<Book> getBooks(String title, Page page, Order<Book> order);
@Find @Find
SelectionQuery<Book> createBooksSelectionQuery(String title); SelectionQuery<Book> createBooksSelectionQuery(String title);