HHH-16633 add ability to specify fetch profiles in @Find annotation

This commit is contained in:
Gavin King 2023-07-08 22:45:25 +02:00
parent 09f110254f
commit 17ea1e28b9
13 changed files with 139 additions and 19 deletions

View File

@ -61,4 +61,6 @@ import static java.lang.annotation.RetentionPolicy.CLASS;
@Target(METHOD) @Target(METHOD)
@Retention(CLASS) @Retention(CLASS)
@Incubating @Incubating
public @interface Find {} public @interface Find {
String[] enabledFetchProfiles() default {};
}

View File

@ -264,10 +264,13 @@ public class LoadQueryInfluencers implements Serializable {
public HashSet<String> adjustFetchProfiles(Set<String> disabledFetchProfiles, Set<String> enabledFetchProfiles) { public HashSet<String> adjustFetchProfiles(Set<String> disabledFetchProfiles, Set<String> enabledFetchProfiles) {
final HashSet<String> oldFetchProfiles = final HashSet<String> oldFetchProfiles =
hasEnabledFetchProfiles() ? new HashSet<>( enabledFetchProfileNames ) : null; hasEnabledFetchProfiles() ? new HashSet<>( enabledFetchProfileNames ) : null;
if ( disabledFetchProfiles != null ) { if ( disabledFetchProfiles != null && enabledFetchProfileNames != null ) {
enabledFetchProfileNames.removeAll( disabledFetchProfiles ); enabledFetchProfileNames.removeAll( disabledFetchProfiles );
} }
if ( enabledFetchProfiles != null ) { if ( enabledFetchProfiles != null ) {
if ( enabledFetchProfileNames == null ) {
enabledFetchProfileNames = new HashSet<>();
}
enabledFetchProfileNames.addAll( enabledFetchProfiles ); enabledFetchProfileNames.addAll( enabledFetchProfiles );
} }
return oldFetchProfiles; return oldFetchProfiles;

View File

@ -14,6 +14,7 @@ import java.util.Set;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.IdentifierLoadAccess; import org.hibernate.IdentifierLoadAccess;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.UnknownProfileException;
import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.LoadQueryInfluencers;
@ -61,6 +62,9 @@ public abstract class BaseNaturalIdLoadAccessImpl<T> implements NaturalIdLoadOpt
} }
public Object enableFetchProfile(String profileName) { public Object enableFetchProfile(String profileName) {
if ( !context.getSession().getFactory().containsFetchProfileDefinition( profileName ) ) {
throw new UnknownProfileException( profileName );
}
if ( enabledFetchProfiles == null ) { if ( enabledFetchProfiles == null ) {
enabledFetchProfiles = new HashSet<>(); enabledFetchProfiles = new HashSet<>();
} }

View File

@ -15,6 +15,7 @@ import org.hibernate.CacheMode;
import org.hibernate.IdentifierLoadAccess; import org.hibernate.IdentifierLoadAccess;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.ObjectNotFoundException; import org.hibernate.ObjectNotFoundException;
import org.hibernate.UnknownProfileException;
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
@ -279,6 +280,9 @@ public class IdentifierLoadAccessImpl<T> implements IdentifierLoadAccess<T>, Jav
@Override @Override
public IdentifierLoadAccess<T> enableFetchProfile(String profileName) { public IdentifierLoadAccess<T> enableFetchProfile(String profileName) {
if ( !context.getSession().getFactory().containsFetchProfileDefinition( profileName ) ) {
throw new UnknownProfileException( profileName );
}
if ( enabledFetchProfiles == null ) { if ( enabledFetchProfiles == null ) {
enabledFetchProfiles = new HashSet<>(); enabledFetchProfiles = new HashSet<>();
} }

View File

@ -40,6 +40,7 @@ import org.hibernate.LockOptions;
import org.hibernate.NonUniqueResultException; import org.hibernate.NonUniqueResultException;
import org.hibernate.ScrollMode; import org.hibernate.ScrollMode;
import org.hibernate.TypeMismatchException; import org.hibernate.TypeMismatchException;
import org.hibernate.UnknownProfileException;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.GraphSemantic;
@ -649,6 +650,9 @@ public abstract class AbstractSelectionQuery<R>
@Override @Override
public SelectionQuery<R> enableFetchProfile(String profileName) { public SelectionQuery<R> enableFetchProfile(String profileName) {
if ( !getSession().getFactory().containsFetchProfileDefinition( profileName ) ) {
throw new UnknownProfileException( profileName );
}
getQueryOptions().enableFetchProfile( profileName ); getQueryOptions().enableFetchProfile( profileName );
return this; return this;
} }

View File

@ -12,6 +12,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element; import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind; import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
@ -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 static java.util.Collections.emptyList;
import static java.util.Collections.emptySet; import static java.util.Collections.emptySet;
import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toList;
import static javax.lang.model.util.ElementFilter.fieldsIn; import static javax.lang.model.util.ElementFilter.fieldsIn;
@ -468,11 +470,26 @@ public class AnnotationMetaEntity extends AnnotationMeta {
paramNames, paramNames,
paramTypes, paramTypes,
dao, dao,
sessionType sessionType,
enabledFetchProfiles( method )
) )
); );
} }
private static List<String> enabledFetchProfiles(ExecutableElement method) {
final Object enabledFetchProfiles =
getAnnotationValue( castNonNull( getAnnotationMirror( method, Constants.FIND ) ),
"enabledFetchProfiles" );
if ( enabledFetchProfiles == null ) {
return emptyList();
}
else {
@SuppressWarnings("unchecked")
final List<AnnotationValue> annotationValues = (List<AnnotationValue>) enabledFetchProfiles;
return annotationValues.stream().map(AnnotationValue::toString).collect(toList());
}
}
private void createMultipleParameterFinder(ExecutableElement method, TypeMirror returnType, TypeElement entity) { private void createMultipleParameterFinder(ExecutableElement method, TypeMirror returnType, TypeElement entity) {
final String methodName = method.getSimpleName().toString(); final String methodName = method.getSimpleName().toString();
final List<String> paramNames = parameterNames(method); final List<String> paramNames = parameterNames(method);
@ -487,7 +504,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
paramNames, paramNames,
paramTypes, paramTypes,
dao, dao,
sessionType sessionType,
enabledFetchProfiles( method )
) )
); );
} }
@ -501,7 +519,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
paramNames, paramNames,
paramTypes, paramTypes,
dao, dao,
sessionType sessionType,
enabledFetchProfiles( method )
) )
); );
} }
@ -523,7 +542,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
List.of( parameter.getSimpleName().toString() ), List.of( parameter.getSimpleName().toString() ),
List.of( parameter.asType().toString() ), List.of( parameter.asType().toString() ),
dao, dao,
sessionType sessionType,
enabledFetchProfiles( method )
) )
); );
break; break;
@ -536,7 +556,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
parameter.getSimpleName().toString(), parameter.getSimpleName().toString(),
parameter.asType().toString(), parameter.asType().toString(),
dao, dao,
sessionType sessionType,
enabledFetchProfiles( method )
) )
); );
break; break;
@ -550,7 +571,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
List.of( parameter.getSimpleName().toString() ), List.of( parameter.getSimpleName().toString() ),
List.of( parameter.asType().toString() ), List.of( parameter.asType().toString() ),
dao, dao,
sessionType sessionType,
enabledFetchProfiles( method )
) )
); );
break; break;

