HHH-16633 introduce native query methods to JPA metamodel generator
This commit is contained in:
parent
698b245753
commit
cfe545ec3d
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.annotations;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.CLASS;
|
||||
|
||||
/**
|
||||
* Identifies a method of an abstract class or interface
|
||||
* as defining the signature of a method which is used to
|
||||
* execute the given {@linkplain #value SQL query}, and is
|
||||
* generated automatically by the Hibernate Metamodel
|
||||
* Generator.
|
||||
* <p>
|
||||
* For example:
|
||||
* <pre>
|
||||
* public interface Books {
|
||||
* @Sql("select * from Book where isbn = :isbn")
|
||||
* Book findBookByIsbn(String isbn);
|
||||
*
|
||||
* @Sql("select * from Book where title like ?1 order by title offset ?3 fetch first ?2 rows only")
|
||||
* List<Book> findBooksByTitleWithPagination(String title, int max, int start);
|
||||
*
|
||||
* @Sql("select * from Book where title like ?1")
|
||||
* Query findBooksByTitle(String title);
|
||||
* }
|
||||
* </pre>
|
||||
* <p>
|
||||
* The Metamodel Generator automatically creates an
|
||||
* "implementation" of these methods in the static metamodel
|
||||
* class {@code Books_}.
|
||||
* <pre>
|
||||
* Book book = Books_.findBookByIsbn(session, isbn);
|
||||
* List<Book> books = Books_.findBooksByTitleWithPagination(session, pattern, 10, 0);
|
||||
* </pre>
|
||||
* <p>
|
||||
* The return type of an annotated method must be:
|
||||
* <ul>
|
||||
* <li>an entity type,
|
||||
* <li>{@link java.util.List},
|
||||
* <li>{@link org.hibernate.query.Query},
|
||||
* <li>{@link jakarta.persistence.Query}, or
|
||||
* <li>{@link org.hibernate.query.NativeQuery}.
|
||||
* </ul>
|
||||
* <p>
|
||||
* The method parameters must match the parameters of the
|
||||
* SQL query, either by name or by position.
|
||||
*
|
||||
* @author Gavin King
|
||||
* @since 6.3
|
||||
*/
|
||||
@Target(METHOD)
|
||||
@Retention(CLASS)
|
||||
@Incubating
|
||||
public @interface Sql {
|
||||
String value();
|
||||
}
|
|
@ -39,7 +39,8 @@ import org.hibernate.jpamodelgen.xml.JpaDescriptorParser;
|
|||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import static org.hibernate.jpamodelgen.util.Constants.QUERY_METHOD;
|
||||
import static org.hibernate.jpamodelgen.util.Constants.HQL;
|
||||
import static org.hibernate.jpamodelgen.util.Constants.SQL;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.containsAnnotation;
|
||||
|
||||
/**
|
||||
|
@ -142,7 +143,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
|||
}
|
||||
else if ( element instanceof TypeElement ) {
|
||||
for ( Element enclosedElement : element.getEnclosedElements() ) {
|
||||
if ( containsAnnotation( enclosedElement, QUERY_METHOD ) ) {
|
||||
if ( containsAnnotation( enclosedElement, HQL, SQL ) ) {
|
||||
AnnotationMetaEntity metaEntity =
|
||||
AnnotationMetaEntity.create( (TypeElement) element, context, false );
|
||||
context.addMetaAuxiliary( metaEntity.getQualifiedName(), metaEntity );
|
||||
|
|
|
@ -228,7 +228,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
gettersAndSettersOfClass.add( rawMethodOfClass );
|
||||
}
|
||||
else if ( rawMethodOfClass instanceof ExecutableElement
|
||||
&& containsAnnotation( rawMethodOfClass, Constants.QUERY_METHOD ) ) {
|
||||
&& containsAnnotation( rawMethodOfClass, Constants.HQL, Constants.SQL ) ) {
|
||||
queryMethods.add( (ExecutableElement) rawMethodOfClass );
|
||||
}
|
||||
}
|
||||
|
@ -348,33 +348,53 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
private void addQueryMethod(
|
||||
ExecutableElement method,
|
||||
String methodName,
|
||||
@Nullable String returnTypeName, @Nullable String containerTypeName) {
|
||||
final AnnotationMirror mirror = getAnnotationMirror(method, Constants.QUERY_METHOD );
|
||||
if ( mirror != null ) {
|
||||
final Object queryString = getAnnotationValue( mirror, "value" );
|
||||
if ( queryString instanceof String ) {
|
||||
final List<String> paramNames =
|
||||
method.getParameters().stream()
|
||||
.map(param -> param.getSimpleName().toString())
|
||||
.collect(toList());
|
||||
final List<String> paramTypes =
|
||||
method.getParameters().stream()
|
||||
.map(param -> param.asType().toString())
|
||||
.collect(toList());
|
||||
final String hql = (String) queryString;
|
||||
final QueryMethod attribute =
|
||||
new QueryMethod(
|
||||
this,
|
||||
methodName,
|
||||
hql,
|
||||
returnTypeName,
|
||||
containerTypeName,
|
||||
paramNames,
|
||||
paramTypes
|
||||
);
|
||||
putMember( attribute.getPropertyName(), attribute );
|
||||
@Nullable String returnTypeName,
|
||||
@Nullable String containerTypeName) {
|
||||
final AnnotationMirror hql = getAnnotationMirror(method, Constants.HQL);
|
||||
if ( hql != null ) {
|
||||
addQueryMethod(method, methodName, returnTypeName, containerTypeName, hql, false);
|
||||
}
|
||||
final AnnotationMirror sql = getAnnotationMirror(method, Constants.SQL);
|
||||
if ( sql != null ) {
|
||||
addQueryMethod(method, methodName, returnTypeName, containerTypeName, sql, true);
|
||||
}
|
||||
}
|
||||
|
||||
checkParameters(method, paramNames, mirror, hql);
|
||||
private void addQueryMethod(
|
||||
ExecutableElement method,
|
||||
String methodName,
|
||||
@Nullable
|
||||
String returnTypeName,
|
||||
@Nullable
|
||||
String containerTypeName,
|
||||
AnnotationMirror mirror,
|
||||
boolean isNative) {
|
||||
final Object queryString = getAnnotationValue(mirror, "value" );
|
||||
if ( queryString instanceof String ) {
|
||||
final List<String> paramNames =
|
||||
method.getParameters().stream()
|
||||
.map(param -> param.getSimpleName().toString())
|
||||
.collect(toList());
|
||||
final List<String> paramTypes =
|
||||
method.getParameters().stream()
|
||||
.map(param -> param.asType().toString())
|
||||
.collect(toList());
|
||||
final String hql = (String) queryString;
|
||||
final QueryMethod attribute =
|
||||
new QueryMethod(
|
||||
this,
|
||||
methodName,
|
||||
hql,
|
||||
returnTypeName,
|
||||
containerTypeName,
|
||||
paramNames,
|
||||
paramTypes,
|
||||
isNative
|
||||
);
|
||||
putMember( attribute.getPropertyName(), attribute );
|
||||
|
||||
checkParameters(method, paramNames, mirror, hql);
|
||||
if (!isNative) {
|
||||
checkHqlSyntax(method, mirror, hql);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ public class QueryMethod implements MetaAttribute {
|
|||
private final @Nullable String containerTypeName;
|
||||
private final List<String> paramNames;
|
||||
private final List<String> paramTypes;
|
||||
private final boolean isNative;
|
||||
|
||||
public QueryMethod(
|
||||
Metamodel annotationMetaEntity,
|
||||
|
@ -35,8 +36,8 @@ public class QueryMethod implements MetaAttribute {
|
|||
@Nullable
|
||||
String containerTypeName,
|
||||
List<String> paramNames,
|
||||
List<String> paramTypes
|
||||
) {
|
||||
List<String> paramTypes,
|
||||
boolean isNative) {
|
||||
this.annotationMetaEntity = annotationMetaEntity;
|
||||
this.methodName = methodName;
|
||||
this.queryString = queryString;
|
||||
|
@ -44,6 +45,7 @@ public class QueryMethod implements MetaAttribute {
|
|||
this.containerTypeName = containerTypeName;
|
||||
this.paramNames = paramNames;
|
||||
this.paramTypes = paramTypes;
|
||||
this.isNative = isNative;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,20 +57,18 @@ public class QueryMethod implements MetaAttribute {
|
|||
public String getAttributeDeclarationString() {
|
||||
StringBuilder declaration = new StringBuilder();
|
||||
declaration.append("public static ");
|
||||
StringBuilder type = new StringBuilder();
|
||||
if (containerTypeName != null) {
|
||||
declaration
|
||||
.append(annotationMetaEntity.importType(containerTypeName));
|
||||
type.append(annotationMetaEntity.importType(containerTypeName));
|
||||
if (returnTypeName != null) {
|
||||
declaration
|
||||
.append("<")
|
||||
.append(annotationMetaEntity.importType(returnTypeName))
|
||||
.append(">");
|
||||
type.append("<").append(annotationMetaEntity.importType(returnTypeName)).append(">");
|
||||
}
|
||||
}
|
||||
else if (returnTypeName != null) {
|
||||
declaration.append(annotationMetaEntity.importType(returnTypeName));
|
||||
type.append(annotationMetaEntity.importType(returnTypeName));
|
||||
}
|
||||
declaration
|
||||
.append(type)
|
||||
.append(" ")
|
||||
.append(methodName)
|
||||
.append("(")
|
||||
|
@ -85,7 +85,14 @@ public class QueryMethod implements MetaAttribute {
|
|||
declaration
|
||||
.append(")")
|
||||
.append(" {")
|
||||
.append("\n return entityManager.createQuery(")
|
||||
.append("\n return ");
|
||||
if ( isNative && returnTypeName != null ) {
|
||||
declaration.append("(").append(type).append(") ");
|
||||
}
|
||||
declaration
|
||||
.append("entityManager.")
|
||||
.append(isNative ? "createNativeQuery" :"createQuery")
|
||||
.append("(")
|
||||
.append(getUpperUnderscoreCaseFromLowerCamelCase(methodName));
|
||||
if (returnTypeName != null) {
|
||||
declaration
|
||||
|
|
|
@ -50,7 +50,8 @@ public final class Constants {
|
|||
public static final String HIB_FILTER_DEF = "org.hibernate.annotations.FilterDef";
|
||||
public static final String HIB_FILTER_DEFS = "org.hibernate.annotations.FilterDefs";
|
||||
|
||||
public static final String QUERY_METHOD = "org.hibernate.annotations.Hql";
|
||||
public static final String HQL = "org.hibernate.annotations.Hql";
|
||||
public static final String SQL = "org.hibernate.annotations.Sql";
|
||||
|
||||
public static final Map<String, String> COLLECTIONS = allCollectionTypes();
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.hibernate.jpamodelgen.test.namedquery;
|
|||
|
||||
import jakarta.persistence.TypedQuery;
|
||||
import org.hibernate.annotations.Hql;
|
||||
import org.hibernate.annotations.Sql;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -14,4 +15,7 @@ public interface Dao {
|
|||
|
||||
@Hql("from Book where isbn = :isbn")
|
||||
Book findByIsbn(String isbn);
|
||||
|
||||
@Sql("select * from Book where isbn = :isbn")
|
||||
Book findByIsbnNative(String isbn);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue