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)
@Retention(CLASS)
@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) {
final HashSet<String> oldFetchProfiles =
hasEnabledFetchProfiles() ? new HashSet<>( enabledFetchProfileNames ) : null;
if ( disabledFetchProfiles != null ) {
if ( disabledFetchProfiles != null && enabledFetchProfileNames != null ) {
enabledFetchProfileNames.removeAll( disabledFetchProfiles );
}
if ( enabledFetchProfiles != null ) {
if ( enabledFetchProfileNames == null ) {
enabledFetchProfileNames = new HashSet<>();
}
enabledFetchProfileNames.addAll( enabledFetchProfiles );
}
return oldFetchProfiles;

View File

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

View File

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

View File

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

View File

@ -12,6 +12,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
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.Validation;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import static java.util.stream.Collectors.toList;
import static javax.lang.model.util.ElementFilter.fieldsIn;
@ -468,11 +470,26 @@ public class AnnotationMetaEntity extends AnnotationMeta {
paramNames,
paramTypes,
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) {
final String methodName = method.getSimpleName().toString();
final List<String> paramNames = parameterNames(method);
@ -487,7 +504,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
paramNames,
paramTypes,
dao,
sessionType
sessionType,
enabledFetchProfiles( method )
)
);
}
@ -501,7 +519,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
paramNames,
paramTypes,
dao,
sessionType
sessionType,
enabledFetchProfiles( method )
)
);
}
@ -523,7 +542,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
List.of( parameter.getSimpleName().toString() ),
List.of( parameter.asType().toString() ),
dao,
sessionType
sessionType,
enabledFetchProfiles( method )
)
);
break;
@ -536,7 +556,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
parameter.getSimpleName().toString(),
parameter.asType().toString(),
dao,
sessionType
sessionType,
enabledFetchProfiles( method )
)
);
break;
@ -550,7 +571,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
List.of( parameter.getSimpleName().toString() ),
List.of( parameter.asType().toString() ),
dao,
sessionType
sessionType,
enabledFetchProfiles( method )
)
);
break;

View File

@ -27,6 +27,7 @@ public class CriteriaFinderMethod implements MetaAttribute {
private final List<String> paramTypes;
private final boolean belongsToDao;
private final String sessionType;
private final List<String> fetchProfiles;
public CriteriaFinderMethod(
Metamodel annotationMetaEntity,
@ -34,7 +35,8 @@ public class CriteriaFinderMethod implements MetaAttribute {
@Nullable String containerType,
List<String> paramNames, List<String> paramTypes,
boolean belongsToDao,
String sessionType) {
String sessionType,
List<String> fetchProfiles) {
this.annotationMetaEntity = annotationMetaEntity;
this.methodName = methodName;
this.entity = entity;
@ -43,6 +45,7 @@ public class CriteriaFinderMethod implements MetaAttribute {
this.paramTypes = paramTypes;
this.belongsToDao = belongsToDao;
this.sessionType = sessionType;
this.fetchProfiles = fetchProfiles;
}
@Override
@ -146,6 +149,23 @@ public class CriteriaFinderMethod implements MetaAttribute {
}
declaration
.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) {
declaration
.append(".getSingleResult()");

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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