HHH-16633 allow finder and query methods to accept the session type as a parameter

This commit is contained in:
Gavin King 2023-07-14 00:56:22 +02:00
parent a80224f921
commit 803cd6aa1e
10 changed files with 257 additions and 180 deletions

View File

@ -7,7 +7,6 @@
package org.hibernate.jpamodelgen.annotation;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.jpamodelgen.model.MetaAttribute;
import org.hibernate.jpamodelgen.model.Metamodel;
import org.hibernate.jpamodelgen.util.Constants;
@ -19,41 +18,24 @@ import static org.hibernate.jpamodelgen.util.StringUtil.getUpperUnderscoreCaseFr
/**
* @author Gavin King
*/
public abstract class AbstractFinderMethod implements MetaAttribute {
final Metamodel annotationMetaEntity;
final String methodName;
public abstract class AbstractFinderMethod extends AbstractQueryMethod {
final String entity;
final boolean belongsToDao;
final String sessionType;
final boolean usingEntityManager;
final boolean reactive;
private final boolean addNonnullAnnotation;
final List<String> fetchProfiles;
final List<String> paramNames;
final List<String> paramTypes;
public AbstractFinderMethod(
Metamodel annotationMetaEntity,
String methodName,
String entity,
boolean belongsToDao,
String sessionType,
String sessionName,
List<String> fetchProfiles,
List<String> paramNames,
List<String> paramTypes,
boolean addNonnullAnnotation) {
this.annotationMetaEntity = annotationMetaEntity;
this.methodName = methodName;
super( annotationMetaEntity, methodName, paramNames, paramTypes, sessionType, sessionName, belongsToDao, addNonnullAnnotation );
this.entity = entity;
this.belongsToDao = belongsToDao;
this.sessionType = sessionType;
this.fetchProfiles = fetchProfiles;
this.paramNames = paramNames;
this.paramTypes = paramTypes;
this.addNonnullAnnotation = addNonnullAnnotation;
this.usingEntityManager = Constants.ENTITY_MANAGER.equals(sessionType);
this.reactive = Constants.MUTINY_SESSION.equals(sessionType);
}
@Override
@ -66,26 +48,11 @@ public abstract class AbstractFinderMethod implements MetaAttribute {
return false;
}
@Override
public String getMetaType() {
throw new UnsupportedOperationException();
}
@Override
public String getPropertyName() {
return methodName;
}
@Override
public String getTypeDeclaration() {
return entity;
}
@Override
public Metamodel getHostingEntity() {
return annotationMetaEntity;
}
abstract boolean isId();
@Override
@ -104,20 +71,6 @@ public abstract class AbstractFinderMethod implements MetaAttribute {
.toString();
}
private String parameterList() {
return paramTypes.stream()
.map(this::strip)
.map(annotationMetaEntity::importType)
.reduce((x, y) -> x + ',' + y)
.orElse("");
}
private String strip(String type) {
int index = type.indexOf("<");
String stripped = index > 0 ? type.substring(0, index) : type;
return type.endsWith("...") ? stripped + "..." : stripped;
}
String constantName() {
return getUpperUnderscoreCaseFromLowerCamelCase(methodName) + "_BY_"
+ paramNames.stream()
@ -212,7 +165,8 @@ public abstract class AbstractFinderMethod implements MetaAttribute {
parameters( declaration) ;
declaration
.append(" {")
.append("\n\treturn entityManager");
.append("\n\treturn ")
.append(sessionName);
}
private void entityType(StringBuilder declaration) {
@ -237,12 +191,7 @@ public abstract class AbstractFinderMethod implements MetaAttribute {
void parameters(StringBuilder declaration) {
declaration
.append("(");
if ( !belongsToDao ) {
notNull( declaration );
declaration
.append(annotationMetaEntity.importType(Constants.ENTITY_MANAGER))
.append(" entityManager");
}
sessionParameter( declaration );
for ( int i = 0; i < paramNames.size(); i ++ ) {
if ( !belongsToDao || i > 0 ) {
declaration
@ -259,13 +208,4 @@ public abstract class AbstractFinderMethod implements MetaAttribute {
declaration
.append(')');
}
private void notNull(StringBuilder declaration) {
if ( addNonnullAnnotation ) {
declaration
.append('@')
.append(annotationMetaEntity.importType("jakarta.annotation.Nonnull"))
.append(' ');
}
}
}

View File

@ -0,0 +1,100 @@
/*
* 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.jpamodelgen.annotation;
import org.hibernate.jpamodelgen.model.MetaAttribute;
import org.hibernate.jpamodelgen.model.Metamodel;
import org.hibernate.jpamodelgen.util.Constants;
import java.util.List;
import java.util.Set;
import static org.hibernate.jpamodelgen.util.Constants.SESSION_TYPES;
/**
* @author Gavin King
*/
public abstract class AbstractQueryMethod implements MetaAttribute {
final Metamodel annotationMetaEntity;
final String methodName;
final List<String> paramNames;
final List<String> paramTypes;
final String sessionType;
final String sessionName;
final boolean belongsToDao;
final boolean usingEntityManager;
final boolean reactive;
final boolean addNonnullAnnotation;
public AbstractQueryMethod(
Metamodel annotationMetaEntity,
String methodName,
List<String> paramNames, List<String> paramTypes,
String sessionType,
String sessionName,
boolean belongsToDao,
boolean addNonnullAnnotation) {
this.annotationMetaEntity = annotationMetaEntity;
this.methodName = methodName;
this.paramNames = paramNames;
this.paramTypes = paramTypes;
this.sessionType = sessionType;
this.sessionName = sessionName;
this.belongsToDao = belongsToDao;
this.addNonnullAnnotation = addNonnullAnnotation;
this.usingEntityManager = Constants.ENTITY_MANAGER.equals(sessionType);
this.reactive = Constants.MUTINY_SESSION.equals(sessionType);
}
@Override
public Metamodel getHostingEntity() {
return annotationMetaEntity;
}
@Override
public String getMetaType() {
throw new UnsupportedOperationException();
}
@Override
public String getPropertyName() {
return methodName;
}
String parameterList() {
return paramTypes.stream()
.map(this::strip)
.map(annotationMetaEntity::importType)
.reduce((x, y) -> x + ',' + y)
.orElse("");
}
String strip(String type) {
int index = type.indexOf("<");
String stripped = index > 0 ? type.substring(0, index) : type;
return type.endsWith("...") ? stripped + "..." : stripped;
}
void sessionParameter(StringBuilder declaration) {
if ( !belongsToDao ) {
notNull(declaration);
declaration
.append(annotationMetaEntity.importType(sessionType))
.append(' ')
.append(sessionName);
}
}
void notNull(StringBuilder declaration) {
if ( addNonnullAnnotation ) {
declaration
.append('@')
.append(annotationMetaEntity.importType("jakarta.annotation.Nonnull"))
.append(' ');
}
}
}

View File

@ -49,6 +49,7 @@ import static javax.lang.model.util.ElementFilter.fieldsIn;
import static javax.lang.model.util.ElementFilter.methodsIn;
import static org.hibernate.jpamodelgen.annotation.QueryMethod.isOrderParam;
import static org.hibernate.jpamodelgen.annotation.QueryMethod.isPageParam;
import static org.hibernate.jpamodelgen.util.Constants.SESSION_TYPES;
import static org.hibernate.jpamodelgen.util.NullnessUtil.castNonNull;
import static org.hibernate.jpamodelgen.util.TypeUtils.containsAnnotation;
import static org.hibernate.jpamodelgen.util.TypeUtils.determineAccessTypeForHierarchy;
@ -494,7 +495,11 @@ public class AnnotationMetaEntity extends AnnotationMeta {
createCriteriaFinder( method, returnType, containerType, entity );
}
else {
switch ( method.getParameters().size() ) {
final long parameterCount =
method.getParameters().stream()
.filter(AnnotationMetaEntity::isFinderParameterMappingToAttribute)
.count();
switch ( (int) parameterCount ) {
case 0:
context.message( method, "missing parameter", Diagnostic.Kind.ERROR );
break;
@ -517,9 +522,13 @@ public class AnnotationMetaEntity extends AnnotationMeta {
final String methodName = method.getSimpleName().toString();
final List<String> paramNames = parameterNames(method);
final List<String> paramTypes = parameterTypes(method);
final String[] sessionType = sessionTypeFromParameters( paramNames, paramTypes );
removeSessionFromParameters(paramNames, paramTypes);
final String methodKey = methodName + paramTypes;
for ( VariableElement param : method.getParameters() ) {
validateFinderParameter(entity, param );
if ( isFinderParameterMappingToAttribute( param ) ) {
validateFinderParameter( entity, param );
}
}
putMember( methodKey,
new CriteriaFinderMethod(
@ -531,13 +540,40 @@ public class AnnotationMetaEntity extends AnnotationMeta {
paramTypes,
false,
dao,
sessionType,
sessionType[0],
sessionType[1],
enabledFetchProfiles( method ),
context.addNonnullAnnotation()
)
);
}
private static boolean isFinderParameterMappingToAttribute(VariableElement param) {
return !SESSION_TYPES.contains(param.asType().toString());
}
private static void removeSessionFromParameters(List<String> paramNames, List<String> paramTypes) {
for ( int i = 0; i < paramNames.size(); i ++ ) {
final String type = paramTypes.get(i);
if ( SESSION_TYPES.contains(type) ) {
paramNames.remove(i);
paramTypes.remove(i);
break;
}
}
}
private String[] sessionTypeFromParameters(List<String> paramNames, List<String> paramTypes) {
for ( int i = 0; i < paramNames.size(); i ++ ) {
final String type = paramTypes.get(i);
final String name = paramNames.get(i);
if ( SESSION_TYPES.contains(type) ) {
return new String[] { type, name };
}
}
return new String[] { sessionType, "entityManager" };
}
private static List<String> enabledFetchProfiles(ExecutableElement method) {
final Object enabledFetchProfiles =
getAnnotationValue( castNonNull( getAnnotationMirror( method, Constants.FIND ) ),
@ -560,8 +596,10 @@ public class AnnotationMetaEntity extends AnnotationMeta {
final String methodName = method.getSimpleName().toString();
final List<String> paramNames = parameterNames( method );
final List<String> paramTypes = parameterTypes( method );
final String[] sessionType = sessionTypeFromParameters( paramNames, paramTypes );
removeSessionFromParameters( paramNames, paramTypes );
final String methodKey = methodName + paramTypes;
if ( !usingStatelessSession() // no byNaturalId() lookup API for SS
if ( !usingStatelessSession(sessionType[0]) // no byNaturalId() lookup API for SS
&& matchesNaturalKey( method, entity ) ) {
putMember( methodKey,
new NaturalIdFinderMethod(
@ -571,7 +609,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
paramNames,
paramTypes,
dao,
sessionType,
sessionType[0],
sessionType[1],
enabledFetchProfiles( method ),
context.addNonnullAnnotation()
)
@ -588,7 +627,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
paramTypes,
false,
dao,
sessionType,
sessionType[0],
sessionType[1],
enabledFetchProfiles( method ),
context.addNonnullAnnotation()
)
@ -598,22 +638,30 @@ public class AnnotationMetaEntity extends AnnotationMeta {
private void createSingleParameterFinder(ExecutableElement method, TypeMirror returnType, TypeElement entity) {
final String methodName = method.getSimpleName().toString();
final VariableElement parameter = method.getParameters().get(0);
final VariableElement parameter =
method.getParameters().stream()
.filter(AnnotationMetaEntity::isFinderParameterMappingToAttribute)
.findFirst().orElseThrow();
final List<String> paramNames = parameterNames(method);
final List<String> paramTypes = parameterTypes(method);
final String[] sessionType = sessionTypeFromParameters( paramNames, paramTypes );
removeSessionFromParameters(paramNames, paramTypes);
final FieldType fieldType = validateFinderParameter( entity, parameter );
if ( fieldType != null ) {
final String methodKey = methodName + "!";
final List<String> profiles = enabledFetchProfiles( method );
switch ( pickStrategy( fieldType, profiles ) ) {
switch ( pickStrategy( fieldType, sessionType[0], profiles ) ) {
case ID:
putMember( methodKey,
new IdFinderMethod(
this,
methodName,
returnType.toString(),
parameter.getSimpleName().toString(),
parameter.asType().toString(),
paramNames.get(0),
paramTypes.get(0),
dao,
sessionType,
sessionType[0],
sessionType[1],
profiles,
context.addNonnullAnnotation()
)
@ -625,10 +673,11 @@ public class AnnotationMetaEntity extends AnnotationMeta {
this,
methodName,
returnType.toString(),
List.of( parameter.getSimpleName().toString() ),
List.of( parameter.asType().toString() ),
paramNames,
paramTypes,
dao,
sessionType,
sessionType[0],
sessionType[1],
profiles,
context.addNonnullAnnotation()
)
@ -641,11 +690,12 @@ public class AnnotationMetaEntity extends AnnotationMeta {
methodName,
returnType.toString(),
null,
List.of( parameter.getSimpleName().toString() ),
List.of( parameter.asType().toString() ),
paramNames,
paramTypes,
fieldType == FieldType.ID,
dao,
sessionType,
sessionType[0],
sessionType[1],
profiles,
context.addNonnullAnnotation()
)
@ -655,16 +705,16 @@ public class AnnotationMetaEntity extends AnnotationMeta {
}
}
private FieldType pickStrategy(FieldType fieldType, List<String> profiles) {
private FieldType pickStrategy(FieldType fieldType, String sessionType, List<String> profiles) {
switch (fieldType) {
case ID:
// no byId() API for SS or M.S, only get()
return (usingStatelessSession() || usingReactiveSession()) && !profiles.isEmpty()
return (usingStatelessSession(sessionType) || usingReactiveSession(sessionType)) && !profiles.isEmpty()
? FieldType.BASIC : FieldType.ID;
case NATURAL_ID:
// no byNaturalId() lookup API for SS
// no byNaturalId() in M.S, but we do have Identifier workaround
return usingStatelessSession() || (usingReactiveSession() && !profiles.isEmpty())
return usingStatelessSession(sessionType) || (usingReactiveSession(sessionType) && !profiles.isEmpty())
? FieldType.BASIC : FieldType.NATURAL_ID;
default:
return FieldType.BASIC;
@ -673,12 +723,14 @@ public class AnnotationMetaEntity extends AnnotationMeta {
private boolean matchesNaturalKey(ExecutableElement method, TypeElement entity) {
boolean result = true;
List<? extends VariableElement> parameters = method.getParameters();
for ( VariableElement param : parameters) {
if ( validateFinderParameter( entity, param ) != FieldType.NATURAL_ID ) {
// no short-circuit here because we want to validate
// all of them and get the nice error report
result = false;
final List<? extends VariableElement> parameters = method.getParameters();
for ( VariableElement param : parameters ) {
if ( isFinderParameterMappingToAttribute( param ) ) {
if ( validateFinderParameter( entity, param ) != FieldType.NATURAL_ID ) {
// no short-circuit here because we want to validate
// all of them and get the nice error report
result = false;
}
}
}
return result && countNaturalIdFields( entity ) == parameters.size() ;
@ -781,7 +833,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
final String hql = (String) query;
final List<String> paramNames = parameterNames( method );
final List<String> paramTypes = parameterTypes( method );
final String[] sessionType = sessionTypeFromParameters( paramNames, paramTypes );
removeSessionFromParameters(paramNames, paramTypes);
final QueryMethod attribute =
new QueryMethod(
this,
@ -793,7 +846,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
paramTypes,
isNative,
dao,
sessionType,
sessionType[0],
sessionType[1],
context.addNonnullAnnotation()
);
putMember( attribute.getPropertyName() + paramTypes, attribute );
@ -923,11 +977,11 @@ public class AnnotationMetaEntity extends AnnotationMeta {
&& !isOrderParam(type);
}
private boolean usingReactiveSession() {
private boolean usingReactiveSession(String sessionType) {
return Constants.MUTINY_SESSION.equals(sessionType);
}
private boolean usingStatelessSession() {
private boolean usingStatelessSession(String sessionType) {
return Constants.HIB_STATELESS_SESSION.equals(sessionType);
}
}

View File

@ -29,9 +29,10 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
boolean isId,
boolean belongsToDao,
String sessionType,
String sessionName,
List<String> fetchProfiles,
boolean addNonnullAnnotation) {
super( annotationMetaEntity, methodName, entity, belongsToDao, sessionType, fetchProfiles,
super( annotationMetaEntity, methodName, entity, belongsToDao, sessionType, sessionName, fetchProfiles,
paramNames, paramTypes, addNonnullAnnotation );
this.containerType = containerType;
this.isId = isId;
@ -61,7 +62,8 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
.append(" == null) throw new IllegalArgumentException(\"Null identifier\");");
}
declaration
.append("\n\tvar builder = entityManager")
.append("\n\tvar builder = ")
.append(sessionName)
.append(usingEntityManager
? ".getEntityManagerFactory()"
: ".getFactory()")
@ -104,7 +106,9 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
}
declaration
.append("\n\t);")
.append("\n\treturn entityManager.createQuery(query)");
.append("\n\treturn ")
.append(sessionName)
.append(".createQuery(query)");
final boolean hasEnabledFetchProfiles = !fetchProfiles.isEmpty();
final boolean hasNativeReturnType = containerType != null && containerType.startsWith("org.hibernate");
final boolean unwrap =

View File

@ -25,9 +25,10 @@ public class IdFinderMethod extends AbstractFinderMethod {
String paramName, String paramType,
boolean belongsToDao,
String sessionType,
String sessionName,
List<String> fetchProfiles,
boolean addNonnullAnnotation) {
super( annotationMetaEntity, methodName, entity, belongsToDao, sessionType, fetchProfiles,
super( annotationMetaEntity, methodName, entity, belongsToDao, sessionType, sessionName, fetchProfiles,
List.of(paramName), List.of(paramType), addNonnullAnnotation );
this.paramName = paramName;
usingStatelessSession = Constants.HIB_STATELESS_SESSION.equals(sessionType);

View File

@ -21,9 +21,10 @@ public class NaturalIdFinderMethod extends AbstractFinderMethod {
List<String> paramNames, List<String> paramTypes,
boolean belongsToDao,
String sessionType,
String sessionName,
List<String> fetchProfiles,
boolean addNonnullAnnotation) {
super( annotationMetaEntity, methodName, entity, belongsToDao, sessionType, fetchProfiles,
super( annotationMetaEntity, methodName, entity, belongsToDao, sessionType, sessionName, fetchProfiles,
paramNames, paramTypes, addNonnullAnnotation );
}

View File

@ -8,7 +8,6 @@ package org.hibernate.jpamodelgen.annotation;
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.jpamodelgen.util.Constants;
import org.hibernate.query.Order;
@ -22,19 +21,11 @@ import static org.hibernate.jpamodelgen.util.StringUtil.getUpperUnderscoreCaseFr
/**
* @author Gavin King
*/
public class QueryMethod implements MetaAttribute {
private final Metamodel annotationMetaEntity;
private final String methodName;
public class QueryMethod extends AbstractQueryMethod {
private final String queryString;
private final @Nullable String returnTypeName;
private final @Nullable String containerTypeName;
private final List<String> paramNames;
private final List<String> paramTypes;
private final boolean isNative;
private final boolean belongsToDao;
private final boolean usingEntityManager;
private final boolean reactive;
private final boolean addNonnullAnnotation;
public QueryMethod(
Metamodel annotationMetaEntity,
@ -49,19 +40,13 @@ public class QueryMethod implements MetaAttribute {
boolean isNative,
boolean belongsToDao,
String sessionType,
String sessionName,
boolean addNonnullAnnotation) {
this.annotationMetaEntity = annotationMetaEntity;
this.methodName = methodName;
super( annotationMetaEntity, methodName, paramNames, paramTypes, sessionType, sessionName, belongsToDao, addNonnullAnnotation );
this.queryString = queryString;
this.returnTypeName = returnTypeName;
this.containerTypeName = containerTypeName;
this.paramNames = paramNames;
this.paramTypes = paramTypes;
this.isNative = isNative;
this.belongsToDao = belongsToDao;
this.addNonnullAnnotation = addNonnullAnnotation;
this.usingEntityManager = Constants.ENTITY_MANAGER.equals(sessionType);
this.reactive = Constants.MUTINY_SESSION.equals(sessionType);
}
@Override
@ -98,8 +83,8 @@ public class QueryMethod implements MetaAttribute {
.append(") ");
}
declaration
.append("entityManager.")
.append(isNative ? "createNativeQuery" : "createQuery")
.append(sessionName)
.append(isNative ? ".createNativeQuery" : ".createQuery")
.append("(")
.append(getConstantName());
if ( returnTypeName != null ) {
@ -210,30 +195,22 @@ public class QueryMethod implements MetaAttribute {
}
private void parameters(List<String> paramTypes, StringBuilder declaration) {
declaration.append("(");
if ( !belongsToDao ) {
notNull( declaration );
declaration
.append(annotationMetaEntity.importType(Constants.ENTITY_MANAGER))
.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;
if ( !belongsToDao || i>0 ) {
declaration
.append("(");
sessionParameter( declaration );
for ( int i = 0; i < paramNames.size(); i++ ) {
if ( !belongsToDao || i > 0 ) {
declaration
.append(", ");
}
final String type = paramTypes.get(i);
final String paramType = returnTypeName != null
? type.replace(returnTypeName, annotationMetaEntity.importType(returnTypeName))
: type;
declaration
.append(annotationMetaEntity.importType(rptype))
.append(annotationMetaEntity.importType(paramType))
.append(" ")
.append(param);
.append(paramNames.get(i));
}
declaration
.append(")");
@ -301,20 +278,6 @@ public class QueryMethod implements MetaAttribute {
}
}
private String parameterList() {
return paramTypes.stream()
.map(this::strip)
.map(annotationMetaEntity::importType)
.reduce((x, y) -> x + ',' + y)
.orElse("");
}
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 parameterType) {
return Page.class.getName().equals(parameterType);
}
@ -359,32 +322,7 @@ public class QueryMethod implements MetaAttribute {
}
}
private void notNull(StringBuilder declaration) {
if ( addNonnullAnnotation ) {
declaration
.append('@')
.append(annotationMetaEntity.importType("jakarta.annotation.Nonnull"))
.append(' ');
}
}
@Override
public String getMetaType() {
throw new UnsupportedOperationException();
}
@Override
public String getPropertyName() {
return methodName;
}
@Override
public String getTypeDeclaration() {
return Constants.QUERY;
}
@Override
public Metamodel getHostingEntity() {
return annotationMetaEntity;
}
}

View File

@ -95,6 +95,14 @@ public final class Constants {
java.util.SortedMap.class.getName(), Constants.MAP_ATTRIBUTE
);
public static final Set<String> SESSION_TYPES =
Set.of(
Constants.ENTITY_MANAGER,
Constants.HIB_SESSION,
Constants.HIB_STATELESS_SESSION,
Constants.MUTINY_SESSION
);
//TODO: this is not even an exhaustive list of built-in basic types
// so any logic that relies on incomplete this list is broken!
public static final Set<String> BASIC_TYPES = Set.of(

View File

@ -0,0 +1,29 @@
package org.hibernate.jpamodelgen.test.hqlsql;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import org.hibernate.Session;
import org.hibernate.StatelessSession;
import org.hibernate.annotations.processing.Find;
import org.hibernate.annotations.processing.HQL;
import java.util.List;
public abstract class Books {
@Find
abstract Book getBook(EntityManager entityManager, String isbn);
@Find
abstract Book getBook(StatelessSession session, String title, String isbn);
@Find
abstract Book getBookByNaturalKey(Session session, String authorName, String title);
@HQL("from Book where title like ?1")
abstract TypedQuery<Book> findByTitle(EntityManager entityManager, String title);
@HQL("from Book where title like ?1 order by title fetch first ?2 rows only")
abstract List<Book> findFirstNByTitle(Session session, String title, int N);
}

View File

@ -18,10 +18,12 @@ import static org.hibernate.jpamodelgen.test.util.TestUtil.assertMetamodelClassG
*/
public class QueryMethodTest extends CompilationTest {
@Test
@WithClasses({ Book.class, Dao.class })
@WithClasses({ Book.class, Dao.class, Books.class })
public void testQueryMethod() {
System.out.println( TestUtil.getMetaModelSourceAsString( Dao.class ) );
System.out.println( TestUtil.getMetaModelSourceAsString( Books.class ) );
assertMetamodelClassGeneratedFor( Book.class );
assertMetamodelClassGeneratedFor( Dao.class );
assertMetamodelClassGeneratedFor( Books.class );
}
}