View File

@ -27,6 +27,7 @@ public class CriteriaFinderMethod implements MetaAttribute {
private final List<String> paramTypes; private final List<String> paramTypes;
private final boolean belongsToDao; private final boolean belongsToDao;
private final String sessionType; private final String sessionType;
private final List<String> fetchProfiles;
public CriteriaFinderMethod( public CriteriaFinderMethod(
Metamodel annotationMetaEntity, Metamodel annotationMetaEntity,
@ -34,7 +35,8 @@ public class CriteriaFinderMethod implements MetaAttribute {
@Nullable String containerType, @Nullable String containerType,
List<String> paramNames, List<String> paramTypes, List<String> paramNames, List<String> paramTypes,
boolean belongsToDao, boolean belongsToDao,
String sessionType) { String sessionType,
List<String> fetchProfiles) {
this.annotationMetaEntity = annotationMetaEntity; this.annotationMetaEntity = annotationMetaEntity;
this.methodName = methodName; this.methodName = methodName;
this.entity = entity; this.entity = entity;
@ -43,6 +45,7 @@ public class CriteriaFinderMethod implements MetaAttribute {
this.paramTypes = paramTypes; this.paramTypes = paramTypes;
this.belongsToDao = belongsToDao; this.belongsToDao = belongsToDao;
this.sessionType = sessionType; this.sessionType = sessionType;
this.fetchProfiles = fetchProfiles;
} }
@Override @Override
@ -146,6 +149,23 @@ public class CriteriaFinderMethod implements MetaAttribute {
} }
declaration declaration
.append("entityManager.createQuery(query)"); .append("entityManager.createQuery(query)");
if ( !fetchProfiles.isEmpty() ) {
if ( Constants.ENTITY_MANAGER.equals(sessionType) ) {
declaration
.append("\n\t\t\t.unwrap(")
.append(annotationMetaEntity.importType(Constants.HIB_SELECTION_QUERY))
.append(".class)");
}
}
for ( String profile : fetchProfiles ) {
declaration
.append("\n\t\t\t.enableFetchProfile(")
.append(profile)
.append(")");
}
if ( !fetchProfiles.isEmpty() ) {
declaration.append("\n\t\t\t");
}
if ( containerType == null) { if ( containerType == null) {
declaration declaration
.append(".getSingleResult()"); .append(".getSingleResult()");

View File

@ -10,6 +10,8 @@ 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 java.util.List;
/** /**
* @author Gavin King * @author Gavin King
*/ */
@ -21,13 +23,15 @@ public class IdFinderMethod implements MetaAttribute {
private final String paramType; private final String paramType;
private final boolean belongsToDao; private final boolean belongsToDao;
private final String sessionType; private final String sessionType;
private final List<String> fetchProfiles;
public IdFinderMethod( public IdFinderMethod(
Metamodel annotationMetaEntity, Metamodel annotationMetaEntity,
String methodName, String entity, String methodName, String entity,
String paramName, String paramType, String paramName, String paramType,
boolean belongsToDao, boolean belongsToDao,
String sessionType) { String sessionType,
List<String> fetchProfiles) {
this.annotationMetaEntity = annotationMetaEntity; this.annotationMetaEntity = annotationMetaEntity;
this.methodName = methodName; this.methodName = methodName;
this.entity = entity; this.entity = entity;
@ -35,6 +39,7 @@ public class IdFinderMethod implements MetaAttribute {
this.paramType = paramType; this.paramType = paramType;
this.belongsToDao = belongsToDao; this.belongsToDao = belongsToDao;
this.sessionType = sessionType; this.sessionType = sessionType;
this.fetchProfiles = fetchProfiles;
} }
@Override @Override
@ -83,13 +88,39 @@ public class IdFinderMethod implements MetaAttribute {
.append(" ") .append(" ")
.append(paramName) .append(paramName)
.append(") {") .append(") {")
.append("\n\treturn entityManager") .append("\n\treturn entityManager");
.append(Constants.HIB_STATELESS_SESSION.equals(sessionType) ? ".get(" : ".find(") if ( fetchProfiles.isEmpty() ) {
.append(annotationMetaEntity.importType(entity)) declaration
.append(".class, ") .append(Constants.HIB_STATELESS_SESSION.equals(sessionType) ? ".get(" : ".find(")
.append(paramName) .append(annotationMetaEntity.importType(entity))
.append(");") .append(".class, ")
.append("\n}"); .append(paramName)
.append(");")
.append("\n}");
}
else {
if ( Constants.ENTITY_MANAGER.equals(sessionType) ) {
declaration
.append(".unwrap(")
.append(annotationMetaEntity.importType(Constants.HIB_SESSION))
.append(".class)\n\t\t\t");
}
declaration
.append(".byId(")
.append(annotationMetaEntity.importType(entity))
.append(".class)");
for ( String profile : fetchProfiles ) {
declaration
.append("\n\t\t\t.enableFetchProfile(")
.append(profile)
.append(")");
}
declaration
.append("\n\t\t\t.load(")
.append(paramName)
.append(");\n}");
}
return declaration.toString(); return declaration.toString();
} }

View File

@ -23,13 +23,15 @@ public class NaturalIdFinderMethod implements MetaAttribute {
private final List<String> paramTypes; private final List<String> paramTypes;
private final boolean belongsToDao; private final boolean belongsToDao;
private final String sessionType; private final String sessionType;
private final List<String> fetchProfiles;
public NaturalIdFinderMethod( public NaturalIdFinderMethod(
Metamodel annotationMetaEntity, Metamodel annotationMetaEntity,
String methodName, String entity, String methodName, String entity,
List<String> paramNames, List<String> paramTypes, List<String> paramNames, List<String> paramTypes,
boolean belongsToDao, boolean belongsToDao,
String sessionType) { String sessionType,
List<String> fetchProfiles) {
this.annotationMetaEntity = annotationMetaEntity; this.annotationMetaEntity = annotationMetaEntity;
this.methodName = methodName; this.methodName = methodName;
this.entity = entity; this.entity = entity;
@ -37,6 +39,7 @@ public class NaturalIdFinderMethod implements MetaAttribute {
this.paramTypes = paramTypes; this.paramTypes = paramTypes;
this.belongsToDao = belongsToDao; this.belongsToDao = belongsToDao;
this.sessionType = sessionType; this.sessionType = sessionType;
this.fetchProfiles = fetchProfiles;
} }
@Override @Override
@ -113,6 +116,12 @@ public class NaturalIdFinderMethod implements MetaAttribute {
.append(paramNames.get(i)) .append(paramNames.get(i))
.append(")"); .append(")");
} }
for ( String profile : fetchProfiles ) {
declaration
.append("\n\t\t\t.enableFetchProfile(")
.append(profile)
.append(")");
}
declaration declaration
.append("\n\t\t\t.load();\n}"); .append("\n\t\t\t.load();\n}");
return declaration.toString(); return declaration.toString();

View File

@ -214,7 +214,7 @@ public final class TypeUtils {
assert parameterValue != null; assert parameterValue != null;
for ( Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry for ( Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry
: annotationMirror.getElementValues().entrySet() ) { : annotationMirror.getElementValues().entrySet() ) {
if ( parameterValue.equals( entry.getKey().getSimpleName().toString() ) ) { if ( entry.getKey().getSimpleName().contentEquals( parameterValue ) ) {
return entry.getValue().getValue(); return entry.getValue().getValue();
} }
} }

View File

@ -16,6 +16,9 @@ public interface Dao {
@Find @Find
Book getBook(String isbn); Book getBook(String isbn);
@Find(enabledFetchProfiles="Goodbye")
Book getBookFetching(String isbn);
@Find @Find
Book getBook(String title, String author); Book getBook(String title, String author);

View File

@ -16,15 +16,24 @@ public interface StatefulDao {
@Find @Find
Book getBook(String isbn); Book getBook(String isbn);
@Find(enabledFetchProfiles="Goodbye")
Book getBookFetching(String isbn);
@Find @Find
Book getBook(String title, String author); Book getBook(String title, String author);
@Find(enabledFetchProfiles="Hello")
Book getBookFetching(String title, String author);
@Find @Find
Book getBook(String title, String isbn, String author); Book getBook(String title, String isbn, String author);
@Find @Find
List<Book> getBooks(String title); List<Book> getBooks(String title);
@Find(enabledFetchProfiles="Hello")
List<Book> getBooksFetching(String title);
@Find @Find
SelectionQuery<Book> createBooksSelectionQuery(String title); SelectionQuery<Book> createBooksSelectionQuery(String title);

View File

@ -16,15 +16,24 @@ public interface StatelessDao {
@Find @Find
Book getBook(String isbn); Book getBook(String isbn);
@Find(enabledFetchProfiles="Goodbye")
Book getBookFetching(String isbn);
@Find @Find
Book getBook(String title, String author); Book getBook(String title, String author);
@Find(enabledFetchProfiles="Hello")
Book getBookFetching(String title, String author);
@Find @Find
Book getBook(String title, String isbn, String author); Book getBook(String title, String isbn, String author);
@Find @Find
List<Book> getBooks(String title); List<Book> getBooks(String title);
@Find(enabledFetchProfiles="Hello")
List<Book> getBooksFetching(String title);
@Find @Find
SelectionQuery<Book> createBooksSelectionQuery(String title); SelectionQuery<Book> createBooksSelectionQuery(String title);