HHH-16633 support new Order and Page objects as parameters of query methods
This commit is contained in:
parent
19a75aad9e
commit
f933b064e9
|
@ -46,12 +46,28 @@ import static java.lang.annotation.RetentionPolicy.CLASS;
|
|||
* <li>an entity type,
|
||||
* <li>{@link java.util.List},
|
||||
* <li>{@link org.hibernate.query.Query},
|
||||
* <li>{@link org.hibernate.query.SelectionQuery},
|
||||
* <li>{@link jakarta.persistence.Query}, or
|
||||
* <li>{@link jakarta.persistence.TypedQuery}.
|
||||
* </ul>
|
||||
* <p>
|
||||
* The method parameters must match the parameters of the HQL query,
|
||||
* either by name or by position.
|
||||
* either by name or by position:
|
||||
* <ul>
|
||||
* <li>an ordinal query parameter of form {@code ?n} is matched to
|
||||
* the <em>n</em>th parameter of the method, and
|
||||
* <li>a named query parameter of form {@code :name} is matched to
|
||||
* the method parameter {@code name}.
|
||||
* </ul>
|
||||
* <p>
|
||||
* As an exception, the method may have:
|
||||
* <ul>
|
||||
* <li>a parameter with type {@code Page}, and/or
|
||||
* <li>a parameter with type {@code Order<? super E>},
|
||||
* {@code List<Order<? super E>>}, or {@code Order<? super E>...}
|
||||
* (varargs) where {@code E} is the entity type returned by the
|
||||
* query.
|
||||
* </ul>
|
||||
* <p>
|
||||
* Queries specified using this annotation are always validated by
|
||||
* the Metamodel Generator, and so it isn't necessary to specify the
|
||||
|
|
|
@ -51,7 +51,13 @@ import static java.lang.annotation.RetentionPolicy.CLASS;
|
|||
* </ul>
|
||||
* <p>
|
||||
* The method parameters must match the parameters of the SQL query,
|
||||
* either by name or by position.
|
||||
* either by name or by position:
|
||||
* <ul>
|
||||
* <li>an ordinal query parameter of form {@code ?n} is matched to
|
||||
* the <em>n</em>th parameter of the method, and
|
||||
* <li>a named query parameter of form {@code :name} is matched to
|
||||
* the method parameter {@code name}.
|
||||
* </ul>
|
||||
*
|
||||
* @author Gavin King
|
||||
* @since 6.3
|
||||
|
|
|
@ -17,6 +17,11 @@ import java.util.Objects;
|
|||
* This is a convenience class which allows query result ordering
|
||||
* rules to be passed around the system before being applied to
|
||||
* a {@link Query} by calling {@link SelectionQuery#setOrder}.
|
||||
* <p>
|
||||
* A parameter of a {@linkplain org.hibernate.annotations.processing.HQL
|
||||
* HQL query method} may be declared with type {@code Order<? super E>},
|
||||
* {@code List<Order<? super E>>}, or {@code Order<? super E>...} (varargs)
|
||||
* where {@code E} is the entity type returned by the query.
|
||||
*
|
||||
* @param <X> The result type of the query to be sorted
|
||||
*
|
||||
|
|
|
@ -15,6 +15,9 @@ import org.hibernate.Incubating;
|
|||
* This is a convenience class which allows a reference to a page of
|
||||
* results to be passed around the system before being applied to
|
||||
* a {@link Query} by calling {@link Query#setPage(Page)}.
|
||||
* <p>
|
||||
* A parameter of a {@linkplain org.hibernate.annotations.processing.HQL
|
||||
* HQL query method} may be declared with type {@code Page}.
|
||||
*
|
||||
* @see Query#setPage(Page)
|
||||
*
|
||||
|
|
|
@ -76,6 +76,11 @@ public class ImportContextImpl implements ImportContext {
|
|||
result = result.substring( 0, fqcn.indexOf( '[' ) );
|
||||
fqcn = result;
|
||||
}
|
||||
else if ( fqcn.endsWith( "..." ) ) {
|
||||
additionalTypePart = "...";
|
||||
result = result.substring( 0, fqcn.indexOf( "..." ) );
|
||||
fqcn = result;
|
||||
}
|
||||
|
||||
String pureFqcn = fqcn.replace( '$', '.' );
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ import org.hibernate.jpamodelgen.validation.Validation;
|
|||
|
||||
import static java.util.Collections.emptySet;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.hibernate.jpamodelgen.annotation.QueryMethod.isOrderParam;
|
||||
import static org.hibernate.jpamodelgen.annotation.QueryMethod.isPageParam;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.containsAnnotation;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.determineAnnotationSpecifiedAccessType;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationMirror;
|
||||
|
@ -385,7 +387,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
);
|
||||
putMember( attribute.getPropertyName() + paramTypes, attribute );
|
||||
|
||||
checkParameters( method, paramNames, mirror, hql );
|
||||
checkParameters( method, paramNames, paramTypes, mirror, hql );
|
||||
if ( !isNative ) {
|
||||
// checkHqlSyntax( method, mirror, hql );
|
||||
Validation.validate(
|
||||
|
@ -399,10 +401,12 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
}
|
||||
}
|
||||
|
||||
private void checkParameters(ExecutableElement method, List<String> paramNames, AnnotationMirror mirror, String hql) {
|
||||
private void checkParameters(ExecutableElement method, List<String> paramNames, List<String> paramTypes, AnnotationMirror mirror, String hql) {
|
||||
for (int i = 1; i <= paramNames.size(); i++) {
|
||||
final String param = paramNames.get(i-1);
|
||||
if ( !hql.contains(":" + param) && !hql.contains("?" + i) ) {
|
||||
final String ptype = paramTypes.get(i-1);
|
||||
if ( !hql.contains(":" + param) && !hql.contains("?" + i)
|
||||
&& !isPageParam(ptype) && !isOrderParam(ptype)) {
|
||||
context.message( method, mirror, "missing query parameter for '" + param
|
||||
+ "' (no parameter named :" + param + " or ?" + i + ")", Diagnostic.Kind.ERROR );
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.jpamodelgen.model.MetaAttribute;
|
||||
import org.hibernate.jpamodelgen.model.Metamodel;
|
||||
import org.hibernate.query.Order;
|
||||
import org.hibernate.query.Page;
|
||||
import org.hibernate.query.SelectionQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -58,6 +61,9 @@ public class QueryMethod implements MetaAttribute {
|
|||
|
||||
@Override
|
||||
public String getAttributeDeclarationString() {
|
||||
List<String> paramTypes = this.paramTypes.stream()
|
||||
.map(ptype->isOrderParam(ptype) && ptype.endsWith("[]") ? ptype.replace("[]", "...") : ptype)
|
||||
.collect(toList());
|
||||
StringBuilder declaration = new StringBuilder();
|
||||
declaration
|
||||
.append("\n/**\n * @see ")
|
||||
|
@ -65,9 +71,14 @@ public class QueryMethod implements MetaAttribute {
|
|||
.append("#")
|
||||
.append(methodName)
|
||||
.append("(")
|
||||
.append(join(",", paramTypes.stream().map(annotationMetaEntity::importType).toArray()))
|
||||
.append(join(",", paramTypes.stream().map(this::strip).map(annotationMetaEntity::importType).toArray()))
|
||||
.append(")")
|
||||
.append("\n **/\n")
|
||||
.append("\n **/\n");
|
||||
if ( paramTypes.stream().anyMatch(ptype -> ptype.endsWith("..."))) {
|
||||
declaration
|
||||
.append("@SafeVarargs\n");
|
||||
}
|
||||
declaration
|
||||
.append("public static ");
|
||||
StringBuilder type = new StringBuilder();
|
||||
if (containerTypeName != null) {
|
||||
|
@ -88,11 +99,16 @@ public class QueryMethod implements MetaAttribute {
|
|||
.append(" entityManager");
|
||||
|
||||
for (int i =0; i<paramNames.size(); i++) {
|
||||
String ptype = paramTypes.get(i);
|
||||
String param = paramNames.get(i);
|
||||
String rptype = returnTypeName != null
|
||||
? ptype.replace(returnTypeName, annotationMetaEntity.importType(returnTypeName))
|
||||
: ptype;
|
||||
declaration
|
||||
.append(", ")
|
||||
.append(annotationMetaEntity.importType(paramTypes.get(i)))
|
||||
.append(annotationMetaEntity.importType(rptype))
|
||||
.append(" ")
|
||||
.append(paramNames.get(i));
|
||||
.append(param);
|
||||
}
|
||||
declaration
|
||||
.append(")")
|
||||
|
@ -104,7 +120,7 @@ public class QueryMethod implements MetaAttribute {
|
|||
}
|
||||
declaration
|
||||
.append("entityManager.")
|
||||
.append(isNative ? "createNativeQuery" :"createQuery")
|
||||
.append(isNative ? "createNativeQuery" : "createQuery")
|
||||
.append("(")
|
||||
.append(getConstantName());
|
||||
if (returnTypeName != null) {
|
||||
|
@ -114,8 +130,10 @@ public class QueryMethod implements MetaAttribute {
|
|||
.append(".class");
|
||||
}
|
||||
declaration.append(")");
|
||||
boolean unwrapped = false;
|
||||
for (int i = 1; i <= paramNames.size(); i++) {
|
||||
String param = paramNames.get(i-1);
|
||||
String ptype = paramTypes.get(i-1);
|
||||
if (queryString.contains(":" + param)) {
|
||||
declaration
|
||||
.append("\n .setParameter(\"")
|
||||
|
@ -132,6 +150,32 @@ public class QueryMethod implements MetaAttribute {
|
|||
.append(param)
|
||||
.append(")");
|
||||
}
|
||||
else if (isPageParam(ptype)) {
|
||||
unwrap( declaration, unwrapped );
|
||||
unwrapped = true;
|
||||
declaration
|
||||
.append("\n .setPage(")
|
||||
.append(param)
|
||||
.append(")");
|
||||
}
|
||||
else if (isOrderParam(ptype)) {
|
||||
unwrap( declaration, unwrapped );
|
||||
unwrapped = true;
|
||||
if (ptype.endsWith("...")) {
|
||||
declaration
|
||||
.append("\n .setOrder(")
|
||||
.append(annotationMetaEntity.importType(List.class.getName()))
|
||||
.append(".of(")
|
||||
.append(param)
|
||||
.append("))");
|
||||
}
|
||||
else {
|
||||
declaration
|
||||
.append("\n .setOrder(")
|
||||
.append(param)
|
||||
.append(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( containerTypeName == null) {
|
||||
declaration.append("\n .getSingleResult()");
|
||||
|
@ -143,9 +187,34 @@ public class QueryMethod implements MetaAttribute {
|
|||
return declaration.toString();
|
||||
}
|
||||
|
||||
private String strip(String type) {
|
||||
int index = type.indexOf("<");
|
||||
String stripped = index > 0 ? type.substring(0, index) : type;
|
||||
return type.endsWith("...") ? stripped + "..." : stripped;
|
||||
}
|
||||
|
||||
static boolean isPageParam(String ptype) {
|
||||
return Page.class.getName().equals(ptype);
|
||||
}
|
||||
|
||||
static boolean isOrderParam(String ptype) {
|
||||
return ptype.startsWith(Order.class.getName())
|
||||
|| ptype.startsWith(List.class.getName() + "<" + Order.class.getName());
|
||||
}
|
||||
|
||||
private void unwrap(StringBuilder declaration, boolean unwrapped) {
|
||||
if ( !unwrapped ) {
|
||||
declaration
|
||||
.append("\n .unwrap(")
|
||||
.append(annotationMetaEntity.importType(SelectionQuery.class.getName()))
|
||||
.append(".class)");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttributeNameDeclarationString() {
|
||||
return new StringBuilder().append("public static final String ")
|
||||
return new StringBuilder()
|
||||
.append("public static final String ")
|
||||
.append(getConstantName())
|
||||
.append(" = \"")
|
||||
.append(queryString)
|
||||
|
@ -160,7 +229,9 @@ public class QueryMethod implements MetaAttribute {
|
|||
}
|
||||
else {
|
||||
return stem + "_" + StringHelper.join("_",
|
||||
paramTypes.stream().map(StringHelper::unqualify).collect(toList()));
|
||||
paramTypes.stream()
|
||||
.filter(name -> !isPageParam(name) && !isOrderParam(name))
|
||||
.map(StringHelper::unqualify).collect(toList()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@ package org.hibernate.jpamodelgen.test.hqlsql;
|
|||
import jakarta.persistence.TypedQuery;
|
||||
import org.hibernate.annotations.processing.HQL;
|
||||
import org.hibernate.annotations.processing.SQL;
|
||||
import org.hibernate.query.Order;
|
||||
import org.hibernate.query.Page;
|
||||
import org.hibernate.query.SelectionQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -13,6 +16,15 @@ public interface Dao {
|
|||
@HQL("from Book where title like ?1 order by title fetch first ?2 rows only")
|
||||
List<Book> findFirstNByTitle(String title, int N);
|
||||
|
||||
@HQL("from Book where title like :title")
|
||||
List<Book> findByTitleWithPagination(String title, Order<? super Book> order, Page page);
|
||||
|
||||
@HQL("from Book where title like :title")
|
||||
SelectionQuery<Book> findByTitleWithOrdering(String title, List<Order<? super Book>> order);
|
||||
|
||||
@HQL("from Book where title like :title")
|
||||
SelectionQuery<Book> findByTitleWithOrderingByVarargs(String title, Order<? super Book>... order);
|
||||
|
||||
@HQL("from Book where isbn = :isbn")
|
||||
Book findByIsbn(String isbn);
|
||||
|
||||
|
|
Loading…
Reference in New Issue